-mm1
--- diff/Documentation/Changes	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/Changes	2004-02-18 09:03:58.000000000 +0000
@@ -216,13 +216,6 @@
 as root before you can use this.  You'll probably also want to
 get the user-space microcode_ctl utility to use with this.
 
-If you have compiled the driver as a module you may need to add
-the following line:
-
-alias char-major-10-184 microcode
-
-to your /etc/modules.conf file.
-
 Powertweak
 ----------
 
@@ -259,17 +252,6 @@
 
 as root.
 
-If you build ppp support as modules, you will need the following in
-your /etc/modules.conf file:
-
-alias char-major-108	ppp_generic
-alias /dev/ppp		ppp_generic
-alias tty-ldisc-3	ppp_async
-alias tty-ldisc-14	ppp_synctty
-alias ppp-compress-21	bsd_comp
-alias ppp-compress-24	ppp_deflate
-alias ppp-compress-26	ppp_deflate
-
 If you use devfsd and build ppp support as modules, you will need
 the following in your /etc/devfsd.conf file:
 
--- diff/Documentation/CodingStyle	2003-07-22 18:54:26.000000000 +0100
+++ source/Documentation/CodingStyle	2004-02-18 09:03:58.000000000 +0000
@@ -1,42 +1,75 @@
 
-		Linux kernel coding style 
+		Linux kernel coding style
 
 This is a short document describing the preferred coding style for the
 linux kernel.  Coding style is very personal, and I won't _force_ my
 views on anybody, but this is what goes for anything that I have to be
 able to maintain, and I'd prefer it for most other things too.  Please
-at least consider the points made here. 
+at least consider the points made here.
 
 First off, I'd suggest printing out a copy of the GNU coding standards,
-and NOT read it.  Burn them, it's a great symbolic gesture. 
+and NOT read it.  Burn them, it's a great symbolic gesture.
 
 Anyway, here goes:
 
 
 	 	Chapter 1: Indentation
 
-Tabs are 8 characters, and thus indentations are also 8 characters. 
+Tabs are 8 characters, and thus indentations are also 8 characters.
 There are heretic movements that try to make indentations 4 (or even 2!)
 characters deep, and that is akin to trying to define the value of PI to
-be 3. 
+be 3.
 
 Rationale: The whole idea behind indentation is to clearly define where
 a block of control starts and ends.  Especially when you've been looking
 at your screen for 20 straight hours, you'll find it a lot easier to see
-how the indentation works if you have large indentations. 
+how the indentation works if you have large indentations.
 
 Now, some people will claim that having 8-character indentations makes
 the code move too far to the right, and makes it hard to read on a
 80-character terminal screen.  The answer to that is that if you need
 more than 3 levels of indentation, you're screwed anyway, and should fix
-your program. 
+your program.
 
 In short, 8-char indents make things easier to read, and have the added
-benefit of warning you when you're nesting your functions too deep. 
-Heed that warning. 
+benefit of warning you when you're nesting your functions too deep.
+Heed that warning.
 
+Don't put multiple statements on a single line unless you have
+something to hide:
 
-		Chapter 2: Placing Braces
+	if (condition) do_this;
+	  do_something_everytime;
+
+Outside of comments, documentation and except in Kconfig, spaces are never
+used for indentation, and the above example is deliberately broken.
+
+Get a decent editor and don't leave whitespace at the end of lines.
+
+
+		Chapter 2: Breaking long lines and strings
+
+Coding style is all about readability and maintainability using commonly
+available tools.
+
+The limit on the length of lines is 80 columns and this is a hard limit.
+
+Statements longer than 80 columns will be broken into sensible chunks.
+Descendants are always substantially shorter than the parent and are placed
+substantially to the right. The same applies to function headers with a long
+argument list. Long strings are as well broken into shorter strings.
+
+void fun(int a, int b, int c)
+{
+	if (condition)
+		printk(KERN_WARNING "Warning this is a long printk with "
+						"3 parameters a: %u b: %u "
+						"c: %u \n", a, b, c);
+	else
+		next_statement;
+}
+
+		Chapter 3: Placing Braces
 
 The other issue that always comes up in C styling is the placement of
 braces.  Unlike the indent size, there are few technical reasons to
@@ -59,7 +92,7 @@
 Heretic people all over the world have claimed that this inconsistency
 is ...  well ...  inconsistent, but all right-thinking people know that
 (a) K&R are _right_ and (b) K&R are right.  Besides, functions are
-special anyway (you can't nest them in C). 
+special anyway (you can't nest them in C).
 
 Note that the closing brace is empty on a line of its own, _except_ in
 the cases where it is followed by a continuation of the same statement,
@@ -79,60 +112,60 @@
 	} else {
 		....
 	}
-			
-Rationale: K&R. 
+
+Rationale: K&R.
 
 Also, note that this brace-placement also minimizes the number of empty
 (or almost empty) lines, without any loss of readability.  Thus, as the
 supply of new-lines on your screen is not a renewable resource (think
 25-line terminal screens here), you have more empty lines to put
-comments on. 
+comments on.
 
 
-		Chapter 3: Naming
+		Chapter 4: Naming
 
 C is a Spartan language, and so should your naming be.  Unlike Modula-2
 and Pascal programmers, C programmers do not use cute names like
 ThisVariableIsATemporaryCounter.  A C programmer would call that
 variable "tmp", which is much easier to write, and not the least more
-difficult to understand. 
+difficult to understand.
 
 HOWEVER, while mixed-case names are frowned upon, descriptive names for
 global variables are a must.  To call a global function "foo" is a
-shooting offense. 
+shooting offense.
 
 GLOBAL variables (to be used only if you _really_ need them) need to
 have descriptive names, as do global functions.  If you have a function
 that counts the number of active users, you should call that
-"count_active_users()" or similar, you should _not_ call it "cntusr()". 
+"count_active_users()" or similar, you should _not_ call it "cntusr()".
 
 Encoding the type of a function into the name (so-called Hungarian
 notation) is brain damaged - the compiler knows the types anyway and can
 check those, and it only confuses the programmer.  No wonder MicroSoft
-makes buggy programs. 
+makes buggy programs.
 
 LOCAL variable names should be short, and to the point.  If you have
-some random integer loop counter, it should probably be called "i". 
+some random integer loop counter, it should probably be called "i".
 Calling it "loop_counter" is non-productive, if there is no chance of it
 being mis-understood.  Similarly, "tmp" can be just about any type of
-variable that is used to hold a temporary value. 
+variable that is used to hold a temporary value.
 
 If you are afraid to mix up your local variable names, you have another
-problem, which is called the function-growth-hormone-imbalance syndrome. 
-See next chapter. 
+problem, which is called the function-growth-hormone-imbalance syndrome.
+See next chapter.
 
-		
-		Chapter 4: Functions
+
+		Chapter 5: Functions
 
 Functions should be short and sweet, and do just one thing.  They should
 fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
-as we all know), and do one thing and do that well. 
+as we all know), and do one thing and do that well.
 
 The maximum length of a function is inversely proportional to the
 complexity and indentation level of that function.  So, if you have a
 conceptually simple function that is just one long (but simple)
 case-statement, where you have to do lots of small things for a lot of
-different cases, it's OK to have a longer function. 
+different cases, it's OK to have a longer function.
 
 However, if you have a complex function, and you suspect that a
 less-than-gifted first-year high-school student might not even
@@ -140,41 +173,78 @@
 maximum limits all the more closely.  Use helper functions with
 descriptive names (you can ask the compiler to in-line them if you think
 it's performance-critical, and it will probably do a better job of it
-than you would have done). 
+than you would have done).
 
 Another measure of the function is the number of local variables.  They
 shouldn't exceed 5-10, or you're doing something wrong.  Re-think the
 function, and split it into smaller pieces.  A human brain can
 generally easily keep track of about 7 different things, anything more
 and it gets confused.  You know you're brilliant, but maybe you'd like
-to understand what you did 2 weeks from now. 
+to understand what you did 2 weeks from now.
+
+
+		Chapter 6: Centralized exiting of functions
 
+Albeit deprecated by some people, the equivalent of the goto statement is
+used frequently by compilers in form of the unconditional jump instruction.
 
-		Chapter 5: Commenting
+The goto statement comes in handy when a function exits from multiple
+locations and some common work such as cleanup has to be done.
+
+The rationale is:
+
+- unconditional statements are easier to understand and follow
+- nesting is reduced
+- errors by not updating individual exit points when making
+    modifications are prevented
+- saves the compiler work to optimize redundant code away ;)
+
+int fun(int )
+{
+	int result = 0;
+	char *buffer = kmalloc(SIZE);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+
+	if (condition1) {
+		while (loop1) {
+			...
+		}
+		result = 1;
+		goto out;
+	}
+	...
+out:
+	kfree(buffer);
+	return result;
+}
+
+		Chapter 7: Commenting
 
 Comments are good, but there is also a danger of over-commenting.  NEVER
 try to explain HOW your code works in a comment: it's much better to
 write the code so that the _working_ is obvious, and it's a waste of
-time to explain badly written code. 
+time to explain badly written code.
 
-Generally, you want your comments to tell WHAT your code does, not HOW. 
+Generally, you want your comments to tell WHAT your code does, not HOW.
 Also, try to avoid putting comments inside a function body: if the
 function is so complex that you need to separately comment parts of it,
-you should probably go back to chapter 4 for a while.  You can make
+you should probably go back to chapter 5 for a while.  You can make
 small comments to note or warn about something particularly clever (or
 ugly), but try to avoid excess.  Instead, put the comments at the head
 of the function, telling people what it does, and possibly WHY it does
-it. 
+it.
 
 
-		Chapter 6: You've made a mess of it
+		Chapter 8: You've made a mess of it
 
 That's OK, we all do.  You've probably been told by your long-time Unix
 user helper that "GNU emacs" automatically formats the C sources for
 you, and you've noticed that yes, it does do that, but the defaults it
 uses are less than desirable (in fact, they are worse than random
 typing - an infinite number of monkeys typing into GNU emacs would never
-make a good program). 
+make a good program).
 
 So, you can either get rid of GNU emacs, or change it to use saner
 values.  To do the latter, you can stick the following in your .emacs file:
@@ -192,7 +262,7 @@
 to add
 
 (setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
-                       auto-mode-alist))
+			auto-mode-alist))
 
 to your .emacs file if you want to have linux-c-mode switched on
 automagically when you edit source files under /usr/src/linux.
@@ -201,33 +271,36 @@
 everything is lost: use "indent".
 
 Now, again, GNU indent has the same brain-dead settings that GNU emacs
-has, which is why you need to give it a few command line options. 
+has, which is why you need to give it a few command line options.
 However, that's not too bad, because even the makers of GNU indent
 recognize the authority of K&R (the GNU people aren't evil, they are
 just severely misguided in this matter), so you just give indent the
-options "-kr -i8" (stands for "K&R, 8 character indents"). 
+options "-kr -i8" (stands for "K&R, 8 character indents"), or use
+"scripts/Lindent", which indents in the latest style.
 
 "indent" has a lot of options, and especially when it comes to comment
-re-formatting you may want to take a look at the manual page.  But
-remember: "indent" is not a fix for bad programming. 
+re-formatting you may want to take a look at the man page.  But
+remember: "indent" is not a fix for bad programming.
 
 
-		Chapter 7: Configuration-files
+		Chapter 9: Configuration-files
 
-For configuration options (arch/xxx/config.in, and all the Config.in files),
+For configuration options (arch/xxx/Kconfig, and all the Kconfig files),
 somewhat different indentation is used.
 
-An indention level of 3 is used in the code, while the text in the config-
-options should have an indention-level of 2 to indicate dependencies. The
-latter only applies to bool/tristate options. For other options, just use
-common sense. An example:
-
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   tristate 'Apply nitroglycerine inside the keyboard (DANGEROUS)' CONFIG_BOOM
-   if [ "$CONFIG_BOOM" != "n" ]; then
-      bool '  Output nice messages when you explode' CONFIG_CHEER
-   fi
-fi
+Help text is indented with 2 spaces.
+
+if CONFIG_EXPERIMENTAL
+	tristate CONFIG_BOOM
+	default n
+	help
+	  Apply nitroglycerine inside the keyboard (DANGEROUS)
+	bool CONFIG_CHEER
+	depends on CONFIG_BOOM
+	default y
+	help
+	  Output nice messages when you explode
+endif
 
 Generally, CONFIG_EXPERIMENTAL should surround all options not considered
 stable. All options that are known to trash data (experimental write-
@@ -235,20 +308,20 @@
 experimental options should be denoted (EXPERIMENTAL).
 
 
-		Chapter 8: Data structures
+		Chapter 10: Data structures
 
 Data structures that have visibility outside the single-threaded
 environment they are created and destroyed in should always have
 reference counts.  In the kernel, garbage collection doesn't exist (and
 outside the kernel garbage collection is slow and inefficient), which
-means that you absolutely _have_ to reference count all your uses. 
+means that you absolutely _have_ to reference count all your uses.
 
 Reference counting means that you can avoid locking, and allows multiple
 users to have access to the data structure in parallel - and not having
 to worry about the structure suddenly going away from under them just
-because they slept or did something else for a while. 
+because they slept or did something else for a while.
 
-Note that locking is _not_ a replacement for reference counting. 
+Note that locking is _not_ a replacement for reference counting.
 Locking is used to keep data structures coherent, while reference
 counting is a memory management technique.  Usually both are needed, and
 they are not to be confused with each other.
@@ -264,3 +337,87 @@
 
 Remember: if another thread can find your data structure, and you don't
 have a reference count on it, you almost certainly have a bug.
+
+
+		Chapter 11: Macros, Enums, Inline functions and RTL
+
+Names of macros defining constants and labels in enums are capitalized.
+
+#define CONSTANT 0x12345
+
+Enums are preferred when defining several related constants.
+
+CAPITALIZED macro names are appreciated but macros resembling functions
+may be named in lower case.
+
+Generally, inline functions are preferable to macros resembling functions.
+
+Macros with multiple statements should be enclosed in a do - while block:
+
+#define macrofun(a,b,c) 			\
+	do {					\
+		if (a == 5)			\
+			do_this(b,c);		\
+	} while (0)
+
+Things to avoid when using macros:
+
+1) macros that affect control flow:
+
+#define FOO(x)					\
+	do {					\
+		if (blah(x) < 0)		\
+			return -EBUGGERED;	\
+	} while(0)
+
+is a _very_ bad idea.  It looks like a function call but exits the "calling"
+function; don't break the internal parsers of those who will read the code.
+
+2) macros that depend on having a local variable with a magic name:
+
+#define FOO(val) bar(index, val)
+
+might look like a good thing, but it's confusing as hell when one reads the
+code and it's prone to breakage from seemingly innocent changes.
+
+3) macros with arguments that are used as l-values: FOO(x) = y; will
+bite you if somebody e.g. turns FOO into an inline function.
+
+4) forgetting about precedence: macros defining constants using expressions
+must enclose the expression in parentheses. Beware of similar issues with
+macros using parameters.
+
+#define CONSTANT 0x4000
+#define CONSTEXP (CONSTANT | 3)
+
+The cpp manual deals with macros exhaustively. The gcc internals manual also
+covers RTL which is used frequently with assembly language in the kernel.
+
+
+		Chapter 12: Printing kernel messages
+
+Kernel developers like to be seen as literate. Do mind the spelling
+of kernel messages to make a good impression. Do not use crippled
+words like "dont" and use "do not" or "don't" instead.
+
+Kernel messages do not have to be terminated with a period.
+
+Printing numbers in parentheses (%d) adds no value and should be avoided.
+
+
+		Chapter 13: References
+
+The C Programming Language, Second Edition
+by Brian W. Kernighan and Dennis M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback).
+
+The Practice of Programming
+Brian W. Kernighan, Rob Pike
+Addison-Wesley, 1999, ISBN 0-201-61586-X
+
+GNU manuals - where in compliance with K&R and this text - for cpp, gcc,
+gcc internals and indent, all available from www.gnu.org.
+
+--
+Last updated on 16 February 2004 by a community effort on LKML.
--- diff/Documentation/binfmt_misc.txt	2003-10-09 09:47:33.000000000 +0100
+++ source/Documentation/binfmt_misc.txt	2004-02-18 09:03:58.000000000 +0000
@@ -15,7 +15,7 @@
 	mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
 your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
@@ -34,6 +34,28 @@
    The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
+ - 'flags' is an optional field that controls several aspects of the invocation
+   of the interpreter. It is a string of capital letters, each controls a certain
+   aspect. The following flags are supported -
+      'P' - preserve-argv[0].  Legacy behavior of binfmt_misc is to overwrite the
+            original argv[0] with the full path to the binary.  When this flag is
+            included, binfmt_misc will add an argument to the argument vector for
+            this purpose, thus preserving the original argv[0].
+      'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
+            of the binary to the interpreter as an argument. When this flag is
+            included, binfmt_misc will open the file for reading and pass its
+            descriptor as an argument, instead of the full path, thus allowing
+            the interpreter to execute non-readable binaries. This feature should
+            be used with care - the interpreter has to be trusted not to emit
+            the contents of the non-readable binary.
+      'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
+            the credentials and security token of the new process according to
+            the interpreter. When this flag is included, these attributes are
+            calculated according to the binary. It also implies the 'O' flag.
+            This feature should be used with care as the interpreter
+            will run with root permissions when a setuid binary owned by root
+            is run with binfmt_misc.
+
 
 There are some restrictions:
  - the whole register string may not exceed 255 characters
@@ -83,9 +105,9 @@
 write a wrapper script for it. See Documentation/java.txt for an
 example.
 
-Your interpreter should NOT look in the PATH for the filename; the
-kernel passes it the full filename to use.  Using the PATH can cause
-unexpected behaviour and be a security hazard.
+Your interpreter should NOT look in the PATH for the filename; the kernel
+passes it the full filename (or the file descriptor) to use.  Using $PATH can
+cause unexpected behaviour and can be a security hazard.
 
 
 There is a web page about binfmt_misc at
--- diff/Documentation/computone.txt	2003-08-20 14:16:23.000000000 +0100
+++ source/Documentation/computone.txt	2004-02-18 09:03:58.000000000 +0000
@@ -41,11 +41,11 @@
 
 	Note the hardware address from the Computone ISA cards installed into
 		the system.  These are required for editing ip2.c or editing
-		/etc/modules.conf, or for specification on the modprobe
+		/etc/modprobe.conf, or for specification on the modprobe
 		command line.
 
-	Note that the /etc/modules.conf file is named /etc/conf.modules
-		with older versions of the module utilities.
+	Note that the /etc/modules.conf should be used for older (pre-2.6)
+		kernels.
 
 Software -
 
@@ -58,7 +58,7 @@
 c) Set address on ISA cards then:
    edit /usr/src/linux/drivers/char/ip2.c if needed 
 	or
-   edit /etc/modules.conf if needed (module).
+   edit /etc/modprobe.conf if needed (module).
 	or both to match this setting.
 d) Run "make modules"
 e) Run "make modules_install"
@@ -145,11 +145,11 @@
 selects polled mode). If no base addresses are specified the defaults in 
 ip2.c are used. If you are autoloading the driver module with kerneld or
 kmod the base addresses and interrupt number must also be set in ip2.c
-and recompile or just insert and options line in /etc/modules.conf or both. 
+and recompile or just insert and options line in /etc/modprobe.conf or both.
 The options line is equivalent to the command line and takes precidence over 
 what is in ip2.c. 
 
-/etc/modules.conf sample:
+/etc/modprobe.conf sample:
 	options ip2 io=1,0x328 irq=1,10
 	alias char-major-71 ip2
 	alias char-major-72 ip2
--- diff/Documentation/crypto/api-intro.txt	2003-10-09 09:47:33.000000000 +0100
+++ source/Documentation/crypto/api-intro.txt	2004-02-18 09:03:58.000000000 +0000
@@ -68,7 +68,7 @@
 CONFIGURATION NOTES
 
 As Triple DES is part of the DES module, for those using modular builds,
-add the following line to /etc/modules.conf:
+add the following line to /etc/modprobe.conf:
 
   alias des3_ede des
 
--- diff/Documentation/digiboard.txt	2003-10-09 09:47:16.000000000 +0100
+++ source/Documentation/digiboard.txt	2004-02-18 09:03:58.000000000 +0000
@@ -24,7 +24,7 @@
 The pcxx driver can be configured using the command line feature while
 loading the kernel with LILO or LOADLIN or, if built as a module,
 with arguments to insmod and modprobe or with parameters in
-/etc/modules.conf for modprobe and kerneld.
+/etc/modprobe.conf for modprobe and kerneld.
 
 After configuring the driver you need to create the device special files
 as described in "Device file creation:" below and set the appropriate
@@ -91,13 +91,13 @@
 
 The remaining board still uses ttyD8-ttyD15 and cud8-cud15.
 
-Example line for /etc/modules.conf for use with kerneld and as default
+Example line for /etc/modprobe.conf for use with kerneld and as default
 parameters for modprobe:
 
 options pcxx           io=0x200 numports=8
 
-For kerneld to work you will likely need to add these two lines to your
-/etc/modules.conf:
+For kmod to work you will likely need to add these two lines to your
+/etc/modprobe.conf:
 
 alias char-major-22    pcxx
 alias char-major-23    pcxx
--- diff/Documentation/fb/intel810.txt	2003-01-02 10:43:02.000000000 +0000
+++ source/Documentation/fb/intel810.txt	2004-02-18 09:03:58.000000000 +0000
@@ -194,7 +194,7 @@
 	modprobe i810fb vram=2 xres=1024 bpp=8 hsync1=30 hsync2=55 vsync1=50 \
 	         vsync2=85 accel=1 mtrr=1
 
-Or just add the following to /etc/modules.conf
+Or just add the following to /etc/modprobe.conf
 
 	options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \
 	vsync2=85 accel=1 mtrr=1
--- diff/Documentation/filesystems/jfs.txt	2003-10-27 09:20:36.000000000 +0000
+++ source/Documentation/filesystems/jfs.txt	2004-02-18 09:03:58.000000000 +0000
@@ -12,10 +12,9 @@
 The following mount options are supported:
 
 iocharset=name	Character set to use for converting from Unicode to
-		ASCII.  The default is compiled into the kernel as
-		CONFIG_NLS_DEFAULT.  Use iocharset=utf8 for UTF8
-		translations.  This requires CONFIG_NLS_UTF8 to be set
-		in the kernel .config file.
+		ASCII.  The default is to do no conversion.  Use
+		iocharset=utf8 for UTF8 translations.  This requires
+		CONFIG_NLS_UTF8 to be set in the kernel .config file.
 
 resize=value	Resize the volume to <value> blocks.  JFS only supports
 		growing a volume, not shrinking it.  This option is only
@@ -36,18 +35,6 @@
 errors=remount-ro	Default. Remount the filesystem read-only on an error.
 errors=panic		Panic and halt the machine if an error occurs.
 
-JFS TODO list:
-
-Plans for our near term development items
-
-   - enhance support for logfile on dedicated partition
-
-Longer term work items
-
-   - implement defrag utility, for online defragmenting
-   - add quota support
-   - add support for block sizes (512,1024,2048)
-
 Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
 
 The JFS mailing list can be subscribed to by using the link labeled
--- diff/Documentation/filesystems/proc.txt	2003-09-17 12:28:01.000000000 +0100
+++ source/Documentation/filesystems/proc.txt	2004-02-18 09:03:58.000000000 +0000
@@ -900,6 +900,15 @@
 Every mounted file system needs a super block, so if you plan to mount lots of
 file systems, you may want to increase these numbers.
 
+aio-nr and aio-max-nr
+---------------------
+
+aio-nr is the running total of the number of events specified on the
+io_setup system call for all currently active aio contexts.  If aio-nr
+reaches aio-max-nr then io_setup will fail with EAGAIN.  Note that
+raising aio-max-nr does not result in the pre-allocation or re-sizing
+of any kernel data structures.
+
 2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats
 -----------------------------------------------------------
 
--- diff/Documentation/ftape.txt	2003-10-09 09:47:33.000000000 +0100
+++ source/Documentation/ftape.txt	2004-02-18 09:03:58.000000000 +0000
@@ -242,15 +242,15 @@
    Module parameters can be specified either directly when invoking
    the program 'insmod' at the shell prompt:
 
-   insmod ftape.o ft_tracing=4
+   modprobe ftape ft_tracing=4
 
-   or by editing the file `/etc/modules.conf' in which case they take
+   or by editing the file `/etc/modprobe.conf' in which case they take
    effect each time when the module is loaded with `modprobe' (please
    refer to the respective manual pages). Thus, you should add a line
 
    options ftape ft_tracing=4
 
-   to `/etc/modules.conf` if you intend to increase the debugging
+   to `/etc/modprobe.conf` if you intend to increase the debugging
    output of the driver.
 
 
@@ -298,7 +298,7 @@
 5. Example module parameter setting
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    To do the same, but with ftape compiled as a loadable kernel
-   module, add the following line to `/etc/modules.conf':
+   module, add the following line to `/etc/modprobe.conf':
 
    options ftape ft_probe_fc10=1 ft_tracing=4
 
--- diff/Documentation/hayes-esp.txt	2002-10-16 04:27:12.000000000 +0100
+++ source/Documentation/hayes-esp.txt	2004-02-18 09:03:58.000000000 +0000
@@ -109,7 +109,7 @@
 insmod esp dma=3 trigger=512
 
 The esp module can be automatically loaded when needed.  To cause this to
-happen, add the following lines to /etc/modules.conf (replacing the last line
+happen, add the following lines to /etc/modprobe.conf (replacing the last line
 with options for your configuration):
 
 alias char-major-57 esp
--- diff/Documentation/ide.txt	2003-10-27 09:20:36.000000000 +0000
+++ source/Documentation/ide.txt	2004-02-18 09:03:58.000000000 +0000
@@ -198,12 +198,11 @@
 can only be compiled into the kernel, and the core code (ide.c) can be
 compiled as a loadable module provided no chipset support is needed.
 
-When using ide.c/ide-tape.c as modules in combination with kerneld, add:
+When using ide.c as a module in combination with kmod, add:
 
 	alias block-major-3 ide-probe
-	alias char-major-37 ide-tape
 
-respectively to /etc/modules.conf.
+to /etc/modprobe.conf.
 
 When ide.c is used as a module, you can pass command line parameters to the
 driver using the "options=" keyword to insmod, while replacing any ',' with
--- diff/Documentation/kbuild/modules.txt	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/kbuild/modules.txt	2004-02-18 09:03:58.000000000 +0000
@@ -17,12 +17,52 @@
 
 Compiling modules outside the official kernel
 ---------------------------------------------
-Often modules are developed outside the official kernel.
-To keep up with changes in the build system the most portable way
-to compile a module outside the kernel is to use the following command-line:
+
+Often modules are developed outside the official kernel.  To keep up
+with changes in the build system the most portable way to compile a
+module outside the kernel is to use the kernel build system,
+kbuild. Use the following command-line:
 
 make -C path/to/kernel/src SUBDIRS=$PWD modules
 
 This requires that a makefile exits made in accordance to
-Documentation/kbuild/makefiles.txt.
+Documentation/kbuild/makefiles.txt. Read that file for more details on
+the build system.
+
+The following is a short summary of how to write your Makefile to get
+you up and running fast. Assuming your module will be called
+yourmodule.ko, your code should be in yourmodule.c and your Makefile
+should include
+
+obj-m := yourmodule.o
+
+If the code for your module is in multiple files that need to be
+linked, you need to tell the build system which files to compile. In
+the case of multiple files, none of these files can be named
+yourmodule.c because doing so would cause a problem with the linking
+step. Assuming your code exists in file1.c, file2.c, and file3.c and
+you want to build yourmodule.ko from them, your Makefile should
+include
+
+obj-m := yourmodule.o
+yourmodule-objs := file1.o file2.o file3.o
+
+Now for a final example to put it all together. Assuming the
+KERNEL_SOURCE environment variable is set to the directory where you
+compiled the kernel, a simple Makefile that builds yourmodule.ko as
+described above would look like
+
+# Tells the build system to build yourmodule.ko.
+obj-m := yourmodule.o
+
+# Tells the build system to build these object files and link them as
+# yourmodule.o, before building yourmodule.ko. This line can be left
+# out if all the code for your module is in one file, yourmodule.c. If
+# you are using multiple files, none of these files can be named
+# yourmodule.c.
+yourmodule-objs := file1.o file2.o file3.o
 
+# Invokes the kernel build system to come back to the current
+# directory and build yourmodule.ko.
+default:
+	make -C ${KERNEL_SOURCE} SUBDIRS=`pwd` modules
--- diff/Documentation/kernel-parameters.txt	2004-02-09 10:36:07.000000000 +0000
+++ source/Documentation/kernel-parameters.txt	2004-02-18 09:03:58.000000000 +0000
@@ -174,11 +174,18 @@
 
 	atascsi=	[HW,SCSI] Atari SCSI
 
-	atkbd.set=	[HW] Select keyboard code set
-			Format: <int>
+	atkbd.extra=	[HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey
+			and similar keyboards
+
+	atkbd.reset=	[HW] Reset keyboard during initialization
+
+	atkbd.set=	[HW] Select keyboard code set 
+			Format: <int> (2 = AT (default) 3 = PS/2)
+
+	atkbd.scroll=	[HW] Enable scroll wheel on MS Office and similar keyboards
+	
 	atkbd.softrepeat=
 			[HW] Use software keyboard repeat
-	atkbd.reset=	[HW] Reset keyboard during initialization
 
 	autotest	[IA64]
 
@@ -237,7 +244,7 @@
 			Forces specified timesource (if avaliable) to be used
 			when calculating gettimeofday(). If specicified timesource
 			is not avalible, it defaults to PIT. 
-			Format: { pit | tsc | cyclone | ... }
+			Format: { pit | tsc | cyclone | pmtmr }
 
 	hpet=		[IA-32,HPET] option to disable HPET and use PIT.
 			Format: disable
@@ -292,6 +299,9 @@
 
 	devfs=		[DEVFS]
 			See Documentation/filesystems/devfs/boot-options.
+
+	dhash_entries=	[KNL]
+			Set number of hash buckets for dentry cache.
  
 	digi=		[HW,SERIAL]
 			IO parameters + enable/disable command.
@@ -310,6 +320,23 @@
 
 	dtc3181e=	[HW,SCSI]
 
+	earlyprintk=	[x86, x86_64]
+			early_printk=vga
+			early_printk=serial[,ttySn[,baudrate]]
+
+			Append ,keep to not disable it when the real console
+			takes over.
+
+			Only vga or serial at a time, not both.
+
+			Currently only ttyS0 and ttyS1 are supported.
+
+			Interaction with the standard serial driver is not
+			very good.
+
+			The VGA output is eventually overwritten by the real
+			console.
+
 	eata=		[HW,SCSI]
 
 	eda=		[HW,PS2]
@@ -424,6 +451,9 @@
 	idle=		[HW]
 			Format: idle=poll or idle=halt
  
+	ihash_entries=	[KNL]
+			Set number of hash buckets for inode cache.
+
 	in2000=		[HW,SCSI]
 			See header of drivers/scsi/in2000.c.
 
@@ -873,6 +903,9 @@
 
 	resume=		[SWSUSP] Specify the partition device for software suspension
 
+	rhash_entries=	[KNL,NET]
+			Set number of hash buckets for route cache
+
 	riscom8=	[HW,SERIAL]
 			Format: <io_board1>[,<io_board2>[,...<io_boardN>]]
 
@@ -1135,6 +1168,9 @@
 	tgfx_2=		See Documentation/input/joystick-parport.txt.
 	tgfx_3=
 
+	thash_entries=	[KNL,NET]
+			Set number of hash buckets for TCP connection
+
 	tipar=		[HW]
 			See header of drivers/char/tipar.c.
 
--- diff/Documentation/networking/baycom.txt	2002-10-16 04:28:34.000000000 +0100
+++ source/Documentation/networking/baycom.txt	2004-02-18 09:03:58.000000000 +0000
@@ -93,10 +93,10 @@
 modems it should access at which ports. This can be done with the setbaycom
 utility. If you are only using one modem, you can also configure the
 driver from the insmod command line (or by means of an option line in
-/etc/modules.conf).
+/etc/modprobe.conf).
 
 Examples:
-  insmod baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4
+  modprobe baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4
   sethdlc -i bcsf0 -p mode "ser12*" io 0x3f8 irq 4
 
 Both lines configure the first port to drive a ser12 modem at the first
--- diff/Documentation/networking/bonding.txt	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/networking/bonding.txt	2004-02-18 09:03:58.000000000 +0000
@@ -73,9 +73,9 @@
 Bond Configuration
 ==================
 
-You will need to add at least the following line to /etc/modules.conf
+You will need to add at least the following line to /etc/modprobe.conf
 so the bonding driver will automatically load when the bond0 interface is
-configured. Refer to the modules.conf manual page for specific modules.conf
+configured. Refer to the modprobe.conf manual page for specific modprobe.conf
 syntax details. The Module Parameters section of this document describes each
 bonding driver parameter.
 
@@ -132,10 +132,10 @@
 appropriate rc directory.
 
 If you specifically need all network drivers loaded before the bonding driver,
-adding the following line to modules.conf will cause the network driver for
+adding the following line to modprobe.conf will cause the network driver for
 eth0 and eth1 to be loaded before the bonding driver.
 
-probeall bond0 eth0 eth1 bonding
+install bond0 /sbin/modprobe -a eth0 eth1 && /sbin/modprobe bonding
 
 Be careful not to reference bond0 itself at the end of the line, or modprobe
 will die in an endless recursive loop.
@@ -191,7 +191,7 @@
 
 Optional parameters for the bonding driver can be supplied as command line
 arguments to the insmod command. Typically, these parameters are specified in
-the file /etc/modules.conf (see the manual page for modules.conf). The
+the file /etc/modprobe.conf (see the manual page for modprobe.conf). The
 available bonding driver parameters are listed below. If a parameter is not
 specified the default value is used. When initially configuring a bond, it
 is recommended "tail -f /var/log/messages" be run in a separate window to
@@ -742,9 +742,8 @@
 
    # modprobe bonding miimon=100
 
-Or, put the following lines in /etc/modules.conf:
+Or, put the following line in /etc/modprobe.conf:
 
-   alias bond0 bonding
    options bond0 miimon=100
 
 There are currently two policies for high availability. They are dependent on
@@ -815,9 +814,8 @@
 
     # modprobe bonding miimon=100 mode=1
 
-Or, put in your /etc/modules.conf :
+Or, put in your /etc/modprobe.conf :
 
-    alias bond0 bonding
     options bond0 miimon=100 mode=active-backup
 
 Example 1: Using multiple host and multiple switches to build a "no single
@@ -919,7 +917,6 @@
 must add the promisc flag there; it will be propagated down to the
 slave interfaces at ifenslave time; a full example might look like:
 
-   grep bond0 /etc/modules.conf || echo alias bond0 bonding >/etc/modules.conf
    ifconfig bond0 promisc up
    for if in eth1 eth2 ...;do
        ifconfig $if up
--- diff/Documentation/networking/dl2k.txt	2002-10-16 04:28:29.000000000 +0100
+++ source/Documentation/networking/dl2k.txt	2004-02-18 09:03:58.000000000 +0000
@@ -37,15 +37,15 @@
 Install linux driver as following command:
 
 1. make all
-2. insmod dl2k.o
+2. insmod dl2k.ko
 3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0
 		    ^^^^^^^^^^^^^^^\	    ^^^^^^^^\
 				    IP		     NETMASK
 Now eth0 should active, you can test it by "ping" or get more information by
 "ifconfig". If tested ok, continue the next step.
 
-4. cp dl2k.o /lib/modules/`uname -r`/kernel/drivers/net
-5. Add the following lines to /etc/modules.conf:
+4. cp dl2k.ko /lib/modules/`uname -r`/kernel/drivers/net
+5. Add the following line to /etc/modprobe.conf:
 	alias eth0 dl2k
 6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0
    located at /etc/sysconfig/network-scripts or create it manually.
@@ -154,8 +154,8 @@
   -----------------
   1. Copy dl2k.o to the network modules directory, typically
      /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net.
-  2. Locate the boot module configuration file, most commonly modules.conf
-     or conf.modules in the /etc directory. Add the following lines:
+  2. Locate the boot module configuration file, most commonly modprobe.conf
+     or modules.conf (for 2.4) in the /etc directory. Add the following lines:
 
      alias ethx dl2k
      options dl2k <optional parameters>
--- diff/Documentation/networking/ifenslave.c	2004-02-18 08:54:06.000000000 +0000
+++ source/Documentation/networking/ifenslave.c	2004-02-18 09:03:58.000000000 +0000
@@ -89,13 +89,13 @@
  *	   while it is running. It was already set during enslave. To
  *	   simplify things, it is now handeled separately.
  *
- *    - 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ *    - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	 - Code cleanup and style changes
  *	   set version to 1.1.0
  */
 
 #define APP_VERSION	"1.1.0"
-#define APP_RELDATE	"Septemer 24, 2003"
+#define APP_RELDATE	"December 1, 2003"
 #define APP_NAME	"ifenslave"
 
 static char *version =
--- diff/Documentation/networking/ltpc.txt	2002-10-16 04:27:48.000000000 +0100
+++ source/Documentation/networking/ltpc.txt	2004-02-18 09:03:58.000000000 +0000
@@ -25,7 +25,7 @@
 
 If you load the driver as a module, you can pass the parameters "io=",
 "irq=", and "dma=" on the command line with insmod or modprobe, or add
-them as options in /etc/modules.conf:
+them as options in /etc/modprobe.conf:
 
  alias lt0 ltpc # autoload the module when the interface is configured
  options ltpc io=0x240 irq=9 dma=1
--- diff/Documentation/networking/sk98lin.txt	2004-02-09 10:36:07.000000000 +0000
+++ source/Documentation/networking/sk98lin.txt	2004-02-18 09:03:58.000000000 +0000
@@ -174,7 +174,7 @@
 to the driver module.
 
 If you use the kernel module loader, you can set driver parameters
-in the file /etc/modules.conf (or old name: /etc/conf.modules).
+in the file /etc/modprobe.conf (or /etc/modules.conf in 2.4 or earlier).
 To set the driver parameters in this file, proceed as follows:
 
 1. Insert a line of the form :
--- diff/Documentation/networking/tuntap.txt	2003-05-21 11:49:49.000000000 +0100
+++ source/Documentation/networking/tuntap.txt	2004-02-18 09:03:58.000000000 +0000
@@ -45,13 +45,10 @@
      bogus network interfaces to trick firewalls or administrators.
 
   Driver module autoloading
-     Make sure that "Kernel module loader" - module auto-loading support is enabled 
-     in your kernel. 
 
-     Add the following line to the /etc/modules.conf:
-	alias char-major-10-200 tun
-     and run
-        depmod -a 
+     Make sure that "Kernel module loader" - module auto-loading
+     support is enabled in your kernel.  The kernel should load it on
+     first access.
   
   Manual loading 
      insert the module by hand:
--- diff/Documentation/networking/vortex.txt	2003-08-20 14:16:23.000000000 +0100
+++ source/Documentation/networking/vortex.txt	2004-02-18 09:03:58.000000000 +0000
@@ -59,8 +59,8 @@
 =================
 
 There are several parameters which may be provided to the driver when
-its module is loaded.  These are usually placed in /etc/modules.conf
-(used to be conf.modules).  Example:
+its module is loaded.  These are usually placed in /etc/modprobe.conf
+(/etc/modules.conf in 2.4).  Example:
 
 options 3c59x debug=3 rx_copybreak=300
 
@@ -216,6 +216,19 @@
   to increase this value on LANs which have very high collision rates.
   The default value is 5000 (5.0 seconds).
 
+enable_wol=N1,N2,N3,...
+
+  Enable Wake-on-LAN support for the relevant interface.  Donald
+  Becker's `ether-wake' application may be used to wake suspended
+  machines.
+
+  Also enables the NIC's power management support.
+
+global_enable_wol=N
+
+  Sets enable_wol mode for all 3c59x NICs in the machine.  Entries in
+  the `enable_wol' array above will override any setting of this.
+
 Media selection
 ---------------
 
@@ -413,9 +426,9 @@
 
       1) Increase the debug level.  Usually this is done via:
 
-         a) modprobe driver.o debug=7
-         b) In /etc/conf.modules (or modules.conf):
-            options driver_name debug=7
+         a) modprobe driver debug=7
+         b) In /etc/modprobe.conf (or /etc/modules.conf for 2.4):
+            options driver debug=7
 
       2) Recreate the problem with the higher debug level,
          send all logs to the maintainer.
--- diff/Documentation/parport.txt	2002-10-16 04:28:25.000000000 +0100
+++ source/Documentation/parport.txt	2004-02-18 09:03:58.000000000 +0000
@@ -39,7 +39,7 @@
 KMod
 ----
 
-If you use kmod, you will find it useful to edit /etc/modules.conf.
+If you use kmod, you will find it useful to edit /etc/modprobe.conf.
 Here is an example of the lines that need to be added:
 
 	alias parport_lowlevel parport_pc
--- diff/Documentation/rocket.txt	2003-06-30 10:07:18.000000000 +0100
+++ source/Documentation/rocket.txt	2004-02-18 09:03:58.000000000 +0000
@@ -43,7 +43,7 @@
 
 If installed as a module, the module must be loaded.  This can be done
 manually by entering "modprobe rocket".  To have the module loaded automatically
-upon system boot, edit the /etc/modules.conf file and add the line
+upon system boot, edit the /etc/modprobe.conf file and add the line
 "alias char-major-46 rocket".
 
 In order to use the ports, their device names (nodes) must be created with mknod.
--- diff/Documentation/s390/3270.txt	2003-08-20 14:16:23.000000000 +0100
+++ source/Documentation/s390/3270.txt	2004-02-18 09:03:58.000000000 +0000
@@ -48,7 +48,7 @@
 script and the resulting /tmp/mkdev3270.
 
 If you have chosen to make tub3270 a module, you add a line to
-/etc/modules.conf.  If you are working on a VM virtual machine, you
+/etc/modprobe.conf.  If you are working on a VM virtual machine, you
 can use DEF GRAF to define virtual 3270 devices.
 
 You may generate both 3270 and 3215 console support, or one or the
@@ -60,7 +60,7 @@
 
 In brief, these are the steps:
 	1. Install the tub3270 patch
-	2. (If a module) add a line to /etc/modules.conf
+	2. (If a module) add a line to /etc/modprobe.conf
 	3. (If VM) define devices with DEF GRAF
 	4. Reboot
 	5. Configure
@@ -84,13 +84,13 @@
 		make modules_install
 
 	2. (Perform this step only if you have configured tub3270 as a
-	module.)  Add a line to /etc/modules.conf to automatically
+	module.)  Add a line to /etc/modprobe.conf to automatically
 	load the driver when it's needed.  With this line added,
 	you will see login prompts appear on your 3270s as soon as
 	boot is complete (or with emulated 3270s, as soon as you dial
 	into your vm guest using the command "DIAL <vmguestname>").
 	Since the line-mode major number is 227, the line to add to
-	/etc/modules.conf should be:
+	/etc/modprobe.conf should be:
 		alias char-major-227 tub3270
 
 	3. Define graphic devices to your vm guest machine, if you
--- diff/Documentation/scsi/aic79xx.txt	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/scsi/aic79xx.txt	2004-02-18 09:03:58.000000000 +0000
@@ -210,7 +210,7 @@
                  INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
                  USE THEM WITH CAUTION. 
 
-   Edit the file "modules.conf" in the directory /etc and add/edit a
+   Edit the file "modprobe.conf" in the directory /etc and add/edit a
    line containing 'options aic79xx aic79xx=[command[,command...]]' where
    'command' is one or more of the following:
    -----------------------------------------------------------------
--- diff/Documentation/scsi/aic7xxx.txt	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/scsi/aic7xxx.txt	2004-02-18 09:03:58.000000000 +0000
@@ -186,7 +186,7 @@
                  INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
                  USE THEM WITH CAUTION. 
 
-   Edit the file "modules.conf" in the directory /etc and add/edit a
+   Edit the file "modprobe.conf" in the directory /etc and add/edit a
    line containing 'options aic7xxx aic7xxx=[command[,command...]]' where
    'command' is one or more of the following:
    -----------------------------------------------------------------
--- diff/Documentation/scsi/osst.txt	2002-11-18 10:11:54.000000000 +0000
+++ source/Documentation/scsi/osst.txt	2004-02-18 09:03:58.000000000 +0000
@@ -67,7 +67,7 @@
 If you want to have the module autoloaded on access to /dev/osst, you may
 add something like
 alias char-major-206 osst
-to your /etc/modules.conf (old name: conf.modules).
+to your /etc/modprobe.conf (before 2.6: modules.conf).
 
 You may find it convenient to create a symbolic link 
 ln -s nosst0 /dev/tape
--- diff/Documentation/sonypi.txt	2003-09-17 12:28:01.000000000 +0100
+++ source/Documentation/sonypi.txt	2004-02-18 09:03:58.000000000 +0000
@@ -43,7 +43,7 @@
 ---------------
 
 Several options can be passed to the sonypi driver, either by adding them
-to /etc/modules.conf file, when the driver is compiled as a module or by
+to /etc/modprobe.conf file, when the driver is compiled as a module or by
 adding the following to the kernel command line (in your bootloader):
 
 	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask[,useinput]]]]]]
@@ -109,7 +109,7 @@
 -----------
 
 In order to automatically load the sonypi module on use, you can put those
-lines in your /etc/modules.conf file:
+lines in your /etc/modprobe.conf file:
 
 	alias char-major-10-250 sonypi
 	options sonypi minor=250
--- diff/Documentation/sound/oss/AWE32	2002-10-16 04:28:25.000000000 +0100
+++ source/Documentation/sound/oss/AWE32	2004-02-18 09:03:58.000000000 +0000
@@ -47,12 +47,12 @@
 
    Copy it to a directory of your choice, and unpack it there.
 
-4) Edit /etc/modules.conf, and insert the following lines at the end of the
+4) Edit /etc/modprobe.conf, and insert the following lines at the end of the
    file:
 
   alias sound-slot-0 sb
   alias sound-service-0-1 awe_wave
-  post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
+  install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
 
   You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
   path of of the sound bank file. That will enable the Sound Blaster and AWE
--- diff/Documentation/sound/oss/AudioExcelDSP16	2002-10-16 04:27:08.000000000 +0100
+++ source/Documentation/sound/oss/AudioExcelDSP16	2004-02-18 09:03:58.000000000 +0000
@@ -41,7 +41,7 @@
 		(0x300, 0x310, 0x320 or 0x330)
 mpu_irq		MPU-401 irq line (5, 7, 9, 10 or 0)
 
-The /etc/modules.conf will have lines like this:
+The /etc/modprobe.conf will have lines like this:
 
 options opl3 io=0x388
 options ad1848 io=0x530 irq=11 dma=3
@@ -51,11 +51,11 @@
 ad1848 are the corresponding options for the MSS and OPL3 modules.
 
 Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly
-the sound card. Installation dependencies must be written in the modules.conf
+the sound card. Installation dependencies must be written in the modprobe.conf
 file:
 
-pre-install ad1848 modprobe aedsp16
-pre-install opl3 modprobe aedsp16
+install ad1848 /sbin/modprobe aedsp16 && /sbin/modprobe -i ad1848
+install opl3 /sbin/modprobe aedsp16 && /sbin/modprobe -i opl3
 
 Then you must load the sound modules stack in this order:
 sound -> aedsp16 -> [ ad1848, opl3 ]
--- diff/Documentation/sound/oss/CMI8330	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/sound/oss/CMI8330	2004-02-18 09:03:58.000000000 +0000
@@ -143,7 +143,7 @@
 
 
 
-Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/modules.conf:
+Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/modprobe.conf:
 
 alias sound ad1848
 alias synth0 opl3
--- diff/Documentation/sound/oss/Introduction	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/sound/oss/Introduction	2004-02-18 09:03:58.000000000 +0000
@@ -168,7 +168,7 @@
 =========
 
 If loading via modprobe, these common files are automatically loaded 
-when requested by modprobe.  For example, my /etc/modules.conf contains:
+when requested by modprobe.  For example, my /etc/modprobe.conf contains:
 
 alias sound sb 
 options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300
@@ -228,7 +228,7 @@
 driver, you should do the following:
 
 1.  remove sound modules (detailed above)
-2.  remove the sound modules from /etc/modules.conf
+2.  remove the sound modules from /etc/modprobe.conf
 3.  move the sound modules from /lib/modules/<kernel>/misc
     (for example, I make a /lib/modules/<kernel>/misc/tmp
     directory and copy the sound module files to that 
@@ -265,7 +265,7 @@
     sb.o could be copied (or symlinked) to sb1.o for the
     second SoundBlaster.
 
-2.  Make a second entry in /etc/modules.conf, for example,
+2.  Make a second entry in /etc/modprobe.conf, for example,
     sound1 or sb1.  This second entry should refer to the
     new module names for example sb1, and should include
     the I/O, etc. for the second sound card.
@@ -369,7 +369,7 @@
 2)  On the command line when using insmod or in a bash script
     using command line calls to load sound.
 
-3)  In /etc/modules.conf when using modprobe.
+3)  In /etc/modprobe.conf when using modprobe.
 
 4)  Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based).
 
--- diff/Documentation/sound/oss/MAD16	2002-10-16 04:29:06.000000000 +0100
+++ source/Documentation/sound/oss/MAD16	2004-02-18 09:03:58.000000000 +0000
@@ -1,4 +1,5 @@
-(This recipe has been edited to update the configuration symbols.)
+(This recipe has been edited to update the configuration symbols,
+ and change over to modprobe.conf for 2.6)
 
 From: Shaw Carruthers <shaw@shawc.demon.co.uk>
 
@@ -20,9 +21,9 @@
 CONFIG_SOUND_MAD16=m
 CONFIG_SOUND_YM3812=m
 
-modules.conf has:
+modprobe.conf has:
 
-alias char-major-14 mad16
+alias char-major-14-* mad16
 options sb mad16=1
 options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
 
--- diff/Documentation/sound/oss/Maestro3	2002-10-16 04:28:34.000000000 +0100
+++ source/Documentation/sound/oss/Maestro3	2004-02-18 09:03:58.000000000 +0000
@@ -64,7 +64,7 @@
 installed with the rest of the modules for the kernel on the system.
 Typically this will be in /lib/modules/ somewhere.  'alias sound-slot-0
 maestro3' should also be added to your module configs (typically
-/etc/modules.conf) if you're using modular OSS/Lite sound and want to
+/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to
 default to using a maestro3 chip.
 
 There are very few options to the driver.  One is 'debug' which will 
--- diff/Documentation/sound/oss/OPL3-SA2	2002-10-16 04:27:14.000000000 +0100
+++ source/Documentation/sound/oss/OPL3-SA2	2004-02-18 09:03:58.000000000 +0000
@@ -162,7 +162,7 @@
 modprobe opl3 io=0x388
 
 See the section "Automatic Module Loading" below for how to set up
-/etc/modules.conf to automate this.
+/etc/modprobe.conf to automate this.
 
 An important thing to remember that the opl3sa2 module's io argument is
 for it's own control port, which handles the card's master mixer for
@@ -196,7 +196,7 @@
 
 Lastly, if you're using modules and want to set up automatic module
 loading with kmod, the kernel module loader, here is the section I
-currently use in my modules.conf file:
+currently use in my modprobe.conf file:
 
 # Sound
 alias sound-slot-0 opl3sa2
--- diff/Documentation/sound/oss/Opti	2002-10-16 04:27:53.000000000 +0100
+++ source/Documentation/sound/oss/Opti	2004-02-18 09:03:58.000000000 +0000
@@ -18,7 +18,7 @@
 If you have another OS installed on your computer it is recommended
 that Linux and the other OS use the same resources.
 
-Also, it is recommended that resources specified in /etc/modules.conf
+Also, it is recommended that resources specified in /etc/modprobe.conf
 and resources specified in /etc/isapnp.conf agree.
 
 Compiling the sound driver
@@ -68,9 +68,9 @@
 Using kmod and autoloading the sound driver
 -------------------------------------------
 Comment: as of linux-2.1.90 kmod is replacing kerneld.
-The config file '/etc/modules.conf' is used as before.
+The config file '/etc/modprobe.conf' is used as before.
 
-This is the sound part of my /etc/modules.conf file.
+This is the sound part of my /etc/modprobe.conf file.
 Following that I will explain each line.
 
 alias mixer0 mad16
@@ -80,7 +80,7 @@
 options sb mad16=1
 options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
 options opl3 io=0x388
-post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
+install mad16 /sbin/modprobe -i mad16 && /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
 
 If you have an MPU daughtercard or onboard MPU you will want to add to the
 "options mad16" line - eg 
--- diff/Documentation/sound/oss/PAS16	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/sound/oss/PAS16	2004-02-18 09:03:58.000000000 +0000
@@ -129,7 +129,7 @@
   You can then get OPL3 functionality by issuing the command:
   insmod opl3
   In addition, you must either add the following line to 
-  /etc/modules.conf:
+  /etc/modprobe.conf:
   options opl3 io=0x388
   or else add the following line to /etc/lilo.conf:
   opl3=0x388
@@ -159,5 +159,5 @@
 append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
 
 If sound is built totally modular, the above options may be 
-specified in /etc/modules.conf for pas2.o, sb.o and opl3.o 
+specified in /etc/modprobe.conf for pas2, sb and opl3
 respectively. 
--- diff/Documentation/sound/oss/README.modules	2002-10-16 04:27:53.000000000 +0100
+++ source/Documentation/sound/oss/README.modules	2004-02-18 09:03:58.000000000 +0000
@@ -26,10 +26,10 @@
 drivers/sound dir. Now one simply configures and makes one's kernel and
 modules in the usual way.
 
- Then, add to your /etc/modules.conf something like:
+ Then, add to your /etc/modprobe.conf something like:
 
-alias char-major-14 sb
-post-install sb /sbin/modprobe "-k" "adlib_card"
+alias char-major-14-* sb
+install sb /sbin/modprobe -i sb && /sbin/modprobe adlib_card
 options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
 options adlib_card io=0x388     # FM synthesizer
 
@@ -65,12 +65,12 @@
  Note that at present there is no way to configure the io, irq and other
 parameters for the modular drivers as one does for the wired drivers.. One
 needs to pass the modules the necessary parameters as arguments, either
-with /etc/modules.conf or with command-line args to modprobe, e.g.
+with /etc/modprobe.conf or with command-line args to modprobe, e.g.
 
-modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
-modprobe -k adlib_card io=0x388
+modprobe sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
+modprobe adlib_card io=0x388
 
- recommend using /etc/modules.conf.
+ recommend using /etc/modprobe.conf.
 
 Persistent DMA Buffers:
 
@@ -88,7 +88,7 @@
 
 To make the sound driver use persistent DMA buffers we need to pass the
 sound.o module a "dmabuf=1" command-line argument. This is normally done
-in /etc/modules.conf like so:
+in /etc/modprobe.conf like so:
 
 options sound		dmabuf=1
 
--- diff/Documentation/sound/oss/Wavefront	2004-01-19 10:22:54.000000000 +0000
+++ source/Documentation/sound/oss/Wavefront	2004-02-18 09:03:58.000000000 +0000
@@ -189,16 +189,15 @@
 6) How do I configure my card ?
 ************************************************************
 
-You need to edit /etc/modules.conf. Here's mine (edited to show the
+You need to edit /etc/modprobe.conf. Here's mine (edited to show the
 relevant details):
 
   # Sound system
-  alias char-major-14 wavefront
+  alias char-major-14-* wavefront
   alias synth0 wavefront
   alias mixer0 cs4232
   alias audio0 cs4232
-  pre-install wavefront modprobe "-k" "cs4232"
-  post-install wavefront modprobe "-k" "opl3"
+  install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3
   options wavefront io=0x200 irq=9
   options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
   options opl3 io=0x388
--- diff/Documentation/sysctl/fs.txt	2003-01-02 10:43:02.000000000 +0000
+++ source/Documentation/sysctl/fs.txt	2004-02-18 09:03:58.000000000 +0000
@@ -138,3 +138,13 @@
 can have. You only need to increase super-max if you need to
 mount more filesystems than the current value in super-max
 allows you to.
+
+==============================================================
+
+aio-nr & aio-max-nr:
+
+aio-nr shows the current system-wide number of asynchronous io
+requests.  aio-max-nr allows you to change the maximum value
+aio-nr can grow to.
+
+==============================================================
--- diff/Documentation/usb/acm.txt	2002-10-16 04:27:22.000000000 +0100
+++ source/Documentation/usb/acm.txt	2004-02-18 09:03:58.000000000 +0000
@@ -28,7 +28,7 @@
 
 1. Usage
 ~~~~~~~~
-  The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal
+  The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal
 adapters that conform to the Universal Serial Bus Communication Device Class
 Abstract Control Model (USB CDC ACM) specification.
 
@@ -65,9 +65,9 @@
 
   To use the modems you need these modules loaded:
 
-	usbcore.o
-	usb-[uo]hci.o or uhci.o
-	acm.o
+	usbcore.ko
+	uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
+	cdc-acm.ko
 
   After that, the modem[s] should be accessible. You should be able to use
 minicom, ppp and mgetty with them.
--- diff/Documentation/usb/scanner.txt	2003-05-21 11:49:49.000000000 +0100
+++ source/Documentation/usb/scanner.txt	2004-02-18 09:03:58.000000000 +0000
@@ -146,14 +146,14 @@
 
   options scanner vendor=0x#### product=0x****
 
-to the /etc/modules.conf file replacing the #'s and the *'s with the
+to the /etc/modprobe.conf file replacing the #'s and the *'s with the
 correct IDs.  The IDs can be retrieved from the messages file or
 using "cat /proc/bus/usb/devices".
 
 If the default timeout is too low, i.e. there are frequent "timeout" messages,
 you may want to increase the timeout manually by using the parameter
 "read_timeout".  The time is given in seconds.  This is an example for
-modules.conf with a timeout of 60 seconds:
+modprobe.conf with a timeout of 60 seconds:
 
   options scanner read_timeout=60
  
--- diff/Documentation/video4linux/CQcam.txt	2003-10-09 09:47:33.000000000 +0100
+++ source/Documentation/video4linux/CQcam.txt	2004-02-18 09:03:58.000000000 +0000
@@ -62,7 +62,7 @@
  
   The configuration requires module configuration and device
 configuration.  I like kmod or kerneld process with the
-/etc/modules.conf file so the modules can automatically load/unload as
+/etc/modprobe.conf file so the modules can automatically load/unload as
 they are used.  The video devices could already exist, be generated
 using MAKEDEV, or need to be created.  The following sections detail
 these procedures.
@@ -71,15 +71,15 @@
 2.1 Module Configuration  
 
   Using modules requires a bit of work to install and pass the
-parameters.  Understand that entries in /etc/modules.conf of:
+parameters.  Understand that entries in /etc/modprobe.conf of:
 
    alias parport_lowlevel parport_pc
    options parport_pc io=0x378 irq=none
    alias char-major-81 videodev
    alias char-major-81-0 c-qcam
 
-will cause the kmod/kerneld/modprobe to do certain things.  If you are
-using kmod or kerneld, then a request for a 'char-major-81-0' will cause
+will cause the kmod/modprobe to do certain things.  If you are
+using kmod, then a request for a 'char-major-81-0' will cause
 the 'c-qcam' module to load.  If you have other video sources with
 modules, you might want to assign the different minor numbers to
 different modules.
--- diff/Documentation/video4linux/Zoran	2003-09-30 15:46:10.000000000 +0100
+++ source/Documentation/video4linux/Zoran	2004-02-18 09:03:58.000000000 +0000
@@ -233,7 +233,7 @@
 option with X being the card number as given in the previous section.
 To have more than one card, use card=X1[,X2[,X3,[X4[..]]]]
 
-To automate this, add the following to your /etc/modules.conf:
+To automate this, add the following to your /etc/modprobe.conf:
 
 options zr36067 card=X1[,X2[,X3[,X4[..]]]]
 alias char-major-81-0 zr36067
--- diff/Documentation/video4linux/bttv/Modules.conf	2002-10-16 04:28:23.000000000 +0100
+++ source/Documentation/video4linux/bttv/Modules.conf	2004-02-18 09:03:58.000000000 +0000
@@ -1,3 +1,6 @@
+# For modern kernels (2.6 or above), this belongs in /etc/modprobe.conf
+# For for 2.4 kernels or earlier, this belongs in /etc/modules.conf.
+
 # i2c
 alias char-major-89	i2c-dev
 options i2c-core	i2c_debug=1
--- diff/Documentation/video4linux/bttv/README	2004-02-09 10:36:07.000000000 +0000
+++ source/Documentation/video4linux/bttv/README	2004-02-18 09:03:58.000000000 +0000
@@ -22,7 +22,7 @@
 cards is in CARDLIST.bttv
 
 If bttv takes very long to load (happens sometimes with the cheap
-cards which have no tuner), try adding this to your modules.conf:
+cards which have no tuner), try adding this to your modprobe.conf:
 	options i2c-algo-bit bit_test=1
 
 For the WinTV/PVR you need one firmware file from the driver CD:
--- diff/Documentation/video4linux/meye.txt	2003-11-25 15:24:57.000000000 +0000
+++ source/Documentation/video4linux/meye.txt	2004-02-18 09:03:58.000000000 +0000
@@ -42,7 +42,7 @@
 ---------------
 
 Several options can be passed to the meye driver, either by adding them
-to /etc/modules.conf file, when the driver is compiled as a module, or
+to /etc/modprobe.conf file, when the driver is compiled as a module, or
 by adding the following to the kernel command line (in your bootloader):
 
 	meye=gbuffers[,gbufsize[,video_nr]]
@@ -59,7 +59,7 @@
 -----------
 
 In order to automatically load the meye module on use, you can put those lines
-in your /etc/modules.conf file:
+in your /etc/modprobe.conf file:
 
 	alias char-major-81 videodev
 	alias char-major-81-0 meye
--- diff/MAINTAINERS	2004-02-18 08:54:06.000000000 +0000
+++ source/MAINTAINERS	2004-02-18 09:04:03.000000000 +0000
@@ -1186,6 +1186,12 @@
 W:	http://developer.osdl.org/rddunlap/kj-patches/
 S:	Maintained
 
+KGDB FOR I386 PLATFORM
+P:	George Anzinger
+M:	george@mvista.com
+L:	linux-net@vger.kernel.org
+S:	Supported
+
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
--- diff/Makefile	2004-02-18 08:54:06.000000000 +0000
+++ source/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 3
-EXTRAVERSION =
+EXTRAVERSION = -mm1
 NAME=Feisty Dunnart
 
 # *DOCUMENTATION*
@@ -444,6 +444,7 @@
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
+AFLAGS		+= -g
 endif
 
 # warn about C99 declaration after statement
--- diff/arch/alpha/kernel/alpha_ksyms.c	2003-06-30 10:07:32.000000000 +0100
+++ source/arch/alpha/kernel/alpha_ksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,6 +11,7 @@
 #include <linux/user.h>
 #include <linux/elfcore.h>
 #include <linux/socket.h>
+#include <linux/syscalls.h>
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/pci.h>
--- diff/arch/alpha/kernel/irq.c	2004-01-19 10:22:54.000000000 +0000
+++ source/arch/alpha/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -252,7 +252,7 @@
 irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -333,7 +333,7 @@
 prof_cpu_mask_read_proc(char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/alpha/kernel/osf_sys.c	2003-08-20 14:16:23.000000000 +0100
+++ source/arch/alpha/kernel/osf_sys.c	2004-02-18 09:03:57.000000000 +0000
@@ -17,6 +17,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
@@ -46,7 +47,6 @@
 #include <asm/processor.h>
 
 extern int do_pipe(int *);
-extern asmlinkage unsigned long sys_brk(unsigned long);
 
 /*
  * Brk needs to return an error.  Still support Linux's brk(0) query idiom,
@@ -821,7 +821,6 @@
    affects all sorts of things, like timeval and itimerval.  */
 
 extern struct timezone sys_tz;
-extern asmlinkage int sys_utimes(char *, struct timeval *);
 extern int do_adjtimex(struct timex *);
 
 struct timeval32
@@ -1315,8 +1314,6 @@
 }
 
 #ifdef CONFIG_OSF4_COMPAT
-extern ssize_t sys_readv(unsigned long, const struct iovec *, unsigned long);
-extern ssize_t sys_writev(unsigned long, const struct iovec *, unsigned long);
 
 /* Clear top 32 bits of iov_len in the user's buffer for
    compatibility with old versions of OSF/1 where iov_len
--- diff/arch/alpha/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/alpha/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -503,6 +503,7 @@
 	time_esterror = NTP_PHASE_LIMIT;
 
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/arm/Kconfig	2004-02-18 08:54:06.000000000 +0000
+++ source/arch/arm/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -639,6 +639,8 @@
 
 source "fs/Kconfig"
 
+source "arch/arm/oprofile/Kconfig"
+
 source "drivers/video/Kconfig"
 
 if ARCH_ACORN || ARCH_CLPS7500 || ARCH_TBOX || ARCH_SHARK || ARCH_SA1100 || PCI
--- diff/arch/arm/Makefile	2004-01-19 10:22:54.000000000 +0000
+++ source/arch/arm/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -116,6 +116,7 @@
 core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
 core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
 
+drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 drivers-$(CONFIG_ARCH_CLPS7500)	+= drivers/acorn/char/
 drivers-$(CONFIG_ARCH_L7200)	+= drivers/acorn/char/
 
--- diff/arch/arm/kernel/armksyms.c	2004-01-19 10:22:54.000000000 +0000
+++ source/arch/arm/kernel/armksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
 #include <asm/elf.h>
@@ -44,14 +45,6 @@
 extern void __bad_xchg(volatile void *ptr, int size);
 
 /*
- * syscalls
- */
-extern int sys_write(int, const char *, int);
-extern int sys_read(int, char *, int);
-extern int sys_lseek(int, off_t, int);
-extern int sys_exit(int);
-
-/*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
  * doesn't really matter since they're not versioned).
--- diff/arch/arm/kernel/sys_arm.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/arm/kernel/sys_arm.c	2004-02-18 09:03:57.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/fs.h>
 #include <linux/file.h>
@@ -137,7 +138,6 @@
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls.
  */
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 
 struct sel_arg_struct {
 	unsigned long n;
--- diff/arch/arm/kernel/time.c	2004-02-18 08:54:06.000000000 +0000
+++ source/arch/arm/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -85,6 +85,9 @@
  */
 static inline void do_profile(struct pt_regs *regs)
 {
+
+	profile_hook(regs);
+
 	if (!user_mode(regs) &&
 	    prof_buffer &&
 	    current->pid) {
--- diff/arch/arm26/Kconfig	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/arm26/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -216,11 +216,6 @@
 
 source "drivers/char/Kconfig"
 
-config KBDMOUSE
-	bool
-	depends on ARCH_ACORN && BUSMOUSE=y
-	default y
-
 source "drivers/media/Kconfig"
 
 source "fs/Kconfig"
--- diff/arch/arm26/kernel/armksyms.c	2003-06-30 10:07:18.000000000 +0100
+++ source/arch/arm26/kernel/armksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
 #include <asm/elf.h>
@@ -43,14 +44,6 @@
 extern void __bad_xchg(volatile void *ptr, int size);
 
 /*
- * syscalls
- */
-extern int sys_write(int, const char *, int);
-extern int sys_read(int, char *, int);
-extern int sys_lseek(int, off_t, int);
-extern int sys_exit(int);
-
-/*
  * libgcc functions - functions that are used internally by the
  * compiler...  (prototypes are not correct though, but that
  * doesn't really matter since they're not versioned).
--- diff/arch/arm26/kernel/sys_arm.c	2003-06-30 10:07:18.000000000 +0100
+++ source/arch/arm26/kernel/sys_arm.c	2004-02-18 09:03:57.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/fs.h>
 #include <linux/file.h>
@@ -138,7 +139,6 @@
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls.
  */
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 
 struct sel_arg_struct {
 	unsigned long n;
--- diff/arch/arm26/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/arm26/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -179,6 +179,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/cris/arch-v10/drivers/ethernet.c	2003-07-11 09:39:49.000000000 +0100
+++ source/arch/cris/arch-v10/drivers/ethernet.c	2004-02-18 09:03:57.000000000 +0000
@@ -482,7 +482,7 @@
 	/* Register device */
 	err = register_netdev(dev);
 	if (err) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/arch/cris/kernel/sys_cris.c	2003-07-11 09:39:50.000000000 +0100
+++ source/arch/cris/kernel/sys_cris.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,6 +11,7 @@
 
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
--- diff/arch/cris/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/cris/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -108,6 +108,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	local_irq_restore(flags);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/h8300/kernel/signal.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/h8300/kernel/signal.c	2004-02-18 09:03:57.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
@@ -46,8 +47,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options,
-			struct rusage * ru);
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
 /*
--- diff/arch/h8300/kernel/sys_h8300.c	2003-08-20 14:16:24.000000000 +0100
+++ source/arch/h8300/kernel/sys_h8300.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -155,8 +156,6 @@
 }
 #endif
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
 struct sel_arg_struct {
 	unsigned long n;
 	fd_set *inp, *outp, *exp;
@@ -261,7 +260,7 @@
 	return -EINVAL;
 }
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
 {
   return -ENOSYS;
 }
--- diff/arch/h8300/kernel/time.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/h8300/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -139,6 +139,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/i386/Kconfig	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -43,6 +43,15 @@
 	help
 	  Choose this option if your computer is a standard PC or compatible.
 
+config X86_ELAN
+	bool "AMD Elan"
+	help
+	  Select this for an AMD Elan processor.
+
+	  Do not use this option for K6/Athlon/Opteron processors!
+
+	  If unsure, choose "PC-compatible" instead.
+
 config X86_VOYAGER
 	bool "Voyager (NCR)"
 	help
@@ -130,6 +139,8 @@
 	default y
 	depends on SMP && X86_ES7000 && MPENTIUMIII
 
+if !X86_ELAN
+
 choice
 	prompt "Processor family"
 	default M686
@@ -222,14 +233,20 @@
 	  extended prefetch instructions in addition to the Pentium II
 	  extensions.
 
+config MPENTIUMM
+	bool "Pentium M"
+	help
+	  Select this for Intel Pentium M (not Pentium-4 M)
+	  notebook chips.
+
 config MPENTIUM4
-	bool "Pentium-4/Celeron(P4-based)/Xeon"
+	bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon"
 	help
-	  Select this for Intel Pentium 4 chips.  This includes both
-	  the Pentium 4 and P4-based Celeron chips.  This option
-	  enables compile flags optimized for the chip, uses the
-	  correct cache shift, and applies any applicable Pentium III
-	  optimizations.
+	  Select this for Intel Pentium 4 chips.  This includes the
+	  Pentium 4, P4-based Celeron and Xeon, and Pentium-4 M
+	  (not Pentium M) chips.  This option enables compile flags
+	  optimized for the chip, uses the correct cache shift, and
+	  applies any applicable Pentium III optimizations.
 
 config MK6
 	bool "K6/K6-II/K6-III"
@@ -312,6 +329,8 @@
 	  when it has moderate overhead. This is intended for generic 
 	  distributions kernels.
 
+endif
+
 #
 # Define implied options from the CPU selection here
 #
@@ -328,9 +347,9 @@
 config X86_L1_CACHE_SHIFT
 	int
 	default "7" if MPENTIUM4 || X86_GENERIC
-	default "4" if MELAN || M486 || M386
+	default "4" if X86_ELAN || M486 || M386
 	default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2
-	default "6" if MK7 || MK8
+	default "6" if MK7 || MK8 || MPENTIUMM
 
 config RWSEM_GENERIC_SPINLOCK
 	bool
@@ -374,22 +393,22 @@
 
 config X86_ALIGNMENT_16
 	bool
-	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2
+	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2
 	default y
 
 config X86_GOOD_APIC
 	bool
-	depends on MK7 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8
+	depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8
 	default y
 
 config X86_INTEL_USERCOPY
 	bool
-	depends on MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7
+	depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7
 	default y
 
 config X86_USE_PPRO_CHECKSUM
 	bool
-	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2
+	depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2
 	default y
 
 config X86_USE_3DNOW
@@ -402,6 +421,54 @@
 	depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
 	default y
 
+config X86_4G
+	bool "4 GB kernel-space and 4 GB user-space virtual memory support"
+	help
+          This option is only useful for systems that have more than 1 GB
+          of RAM.
+
+          The default kernel VM layout leaves 1 GB of virtual memory for
+          kernel-space mappings, and 3 GB of VM for user-space applications.
+          This option ups both the kernel-space VM and the user-space VM to
+          4 GB.
+
+          The cost of this option is additional TLB flushes done at
+          system-entry points that transition from user-mode into kernel-mode.
+          I.e. system calls and page faults, and IRQs that interrupt user-mode
+          code. There's also additional overhead to kernel operations that copy
+          memory to/from user-space. The overhead from this is hard to tell and
+          depends on the workload - it can be anything from no visible overhead
+          to 20-30% overhead. A good rule of thumb is to count with a runtime
+          overhead of 20%.
+
+          The upside is the much increased kernel-space VM, which more than
+          quadruples the maximum amount of RAM supported. Kernels compiled with
+          this option boot on 64GB of RAM and still have more than 3.1 GB of
+          'lowmem' left. Another bonus is that highmem IO bouncing decreases,
+          if used with drivers that still use bounce-buffers.
+
+          There's also a 33% increase in user-space VM size - database
+          applications might see a boost from this.
+
+          But the cost of the TLB flushes and the runtime overhead has to be
+          weighed against the bonuses offered by the larger VM spaces. The
+          dividing line depends on the actual workload - there might be 4 GB
+          systems that benefit from this option. Systems with less than 4 GB
+          of RAM will rarely see a benefit from this option - but it's not
+          out of question, the exact circumstances have to be considered.
+
+config X86_SWITCH_PAGETABLES
+	def_bool X86_4G
+
+config X86_4G_VM_LAYOUT
+	def_bool X86_4G
+
+config X86_UACCESS_INDIRECT
+	def_bool X86_4G
+
+config X86_HIGH_ENTRY
+	def_bool X86_4G
+
 config HPET_TIMER
 	bool "HPET Timer Support"
 	help
@@ -459,6 +526,16 @@
 	  This is purely to save memory - each supported CPU adds
 	  approximately eight kilobytes to the kernel image.
 
+config SCHED_SMT
+	bool "SMT (Hyperthreading) scheduler support"
+	depends on SMP
+	default off
+	help
+	  SMT scheduler support improves the CPU scheduler's decision making
+	  when dealing with Intel Pentium 4 chips with HyperThreading at a
+	  cost of slightly increased overhead in some places. If unsure say
+	  N here.
+
 config PREEMPT
 	bool "Preemptible Kernel"
 	help
@@ -513,7 +590,7 @@
 
 config X86_TSC
 	bool
-	depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ
+	depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ
 	default y
 
 config X86_MCE
@@ -603,8 +680,6 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called microcode.
-	  If you use modprobe or kmod you may also want to add the line
-	  'alias char-major-10-184 microcode' to your /etc/modules.conf file.
 
 config X86_MSR
 	tristate "/dev/cpu/*/msr - Model-specific register support"
@@ -701,7 +776,7 @@
 # Common NUMA Features
 config NUMA
 	bool "Numa Memory Allocation Support"
-	depends on SMP && HIGHMEM64G && (X86_PC || X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
+	depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
 	default n if X86_PC
 	default y if (X86_NUMAQ || X86_SUMMIT)
 
@@ -809,6 +884,14 @@
 	anything about EFI).  However, even with this option, the resultant
 	kernel should continue to boot on existing non-EFI platforms.
 
+config IRQBALANCE
+ 	bool "Enable kernel irq balancing"
+	depends on SMP
+	default y
+	help
+ 	  The defalut yes will allow the kernel to do irq load balancing.
+	  Saying no will keep the kernel from doing irq load balancing.
+
 config HAVE_DEC_LOCK
 	bool
 	depends on (SMP || PREEMPT) && X86_CMPXCHG
@@ -821,6 +904,19 @@
 	depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
 	default y
 
+config REGPARM
+	bool "Use register arguments (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	default n
+	help
+	Compile the kernel with -mregparm=3. This uses an different ABI
+	and passes the first three arguments of a function call in registers.
+	This will probably break binary only modules.
+
+	This feature is only enabled for gcc-3.0 and later - earlier compilers
+	generate incorrect output with certain kernel constructs when
+	-mregparm=3 is used.
+
 endmenu
 
 
@@ -1030,12 +1126,16 @@
 	  PCI-based systems don't have any BIOS at all. Linux can also try to
 	  detect the PCI hardware directly without using the BIOS.
 
-	  With this option, you can specify how Linux should detect the PCI
-	  devices. If you choose "BIOS", the BIOS will be used, if you choose
-	  "Direct", the BIOS won't be used, and if you choose "Any", the
-	  kernel will try the direct access method and falls back to the BIOS
-	  if that doesn't work. If unsure, go with the default, which is
-	  "Any".
+	  With this option, you can specify how Linux should detect the
+	  PCI devices. If you choose "BIOS", the BIOS will be used,
+	  if you choose "Direct", the BIOS won't be used, and if you
+	  choose "MMConfig", then PCI Express MMCONFIG will be used.
+	  If you choose "Any", the kernel will try MMCONFIG, then the
+	  direct access method and falls back to the BIOS if that doesn't
+	  work. If unsure, go with the default, which is "Any".
+
+config PCI_GOMMCONFIG
+	bool "MMConfig"
 
 config PCI_GODIRECT
 	bool "Direct"
@@ -1055,6 +1155,12 @@
  	depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
 	default y
 
+config PCI_MMCONFIG
+	bool
+	depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY)
+	select ACPI_BOOT
+	default y
+
 config PCI_USE_VECTOR
 	bool "Vector-based interrupt indexing"
 	depends on X86_LOCAL_APIC && X86_IO_APIC
@@ -1177,6 +1283,19 @@
 	  Say Y here if you are developing drivers or trying to debug and
 	  identify kernel problems.
 
+config EARLY_PRINTK
+	bool "Early printk" if EMBEDDED
+	default y
+	help
+	  Write kernel log output directly into the VGA buffer or to a serial
+	  port.
+
+	  This is useful for kernel debugging when your machine crashes very
+	  early before the console code is initialized. For normal operation
+	  it is not recommended because it looks ugly and doesn't cooperate
+	  with klogd/syslogd or the X server. You should normally N here,
+	  unless you want to debug such a crash.
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
@@ -1231,6 +1350,15 @@
 	  This results in a large slowdown, but helps to find certain types
 	  of memory corruptions.
 
+config SPINLINE
+	bool "Spinlock inlining"
+	depends on DEBUG_KERNEL
+	help
+	  This will change spinlocks from out of line to inline, making them
+	  account cost to the callers in readprofile, rather than the lock
+	  itself (as ".text.lock.filename"). This can be helpful for finding
+	  the callers of locks.
+
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
 	depends on DEBUG_KERNEL && HIGHMEM
@@ -1247,20 +1375,208 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 	  
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 config DEBUG_SPINLOCK_SLEEP
 	bool "Sleep-inside-spinlock checking"
 	help
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
+	default KGDB
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
 	  and slower, but it will give very useful debugging information.
 	  If you don't debug the kernel, you can say N, but we may not be able
 	  to solve problems without frame pointers.
 
+config MAGIC_SYSRQ
+	bool
+	depends on KGDB_SYSRQ
+	default y
+
 config X86_FIND_SMP_CONFIG
 	bool
 	depends on X86_LOCAL_APIC || X86_VOYAGER
--- diff/arch/i386/Makefile	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -19,7 +19,7 @@
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
 LDFLAGS_vmlinux :=
 
-CFLAGS += -pipe
+CFLAGS += -pipe -msoft-float
 
 # prevent gcc from keeping the stack 16 byte aligned
 CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
@@ -34,8 +34,9 @@
 cflags-$(CONFIG_M686)		+= -march=i686
 cflags-$(CONFIG_MPENTIUMII)	+= $(call check_gcc,-march=pentium2,-march=i686)
 cflags-$(CONFIG_MPENTIUMIII)	+= $(call check_gcc,-march=pentium3,-march=i686)
+cflags-$(CONFIG_MPENTIUMM)	+= $(call check_gcc,-march=pentium3,-march=i686)
 cflags-$(CONFIG_MPENTIUM4)	+= $(call check_gcc,-march=pentium4,-march=i686)
-cflags-$(CONFIG_MK6)		+= $(call check_gcc,-march=k6,-march=i586)
+cflags-$(CONFIG_MK6)		+= -march=k6
 # Please note, that patches that add -march=athlon-xp and friends are pointless.
 # They make zero difference whatsosever to performance at this time.
 cflags-$(CONFIG_MK7)		+= $(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4)
@@ -47,6 +48,18 @@
 cflags-$(CONFIG_MCYRIXIII)	+= $(call check_gcc,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MVIAC3_2)	+= $(call check_gcc,-march=c3-2,-march=i686)
 
+# AMD Elan support
+cflags-$(CONFIG_X86_ELAN)	+= -march=i486
+
+# -mregparm=3 works ok on gcc-3.0 and later
+#
+GCC_VERSION			:= $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
+cflags-$(CONFIG_REGPARM) 	+= $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
+
+# Enable unit-at-a-time mode when possible. It shrinks the
+# kernel considerably.
+CFLAGS += $(call check_gcc,-funit-at-a-time,)
+
 CFLAGS += $(cflags-y)
 
 # Default subarch .c files
@@ -84,6 +97,9 @@
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
+mflags-$(CONFIG_KGDB) += -gdwarf-2
+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
+
 head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
--- diff/arch/i386/boot/Makefile	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/i386/boot/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -31,6 +31,8 @@
 
 host-progs	:= tools/build
 
+HOSTCFLAGS_build.o := -Iinclude
+
 # ---------------------------------------------------------------------------
 
 $(obj)/zImage:  IMAGE_OFFSET := 0x1000
--- diff/arch/i386/boot/setup.S	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/boot/setup.S	2004-02-18 09:03:57.000000000 +0000
@@ -164,7 +164,7 @@
 					# can be located anywhere in
 					# low memory 0x10000 or higher.
 
-ramdisk_max:	.long MAXMEM-1		# (Header version 0x0203 or later)
+ramdisk_max:	.long __MAXMEM-1	# (Header version 0x0203 or later)
 					# The highest safe address for
 					# the contents of an initrd
 
@@ -776,7 +776,7 @@
 # AMD Elan bug fix by Robert Schwebel.
 #
 
-#if defined(CONFIG_MELAN)
+#if defined(CONFIG_X86_ELAN)
 	movb $0x02, %al			# alternate A20 gate
 	outb %al, $0x92			# this works on SC410/SC520
 a20_elan_wait:
--- diff/arch/i386/kernel/Makefile	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -7,13 +7,14 @@
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
-		doublefault.o
+		doublefault.o entry_trampoline.o
 
 obj-y				+= cpu/
 obj-y				+= timers/
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
@@ -31,6 +32,7 @@
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
+obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 
 EXTRA_AFLAGS   := -traditional
 
--- diff/arch/i386/kernel/acpi/boot.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/acpi/boot.c	2004-02-18 09:03:57.000000000 +0000
@@ -96,6 +96,31 @@
 }
 
 
+#ifdef CONFIG_PCI_MMCONFIG
+static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg *mcfg;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+
+	if (mcfg->base_reserved) {
+		printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+		return -ENODEV;
+	}
+
+	pci_mmcfg_base_addr = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_PCI_MMCONFIG */
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
@@ -339,7 +364,7 @@
 	 * RSDP signature.
 	 */
 	for (offset = 0; offset < length; offset += 16) {
-		if (strncmp((char *) (start + offset), "RSD PTR ", sig_len))
+		if (strncmp((char *) __va(start + offset), "RSD PTR ", sig_len))
 			continue;
 		return (start + offset);
 	}
@@ -376,6 +401,37 @@
 }
 #endif
 
+/* detect the location of the ACPI PM Timer */
+#ifdef CONFIG_X86_PM_TIMER
+extern u32 pmtmr_ioport;
+
+static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
+{
+	struct fadt_descriptor_rev2 *fadt =0;
+
+	fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size);
+	if(!fadt) {
+		printk(KERN_WARNING PREFIX "Unable to map FADT\n");
+		return 0;
+	}
+
+	if (fadt->revision >= FADT2_REVISION_ID) {
+		/* FADT rev. 2 */
+		if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO)
+			return 0;
+
+		pmtmr_ioport = fadt->xpm_tmr_blk.address;
+	} else {
+		/* FADT rev. 1 */
+		pmtmr_ioport = fadt->V1_pm_tmr_blk;
+	}
+	if (pmtmr_ioport)
+		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport);
+	return 0;
+}
+#endif
+
+
 unsigned long __init
 acpi_find_rsdp (void)
 {
@@ -398,55 +454,14 @@
 	return rsdp_phys;
 }
 
-/*
- * acpi_boot_init()
- *  called from setup_arch(), always.
- *	1. maps ACPI tables for later use
- *	2. enumerates lapics
- *	3. enumerates io-apics
- *
- * side effects:
- *	acpi_lapic = 1 if LAPIC found
- *	acpi_ioapic = 1 if IOAPIC found
- *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
- *	if acpi_blacklisted() acpi_disabled = 1;
- *	acpi_irq_model=...
- *	...
- *
- * return value: (currently ignored)
- *	0: success
- *	!0: failure
- */
 
-int __init
-acpi_boot_init (void)
+static int acpi_apic_setup(void)
 {
-	int			result = 0;
+	int result;
 
-	if (acpi_disabled && !acpi_ht)
-		 return 1;
-
-	/*
-	 * The default interrupt routing model is PIC (8259).  This gets
-	 * overriden if IOAPICs are enumerated (below).
-	 */
-	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
-
-	/* 
-	 * Initialize the ACPI boot-time table parser.
-	 */
-	result = acpi_table_init();
-	if (result) {
-		acpi_disabled = 1;
-		return result;
-	}
-
-	result = acpi_blacklisted();
-	if (result) {
-		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
-		acpi_disabled = 1;
-		return result;
-	}
+#ifdef CONFIG_X86_PM_TIMER
+	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
+#endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -506,24 +521,17 @@
 
 	acpi_lapic = 1;
 
-#endif /*CONFIG_X86_LOCAL_APIC*/
+#endif /* CONFIG_X86_LOCAL_APIC */
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER)
 
 	/* 
 	 * I/O APIC 
-	 * --------
 	 */
 
-	/*
-	 * ACPI interpreter is required to complete interrupt setup,
-	 * so if it is off, don't enumerate the io-apics with ACPI.
-	 * If MPS is present, it will handle them,
-	 * otherwise the system will stay in PIC mode
-	 */
-	if (acpi_disabled || acpi_noirq) {
+	if (acpi_noirq) {
 		return 1;
-        }
+	}
 
 	/*
  	 * if "noapic" boot option, don't look for IO-APICs
@@ -538,8 +546,7 @@
 	if (!result) {
 		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
 		return -ENODEV;
-	}
-	else if (result < 0) {
+	} else if (result < 0) {
 		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
 		return result;
 	}
@@ -569,16 +576,87 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
-#ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
 		clustered_apic_check();
 	}
-#endif
+
+	return 0;
+}
+
+/*
+ * acpi_boot_init()
+ *  called from setup_arch(), always.
+ *	1. maps ACPI tables for later use
+ *	2. enumerates lapics
+ *	3. enumerates io-apics
+ *
+ * side effects:
+ *	acpi_lapic = 1 if LAPIC found
+ *	acpi_ioapic = 1 if IOAPIC found
+ *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
+ *	if acpi_blacklisted() acpi_disabled = 1;
+ *	acpi_irq_model=...
+ *	...
+ *
+ * return value: (currently ignored)
+ *	0: success
+ *	!0: failure
+ */
+
+int __init
+acpi_boot_init (void)
+{
+	int result, error;
+
+	if (acpi_disabled && !acpi_ht)
+		 return 1;
+
+	/*
+	 * The default interrupt routing model is PIC (8259).  This gets
+	 * overriden if IOAPICs are enumerated (below).
+	 */
+	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
+
+	/*
+	 * Initialize the ACPI boot-time table parser.
+	 */
+	result = acpi_table_init();
+	if (result) {
+		acpi_disabled = 1;
+		return result;
+	}
+
+	result = acpi_blacklisted();
+	if (result) {
+		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
+		acpi_disabled = 1;
+		return result;
+	}
+
+	error = acpi_apic_setup();
+
+#ifdef CONFIG_PCI_MMCONFIG
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result);
+		if (!error)
+			error = result;
+	} else if (result > 1) {
+		printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n");
+	}
+#endif /* CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_HPET_TIMER
-	acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error %d parsing HPET\n", result);
+		if (!error)
+			error = result;
+	} else if (result > 1) {
+		printk(KERN_WARNING PREFIX "Multiple HPET tables exist\n");
+	}
 #endif
 
-	return 0;
+	return error;
 }
--- diff/arch/i386/kernel/asm-offsets.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/asm-offsets.c	2004-02-18 09:03:57.000000000 +0000
@@ -4,9 +4,11 @@
  * to extract and format the required data.
  */
 
+#include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/ucontext.h>
 #include "sigframe.h"
+#include <asm/fixmap.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -28,4 +30,17 @@
 
 	DEFINE(RT_SIGFRAME_sigcontext,
 	       offsetof (struct rt_sigframe, uc.uc_mcontext));
+	DEFINE(TI_task, offsetof (struct thread_info, task));
+	DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain));
+	DEFINE(TI_flags, offsetof (struct thread_info, flags));
+	DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count));
+	DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit));
+	DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack));
+	DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack));
+	DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd));
+
+	DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0));
+	DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL));
+	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
+	DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7]));
 }
--- diff/arch/i386/kernel/cpu/centaur.c	2003-05-21 11:49:49.000000000 +0100
+++ source/arch/i386/kernel/cpu/centaur.c	2004-02-18 09:03:57.000000000 +0000
@@ -246,7 +246,15 @@
 	lo&=~0x1C0;	/* blank bits 8-6 */
 	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
 }
-#endif
+#endif /* CONFIG_X86_OOSTORE */
+
+#define ACE_PRESENT	(1 << 6)
+#define ACE_ENABLED	(1 << 7)
+#define ACE_FCR		(1 << 28)	/* MSR_VIA_FCR */
+
+#define RNG_PRESENT	(1 << 2)
+#define RNG_ENABLED	(1 << 3)
+#define RNG_ENABLE	(1 << 6)	/* MSR_VIA_RNG */
 
 static void __init init_c3(struct cpuinfo_x86 *c)
 {
@@ -254,6 +262,24 @@
 
 	/* Test for Centaur Extended Feature Flags presence */
 	if (cpuid_eax(0xC0000000) >= 0xC0000001) {
+		u32 tmp = cpuid_edx(0xC0000001);
+
+		/* enable ACE unit, if present and disabled */
+		if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
+			rdmsr (MSR_VIA_FCR, lo, hi);
+			lo |= ACE_FCR;		/* enable ACE unit */
+			wrmsr (MSR_VIA_FCR, lo, hi);
+			printk(KERN_INFO "CPU: Enabled ACE h/w crypto\n");
+		}
+
+		/* enable RNG unit, if present and disabled */
+		if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
+			rdmsr (MSR_VIA_RNG, lo, hi);
+			lo |= RNG_ENABLE;	/* enable RNG unit */
+			wrmsr (MSR_VIA_RNG, lo, hi);
+			printk(KERN_INFO "CPU: Enabled h/w RNG\n");
+		}
+
 		/* store Centaur Extended Feature Flags as
 		 * word 5 of the CPU capability bit array
 		 */
--- diff/arch/i386/kernel/cpu/common.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/cpu/common.c	2004-02-18 09:03:57.000000000 +0000
@@ -514,12 +514,16 @@
 	set_tss_desc(cpu,t);
 	cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
 	load_TR_desc();
-	load_LDT(&init_mm.context);
+	if (cpu)
+		load_LDT(&init_mm.context);
 
 	/* Set up doublefault TSS pointer in the GDT */
 	__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
 	cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
 
+	if (cpu)
+		trap_init_virtual_GDT();
+
 	/* Clear %fs and %gs. */
 	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
 
--- diff/arch/i386/kernel/cpu/cpufreq/Kconfig	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/cpufreq/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -54,7 +54,7 @@
 
 config ELAN_CPUFREQ
 	tristate "AMD Elan"
-	depends on CPU_FREQ_TABLE && MELAN
+	depends on CPU_FREQ_TABLE && X86_ELAN
 	---help---
 	  This adds the CPUFreq driver for AMD Elan SC400 and SC410
 	  processors.
--- diff/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	2004-02-18 09:03:57.000000000 +0000
@@ -57,8 +57,7 @@
 	u32 l, h;
 	cpumask_t cpus_allowed, affected_cpu_map;
 	struct cpufreq_freqs freqs;
-	int hyperthreading = 0;
-	int sibling = 0;
+	int j;
 
 	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || 
 		(newstate == DC_RESV))
@@ -68,13 +67,10 @@
 	cpus_allowed = current->cpus_allowed;
 
 	/* only run on CPU to be set, or on its sibling */
-       affected_cpu_map = cpumask_of_cpu(cpu);
-#ifdef CONFIG_X86_HT
-	hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2));
-	if (hyperthreading) {
-		sibling = cpu_sibling_map[cpu];
-                cpu_set(sibling, affected_cpu_map);
-	}
+#ifdef CONFIG_SMP
+	affected_cpu_map = cpu_sibling_map[cpu];
+#else
+	affected_cpu_map = cpumask_of_cpu(cpu);
 #endif
 	set_cpus_allowed(current, affected_cpu_map);
         BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
@@ -97,11 +93,11 @@
 	/* notifiers */
 	freqs.old = stock_freq * l / 8;
 	freqs.new = stock_freq * newstate / 8;
-	freqs.cpu = cpu;
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-	if (hyperthreading) {
-		freqs.cpu = sibling;
-		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	for_each_cpu(j) {
+		if (cpu_isset(j, affected_cpu_map)) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+		}
 	}
 
 	rdmsr(MSR_IA32_THERM_STATUS, l, h);
@@ -132,10 +128,11 @@
 	set_cpus_allowed(current, cpus_allowed);
 
 	/* notifiers */
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-	if (hyperthreading) {
-		freqs.cpu = cpu;
-		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	for_each_cpu(j) {
+		if (cpu_isset(j, affected_cpu_map)) {
+			freqs.cpu = j;
+			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+		}
 	}
 
 	return 0;
--- diff/arch/i386/kernel/cpu/intel.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/intel.c	2004-02-18 09:03:57.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/uaccess.h>
+#include <asm/desc.h>
 
 #include "cpu.h"
 
@@ -19,8 +20,6 @@
 #include <mach_apic.h>
 #endif
 
-extern int trap_init_f00f_bug(void);
-
 #ifdef CONFIG_X86_INTEL_USERCOPY
 /*
  * Alignment at which movsl is preferred for bulk memory copies.
@@ -165,7 +164,7 @@
 
 		c->f00f_bug = 1;
 		if ( !f00f_workaround_enabled ) {
-			trap_init_f00f_bug();
+			trap_init_virtual_IDT();
 			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
 			f00f_workaround_enabled = 1;
 		}
@@ -248,6 +247,12 @@
 	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
 	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
 		clear_bit(X86_FEATURE_SEP, c->x86_capability);
+	/*
+	 * FIXME: SEP is disabled for 4G/4G for now:
+	 */
+#ifdef CONFIG_X86_HIGH_ENTRY
+	clear_bit(X86_FEATURE_SEP, c->x86_capability);
+#endif
 
 	/* Names for the Pentium II/Celeron processors 
 	   detectable only by also checking the cache size.
--- diff/arch/i386/kernel/cpu/mcheck/non-fatal.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/kernel/cpu/mcheck/non-fatal.c	2004-02-18 09:03:57.000000000 +0000
@@ -24,8 +24,6 @@
 
 #include "mce.h"
 
-static struct timer_list mce_timer;
-static int timerset;
 static int firstbank;
 
 #define MCE_RATE	15*HZ	/* timer rate is 15s */
@@ -35,14 +33,15 @@
 	u32 low, high;
 	int i;
 
-	preempt_disable(); 
 	for (i=firstbank; i<nr_mce_banks; i++) {
 		rdmsr (MSR_IA32_MC0_STATUS+i*4, low, high);
 
 		if (high & (1<<31)) {
-			printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occurred on CPU %d.\n",
+			printk(KERN_INFO "MCE: The hardware reports a non "
+				"fatal, correctable incident occurred on "
+				"CPU %d.\n",
 				smp_processor_id());
-			printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
+			printk (KERN_INFO "Bank %d: %08x%08x\n", i, high, low);
 
 			/* Scrub the error so we don't pick it up in MCE_RATE seconds time. */
 			wrmsr (MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
@@ -51,27 +50,17 @@
 			wmb();
 		}
 	}
-	preempt_enable();
 }
 
-static void do_mce_timer(void *data)
+static void mce_work_fn(void *data);
+static DECLARE_WORK(mce_work, mce_work_fn, NULL);
+
+static void mce_work_fn(void *data)
 { 
-	smp_call_function (mce_checkregs, NULL, 1, 1);
+	on_each_cpu(mce_checkregs, NULL, 1, 1);
+	schedule_delayed_work(&mce_work, MCE_RATE);
 } 
 
-static DECLARE_WORK(mce_work, do_mce_timer, NULL);
-
-static void mce_timerfunc (unsigned long data)
-{
-	mce_checkregs (NULL);
-#ifdef CONFIG_SMP
-	if (num_online_cpus() > 1) 
-		schedule_work (&mce_work); 
-#endif
-	mce_timer.expires = jiffies + MCE_RATE;
-	add_timer (&mce_timer);
-}	
-
 static int __init init_nonfatal_mce_checker(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -91,17 +80,11 @@
 	else
 			firstbank = 0;
 
-	if (timerset == 0) {
-		/* Set the timer to check for non-fatal
-		   errors every MCE_RATE seconds */
-		init_timer (&mce_timer);
-		mce_timer.expires = jiffies + MCE_RATE;
-		mce_timer.data = 0;
-		mce_timer.function = &mce_timerfunc;
-		add_timer (&mce_timer);
-		timerset = 1;
-		printk(KERN_INFO "Machine check exception polling timer started.\n");
-	}
+	/*
+	 * Check for non-fatal errors every MCE_RATE s
+	 */
+	schedule_delayed_work(&mce_work, MCE_RATE);
+	printk(KERN_INFO "Machine check exception polling timer started.\n");
 	return 0;
 }
 module_init(init_nonfatal_mce_checker);
--- diff/arch/i386/kernel/cpu/proc.c	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/i386/kernel/cpu/proc.c	2004-02-18 09:03:57.000000000 +0000
@@ -50,7 +50,7 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 		/* VIA/Cyrix/Centaur-defined */
-		NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
--- diff/arch/i386/kernel/doublefault.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/doublefault.c	2004-02-18 09:03:57.000000000 +0000
@@ -7,12 +7,13 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
+#include <asm/fixmap.h>
 
 #define DOUBLEFAULT_STACKSIZE (1024)
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
 
-#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000)
+#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START))
 
 static void doublefault_fn(void)
 {
@@ -38,8 +39,8 @@
 
 			printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
 				t->eax, t->ebx, t->ecx, t->edx);
-			printk("esi = %08lx, edi = %08lx\n",
-				t->esi, t->edi);
+			printk("esi = %08lx, edi = %08lx, ebp = %08lx\n",
+				t->esi, t->edi, t->ebp);
 		}
 	}
 
--- diff/arch/i386/kernel/edd.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/edd.c	2004-02-18 09:03:57.000000000 +0000
@@ -134,18 +134,18 @@
 
 	for (i = 0; i < 4; i++) {
 		if (isprint(info->params.host_bus_type[i])) {
-			p += snprintf(p, left, "%c", info->params.host_bus_type[i]);
+			p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
 		} else {
-			p += snprintf(p, left, " ");
+			p += scnprintf(p, left, " ");
 		}
 	}
 
 	if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
-		p += snprintf(p, left, "\tbase_address: %x\n",
+		p += scnprintf(p, left, "\tbase_address: %x\n",
 			     info->params.interface_path.isa.base_address);
 	} else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
 		   !strncmp(info->params.host_bus_type, "PCI", 3)) {
-		p += snprintf(p, left,
+		p += scnprintf(p, left,
 			     "\t%02x:%02x.%d  channel: %u\n",
 			     info->params.interface_path.pci.bus,
 			     info->params.interface_path.pci.slot,
@@ -154,12 +154,12 @@
 	} else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
 		   !strncmp(info->params.host_bus_type, "XPRS", 4) ||
 		   !strncmp(info->params.host_bus_type, "HTPT", 4)) {
-		p += snprintf(p, left,
+		p += scnprintf(p, left,
 			     "\tTBD: %llx\n",
 			     info->params.interface_path.ibnd.reserved);
 
 	} else {
-		p += snprintf(p, left, "\tunknown: %llx\n",
+		p += scnprintf(p, left, "\tunknown: %llx\n",
 			     info->params.interface_path.unknown.reserved);
 	}
 	return (p - buf);
@@ -178,43 +178,43 @@
 
 	for (i = 0; i < 8; i++) {
 		if (isprint(info->params.interface_type[i])) {
-			p += snprintf(p, left, "%c", info->params.interface_type[i]);
+			p += scnprintf(p, left, "%c", info->params.interface_type[i]);
 		} else {
-			p += snprintf(p, left, " ");
+			p += scnprintf(p, left, " ");
 		}
 	}
 	if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
-		p += snprintf(p, left, "\tdevice: %u  lun: %u\n",
+		p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
 			     info->params.device_path.atapi.device,
 			     info->params.device_path.atapi.lun);
 	} else if (!strncmp(info->params.interface_type, "ATA", 3)) {
-		p += snprintf(p, left, "\tdevice: %u\n",
+		p += scnprintf(p, left, "\tdevice: %u\n",
 			     info->params.device_path.ata.device);
 	} else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
-		p += snprintf(p, left, "\tid: %u  lun: %llu\n",
+		p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
 			     info->params.device_path.scsi.id,
 			     info->params.device_path.scsi.lun);
 	} else if (!strncmp(info->params.interface_type, "USB", 3)) {
-		p += snprintf(p, left, "\tserial_number: %llx\n",
+		p += scnprintf(p, left, "\tserial_number: %llx\n",
 			     info->params.device_path.usb.serial_number);
 	} else if (!strncmp(info->params.interface_type, "1394", 4)) {
-		p += snprintf(p, left, "\teui: %llx\n",
+		p += scnprintf(p, left, "\teui: %llx\n",
 			     info->params.device_path.i1394.eui);
 	} else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
-		p += snprintf(p, left, "\twwid: %llx lun: %llx\n",
+		p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
 			     info->params.device_path.fibre.wwid,
 			     info->params.device_path.fibre.lun);
 	} else if (!strncmp(info->params.interface_type, "I2O", 3)) {
-		p += snprintf(p, left, "\tidentity_tag: %llx\n",
+		p += scnprintf(p, left, "\tidentity_tag: %llx\n",
 			     info->params.device_path.i2o.identity_tag);
 	} else if (!strncmp(info->params.interface_type, "RAID", 4)) {
-		p += snprintf(p, left, "\tidentity_tag: %x\n",
+		p += scnprintf(p, left, "\tidentity_tag: %x\n",
 			     info->params.device_path.raid.array_number);
 	} else if (!strncmp(info->params.interface_type, "SATA", 4)) {
-		p += snprintf(p, left, "\tdevice: %u\n",
+		p += scnprintf(p, left, "\tdevice: %u\n",
 			     info->params.device_path.sata.device);
 	} else {
-		p += snprintf(p, left, "\tunknown: %llx %llx\n",
+		p += scnprintf(p, left, "\tunknown: %llx %llx\n",
 			     info->params.device_path.unknown.reserved1,
 			     info->params.device_path.unknown.reserved2);
 	}
@@ -256,7 +256,7 @@
 		return -EINVAL;
 	}
 
-	p += snprintf(p, left, "0x%02x\n", info->version);
+	p += scnprintf(p, left, "0x%02x\n", info->version);
 	return (p - buf);
 }
 
@@ -264,7 +264,7 @@
 edd_show_disk80_sig(struct edd_device *edev, char *buf)
 {
 	char *p = buf;
-	p += snprintf(p, left, "0x%08x\n", edd_disk80_sig);
+	p += scnprintf(p, left, "0x%08x\n", edd_disk80_sig);
 	return (p - buf);
 }
 
@@ -278,16 +278,16 @@
 	}
 
 	if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
-		p += snprintf(p, left, "Fixed disk access\n");
+		p += scnprintf(p, left, "Fixed disk access\n");
 	}
 	if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
-		p += snprintf(p, left, "Device locking and ejecting\n");
+		p += scnprintf(p, left, "Device locking and ejecting\n");
 	}
 	if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
-		p += snprintf(p, left, "Enhanced Disk Drive support\n");
+		p += scnprintf(p, left, "Enhanced Disk Drive support\n");
 	}
 	if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
-		p += snprintf(p, left, "64-bit extensions\n");
+		p += scnprintf(p, left, "64-bit extensions\n");
 	}
 	return (p - buf);
 }
@@ -302,21 +302,21 @@
 	}
 
 	if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
-		p += snprintf(p, left, "DMA boundary error transparent\n");
+		p += scnprintf(p, left, "DMA boundary error transparent\n");
 	if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
-		p += snprintf(p, left, "geometry valid\n");
+		p += scnprintf(p, left, "geometry valid\n");
 	if (info->params.info_flags & EDD_INFO_REMOVABLE)
-		p += snprintf(p, left, "removable\n");
+		p += scnprintf(p, left, "removable\n");
 	if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
-		p += snprintf(p, left, "write verify\n");
+		p += scnprintf(p, left, "write verify\n");
 	if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
-		p += snprintf(p, left, "media change notification\n");
+		p += scnprintf(p, left, "media change notification\n");
 	if (info->params.info_flags & EDD_INFO_LOCKABLE)
-		p += snprintf(p, left, "lockable\n");
+		p += scnprintf(p, left, "lockable\n");
 	if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
-		p += snprintf(p, left, "no media present\n");
+		p += scnprintf(p, left, "no media present\n");
 	if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
-		p += snprintf(p, left, "use int13 fn50\n");
+		p += scnprintf(p, left, "use int13 fn50\n");
 	return (p - buf);
 }
 
@@ -329,7 +329,7 @@
 		return -EINVAL;
 	}
 
-	p += snprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
+	p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
 	return (p - buf);
 }
 
@@ -342,7 +342,7 @@
 		return -EINVAL;
 	}
 
-	p += snprintf(p, left, "0x%x\n", info->params.num_default_heads);
+	p += scnprintf(p, left, "0x%x\n", info->params.num_default_heads);
 	return (p - buf);
 }
 
@@ -355,7 +355,7 @@
 		return -EINVAL;
 	}
 
-	p += snprintf(p, left, "0x%x\n", info->params.sectors_per_track);
+	p += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track);
 	return (p - buf);
 }
 
@@ -368,7 +368,7 @@
 		return -EINVAL;
 	}
 
-	p += snprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
+	p += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
 	return (p - buf);
 }
 
--- diff/arch/i386/kernel/entry.S	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/i386/kernel/entry.S	2004-02-18 09:03:57.000000000 +0000
@@ -43,11 +43,25 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
+#include <asm/asm_offsets.h>
 #include <asm/errno.h>
 #include <asm/segment.h>
+#include <asm/page.h>
 #include <asm/smp.h>
 #include <asm/page.h>
 #include "irq_vectors.h"
+        /* We do not recover from a stack overflow, but at least
+         * we know it happened and should be able to track it down.
+         */
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#define STACK_OVERFLOW_TEST \
+        testl $7680,%esp;    \
+        jnz   10f;            \
+        call  stack_overflow; \
+10:
+#else
+#define STACK_OVERFLOW_TEST
+#endif
 
 #define nr_syscalls ((syscall_table_size)/4)
 
@@ -87,7 +101,102 @@
 #define resume_kernel		restore_all
 #endif
 
-#define SAVE_ALL \
+#ifdef CONFIG_X86_HIGH_ENTRY
+
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
+/*
+ * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu,
+ * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is
+ * left stale, so we must check whether to repeat the real stack calculation.
+ */
+#define repeat_if_esp_changed				\
+	xorl %esp, %ebp;				\
+	testl $0xffffe000, %ebp;			\
+	jnz 0b
+#else
+#define repeat_if_esp_changed
+#endif
+
+/* clobbers ebx, edx and ebp */
+
+#define __SWITCH_KERNELSPACE				\
+	cmpl $0xff000000, %esp;				\
+	jb 1f;						\
+							\
+	/*						\
+	 * switch pagetables and load the real stack,	\
+	 * keep the stack offset:			\
+	 */						\
+							\
+	movl $swapper_pg_dir-__PAGE_OFFSET, %edx;	\
+							\
+	/* GET_THREAD_INFO(%ebp) intermixed */		\
+0:							\
+	movl %esp, %ebp;				\
+	movl %esp, %ebx;				\
+	andl $0xffffe000, %ebp;				\
+	andl $0x00001fff, %ebx;				\
+	orl TI_real_stack(%ebp), %ebx;			\
+	repeat_if_esp_changed;				\
+							\
+	movl %edx, %cr3;				\
+	movl %ebx, %esp;				\
+1:
+
+#endif
+
+
+#define __SWITCH_USERSPACE \
+	/* interrupted any of the user return paths? */	\
+							\
+	movl EIP(%esp), %eax;				\
+							\
+	cmpl $int80_ret_start_marker, %eax;		\
+	jb 33f; /* nope - continue with sysexit check */\
+	cmpl $int80_ret_end_marker, %eax;		\
+	jb 22f; /* yes - switch to virtual stack */	\
+33:							\
+	cmpl $sysexit_ret_start_marker, %eax;		\
+	jb 44f; /* nope - continue with user check */	\
+	cmpl $sysexit_ret_end_marker, %eax;		\
+	jb 22f; /* yes - switch to virtual stack */	\
+	/* return to userspace? */			\
+44:							\
+	movl EFLAGS(%esp),%ecx;				\
+	movb CS(%esp),%cl;				\
+	testl $(VM_MASK | 3),%ecx;			\
+	jz 2f;						\
+22:							\
+	/*						\
+	 * switch to the virtual stack, then switch to	\
+	 * the userspace pagetables.			\
+	 */						\
+							\
+	GET_THREAD_INFO(%ebp);				\
+	movl TI_virtual_stack(%ebp), %edx;		\
+	movl TI_user_pgd(%ebp), %ecx;			\
+							\
+	movl %esp, %ebx;				\
+	andl $0x1fff, %ebx;				\
+	orl %ebx, %edx;					\
+int80_ret_start_marker:					\
+	movl %edx, %esp; 				\
+	movl %ecx, %cr3;				\
+							\
+	__RESTORE_ALL;					\
+int80_ret_end_marker:					\
+2:
+
+#else /* !CONFIG_X86_HIGH_ENTRY */
+
+#define __SWITCH_KERNELSPACE
+#define __SWITCH_USERSPACE
+
+#endif
+
+#define __SAVE_ALL \
 	cld; \
 	pushl %es; \
 	pushl %ds; \
@@ -102,7 +211,7 @@
 	movl %edx, %ds; \
 	movl %edx, %es;
 
-#define RESTORE_INT_REGS \
+#define __RESTORE_INT_REGS \
 	popl %ebx;	\
 	popl %ecx;	\
 	popl %edx;	\
@@ -111,29 +220,28 @@
 	popl %ebp;	\
 	popl %eax
 
-#define RESTORE_REGS	\
-	RESTORE_INT_REGS; \
-1:	popl %ds;	\
-2:	popl %es;	\
+#define __RESTORE_REGS	\
+	__RESTORE_INT_REGS; \
+111:	popl %ds;	\
+222:	popl %es;	\
 .section .fixup,"ax";	\
-3:	movl $0,(%esp);	\
-	jmp 1b;		\
-4:	movl $0,(%esp);	\
-	jmp 2b;		\
+444:	movl $0,(%esp);	\
+	jmp 111b;	\
+555:	movl $0,(%esp);	\
+	jmp 222b;	\
 .previous;		\
 .section __ex_table,"a";\
 	.align 4;	\
-	.long 1b,3b;	\
-	.long 2b,4b;	\
+	.long 111b,444b;\
+	.long 222b,555b;\
 .previous
 
-
-#define RESTORE_ALL	\
-	RESTORE_REGS	\
+#define __RESTORE_ALL	\
+	__RESTORE_REGS	\
 	addl $4, %esp;	\
-1:	iret;		\
+333:	iret;		\
 .section .fixup,"ax";   \
-2:	sti;		\
+666:	sti;		\
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
 	movl %edx, %es; \
@@ -142,10 +250,19 @@
 .previous;		\
 .section __ex_table,"a";\
 	.align 4;	\
-	.long 1b,2b;	\
+	.long 333b,666b;\
 .previous
 
+#define SAVE_ALL \
+	__SAVE_ALL;					\
+	__SWITCH_KERNELSPACE;				\
+        STACK_OVERFLOW_TEST;
+
+#define RESTORE_ALL					\
+	__SWITCH_USERSPACE;				\
+	__RESTORE_ALL;
 
+.section .entry.text,"ax"
 
 ENTRY(lcall7)
 	pushfl			# We get a different stack layout with call
@@ -163,7 +280,7 @@
 	movl %edx,EIP(%ebp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%ebp)	#
 	andl $-8192, %ebp	# GET_THREAD_INFO
-	movl TI_EXEC_DOMAIN(%ebp), %edx	# Get the execution domain
+	movl TI_exec_domain(%ebp), %edx	# Get the execution domain
 	call *4(%edx)		# Call the lcall7 handler for the domain
 	addl $4, %esp
 	popl %eax
@@ -208,7 +325,7 @@
  	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
 					# int/exception return?
 	jne work_pending
@@ -216,18 +333,18 @@
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	cmpl $0,TI_PRE_COUNT(%ebp)	# non-zero preempt_count ?
+	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
 	jnz restore_all
 need_resched:
-	movl TI_FLAGS(%ebp), %ecx	# need_resched set ?
+	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
 	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
 	jz restore_all
-	movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp)
+	movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp)
 	sti
 	call schedule
-	movl $0,TI_PRE_COUNT(%ebp)
+	movl $0,TI_preempt_count(%ebp)
 	cli
 	jmp need_resched
 #endif
@@ -246,37 +363,50 @@
 	pushl $(__USER_CS)
 	pushl $SYSENTER_RETURN
 
-/*
- * Load the potential sixth argument from user stack.
- * Careful about security.
- */
-	cmpl $__PAGE_OFFSET-3,%ebp
-	jae syscall_fault
-1:	movl (%ebp),%ebp
-.section __ex_table,"a"
-	.align 4
-	.long 1b,syscall_fault
-.previous
-
 	pushl %eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 
-	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
+	testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
 	jnz syscall_trace_entry
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
 	cli
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
 	jne syscall_exit_work
+
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+
+	GET_THREAD_INFO(%ebp)
+	movl TI_virtual_stack(%ebp), %edx
+	movl TI_user_pgd(%ebp), %ecx
+	movl %esp, %ebx
+	andl $0x1fff, %ebx
+	orl %ebx, %edx
+sysexit_ret_start_marker:
+	movl %edx, %esp
+	movl %ecx, %cr3
+#endif
+	/*
+	 * only ebx is not restored by the userspace sysenter vsyscall
+	 * code, it assumes it to be callee-saved.
+	 */
+	movl EBX(%esp), %ebx
+
 /* if something modifies registers it must also disable sysexit */
+
 	movl EIP(%esp), %edx
 	movl OLDESP(%esp), %ecx
+
 	sti
 	sysexit
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+sysexit_ret_end_marker:
+	nop
+#endif
 
 
 	# system call handler stub
@@ -287,7 +417,7 @@
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 					# system call tracing in operation
-	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)
+	testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp)
 	jnz syscall_trace_entry
 syscall_call:
 	call *sys_call_table(,%eax,4)
@@ -296,10 +426,23 @@
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
 restore_all:
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
+	movb CS(%esp), %al
+	testl $(VM_MASK | 3), %eax
+	jz resume_kernelX		# returning to kernel or vm86-space
+
+	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
+	jz resume_kernelX
+
+        int $3
+
+resume_kernelX:
+#endif
 	RESTORE_ALL
 
 	# perform work that needs to be done immediately before resumption
@@ -312,7 +455,7 @@
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
-	movl TI_FLAGS(%ebp), %ecx
+	movl TI_flags(%ebp), %ecx
 	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done other
 					# than syscall tracing?
 	jz restore_all
@@ -327,6 +470,22 @@
 					# vm86-space
 	xorl %edx, %edx
 	call do_notify_resume
+
+#if CONFIG_X86_HIGH_ENTRY
+	/*
+	 * Reload db7 if necessary:
+	 */
+	movl TI_flags(%ebp), %ecx
+	testb $_TIF_DB7, %cl
+	jnz work_db7
+
+	jmp restore_all
+
+work_db7:
+	movl TI_task(%ebp), %edx;
+	movl task_thread_db7(%edx), %edx;
+	movl %edx, %db7;
+#endif
 	jmp restore_all
 
 	ALIGN
@@ -382,7 +541,7 @@
  */
 .data
 ENTRY(interrupt)
-.text
+.previous
 
 vector=0
 ENTRY(irq_entries_start)
@@ -392,7 +551,7 @@
 	jmp common_interrupt
 .data
 	.long 1b
-.text
+.previous
 vector=vector+1
 .endr
 
@@ -433,12 +592,17 @@
 	movl ES(%esp), %edi		# get the function address
 	movl %eax, ORIG_EAX(%esp)
 	movl %ecx, ES(%esp)
-	movl %esp, %edx
 	pushl %esi			# push the error code
-	pushl %edx			# push the pt_regs pointer
 	movl $(__USER_DS), %edx
 	movl %edx, %ds
 	movl %edx, %es
+
+/* clobbers edx, ebx and ebp */
+	__SWITCH_KERNELSPACE
+
+	leal 4(%esp), %edx		# prepare pt_regs
+	pushl %edx			# push pt_regs
+
 	call *%edi
 	addl $8, %esp
 	jmp ret_from_exception
@@ -515,8 +679,8 @@
 	/* Do not access memory above the end of our stack page,
 	 * it might not exist.
 	 */
-	andl $0x1fff,%eax
-	cmpl $0x1fec,%eax
+	andl $(THREAD_SIZE-1),%eax
+	cmpl $(THREAD_SIZE-20),%eax
 	popl %eax
 	jae nmi_stack_correct
 	cmpl $sysenter_entry,12(%esp)
@@ -529,7 +693,7 @@
 	pushl %edx
 	call do_nmi
 	addl $8, %esp
-	RESTORE_ALL
+	jmp restore_all
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -606,6 +770,8 @@
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
 
+.previous
+
 .data
 ENTRY(sys_call_table)
 	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
--- diff/arch/i386/kernel/head.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/head.S	2004-02-18 09:03:57.000000000 +0000
@@ -16,6 +16,8 @@
 #include <asm/pgtable.h>
 #include <asm/desc.h>
 #include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/asm_offsets.h>
 
 #define OLD_CL_MAGIC_ADDR	0x90020
 #define OLD_CL_MAGIC		0xA33F
@@ -325,12 +327,12 @@
 	ret
 
 ENTRY(stack_start)
-	.long init_thread_union+8192
+	.long init_thread_union+THREAD_SIZE
 	.long __BOOT_DS
 
 /* This is the default interrupt "handler" :-) */
 int_msg:
-	.asciz "Unknown interrupt\n"
+	.asciz "Unknown interrupt or fault at EIP %p %p %p\n"
 	ALIGN
 ignore_int:
 	cld
@@ -342,9 +344,17 @@
 	movl $(__KERNEL_DS),%eax
 	movl %eax,%ds
 	movl %eax,%es
+	pushl 16(%esp)
+	pushl 24(%esp)
+	pushl 32(%esp)
+	pushl 40(%esp)
 	pushl $int_msg
 	call printk
 	popl %eax
+	popl %eax
+	popl %eax
+	popl %eax
+	popl %eax
 	popl %ds
 	popl %es
 	popl %edx
@@ -377,23 +387,27 @@
 	.fill NR_CPUS-1,8,0		# space for the other GDT descriptors
 
 /*
- * This is initialized to create an identity-mapping at 0-8M (for bootup
- * purposes) and another mapping of the 0-8M area at virtual address
+ * This is initialized to create an identity-mapping at 0-16M (for bootup
+ * purposes) and another mapping of the 0-16M area at virtual address
  * PAGE_OFFSET.
  */
 .org 0x1000
 ENTRY(swapper_pg_dir)
 	.long 0x00102007
 	.long 0x00103007
-	.fill BOOT_USER_PGD_PTRS-2,4,0
-	/* default: 766 entries */
+	.long 0x00104007
+	.long 0x00105007
+	.fill BOOT_USER_PGD_PTRS-4,4,0
+	/* default: 764 entries */
 	.long 0x00102007
 	.long 0x00103007
-	/* default: 254 entries */
-	.fill BOOT_KERNEL_PGD_PTRS-2,4,0
+	.long 0x00104007
+	.long 0x00105007
+	/* default: 252 entries */
+	.fill BOOT_KERNEL_PGD_PTRS-4,4,0
 
 /*
- * The page tables are initialized to only 8MB here - the final page
+ * The page tables are initialized to only 16MB here - the final page
  * tables are set up later depending on memory size.
  */
 .org 0x2000
@@ -402,15 +416,21 @@
 .org 0x3000
 ENTRY(pg1)
 
+.org 0x4000
+ENTRY(pg2)
+
+.org 0x5000
+ENTRY(pg3)
+
 /*
  * empty_zero_page must immediately follow the page tables ! (The
  * initialization loop counts until empty_zero_page)
  */
 
-.org 0x4000
+.org 0x6000
 ENTRY(empty_zero_page)
 
-.org 0x5000
+.org 0x7000
 
 /*
  * Real beginning of normal "text" segment
@@ -419,12 +439,12 @@
 ENTRY(_stext)
 
 /*
- * This starts the data section. Note that the above is all
- * in the text section because it has alignment requirements
- * that we cannot fulfill any other way.
+ * This starts the data section.
  */
 .data
 
+.align PAGE_SIZE_asm
+
 /*
  * The Global Descriptor Table contains 28 quadwords, per-CPU.
  */
@@ -439,7 +459,9 @@
 	.quad 0x00cf9a000000ffff	/* kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* kernel 4GB data at 0x00000000 */
 #endif
-	.align L1_CACHE_BYTES
+
+.align PAGE_SIZE_asm
+
 ENTRY(cpu_gdt_table)
 	.quad 0x0000000000000000	/* NULL descriptor */
 	.quad 0x0000000000000000	/* 0x0b reserved */
--- diff/arch/i386/kernel/i386_ksyms.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/i386_ksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -97,7 +97,6 @@
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
 /* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__udelay);
@@ -111,13 +110,17 @@
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
+#if !defined(CONFIG_X86_UACCESS_INDIRECT)
 EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__direct_strncpy_from_user);
 EXPORT_SYMBOL(clear_user);
 EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(__copy_from_user_ll);
 EXPORT_SYMBOL(__copy_to_user_ll);
 EXPORT_SYMBOL(strnlen_user);
+#else /* CONFIG_X86_UACCESS_INDIRECT */
+EXPORT_SYMBOL(direct_csum_partial_copy_generic);
+#endif
 
 EXPORT_SYMBOL(dma_alloc_coherent);
 EXPORT_SYMBOL(dma_free_coherent);
--- diff/arch/i386/kernel/i387.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/i387.c	2004-02-18 09:03:57.000000000 +0000
@@ -218,6 +218,7 @@
 static int convert_fxsr_to_user( struct _fpstate __user *buf,
 					struct i387_fxsave_struct *fxsave )
 {
+	struct _fpreg tmp[8]; /* 80 bytes scratch area */
 	unsigned long env[7];
 	struct _fpreg __user *to;
 	struct _fpxreg *from;
@@ -234,23 +235,25 @@
 	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
 		return 1;
 
-	to = &buf->_st[0];
+	to = tmp;
 	from = (struct _fpxreg *) &fxsave->st_space[0];
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
 		unsigned long *t = (unsigned long *)to;
 		unsigned long *f = (unsigned long *)from;
 
-		if (__put_user(*f, t) ||
-				__put_user(*(f + 1), t + 1) ||
-				__put_user(from->exponent, &to->exponent))
-			return 1;
+		*t = *f;
+		*(t + 1) = *(f+1);
+		to->exponent = from->exponent;
 	}
+	if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8])))
+		return 1;
 	return 0;
 }
 
 static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
 					  struct _fpstate __user *buf )
 {
+	struct _fpreg tmp[8]; /* 80 bytes scratch area */
 	unsigned long env[7];
 	struct _fpxreg *to;
 	struct _fpreg __user *from;
@@ -258,6 +261,8 @@
 
 	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
 		return 1;
+	if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8])))
+		return 1;
 
 	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
 	fxsave->swd = (unsigned short)(env[1] & 0xffff);
@@ -269,15 +274,14 @@
 	fxsave->fos = env[6];
 
 	to = (struct _fpxreg *) &fxsave->st_space[0];
-	from = &buf->_st[0];
+	from = tmp;
 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
 		unsigned long *t = (unsigned long *)to;
 		unsigned long *f = (unsigned long *)from;
 
-		if (__get_user(*t, f) ||
-				__get_user(*(t + 1), f + 1) ||
-				__get_user(to->exponent, &from->exponent))
-			return 1;
+		*t = *f;
+		*(t + 1) = *(f + 1);
+		to->exponent = from->exponent;
 	}
 	return 0;
 }
--- diff/arch/i386/kernel/init_task.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/i386/kernel/init_task.c	2004-02-18 09:03:57.000000000 +0000
@@ -26,7 +26,7 @@
  */
 union thread_union init_thread_union 
 	__attribute__((__section__(".data.init_task"))) =
-		{ INIT_THREAD_INFO(init_task) };
+		{ INIT_THREAD_INFO(init_task, init_thread_union) };
 
 /*
  * Initial task structure.
@@ -44,5 +44,5 @@
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
+struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS };
 
--- diff/arch/i386/kernel/io_apic.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/kernel/io_apic.c	2004-02-18 09:03:57.000000000 +0000
@@ -280,7 +280,7 @@
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-#if defined(CONFIG_SMP)
+#if defined(CONFIG_IRQBALANCE)
 # include <asm/processor.h>	/* kernel_thread() */
 # include <linux/kernel_stat.h>	/* kstat */
 # include <linux/slab.h>		/* kmalloc() */
@@ -317,8 +317,7 @@
 
 #define IRQ_ALLOWED(cpu, allowed_mask)	cpu_isset(cpu, allowed_mask)
 
-#define CPU_TO_PACKAGEINDEX(i) \
-		((physical_balance && i > cpu_sibling_map[i]) ? cpu_sibling_map[i] : i)
+#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i]))
 
 #define MAX_BALANCED_IRQ_INTERVAL	(5*HZ)
 #define MIN_BALANCED_IRQ_INTERVAL	(HZ/2)
@@ -401,6 +400,7 @@
 	unsigned long max_cpu_irq = 0, min_cpu_irq = (~0);
 	unsigned long move_this_load = 0;
 	int max_loaded = 0, min_loaded = 0;
+	int load;
 	unsigned long useful_load_threshold = balanced_irq_interval + 10;
 	int selected_irq;
 	int tmp_loaded, first_attempt = 1;
@@ -452,7 +452,7 @@
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_online(i))
 			continue;
-		if (physical_balance && i > cpu_sibling_map[i])
+		if (i != CPU_TO_PACKAGEINDEX(i))
 			continue;
 		if (min_cpu_irq > CPU_IRQ(i)) {
 			min_cpu_irq = CPU_IRQ(i);
@@ -471,7 +471,7 @@
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_online(i))
 			continue;
-		if (physical_balance && i > cpu_sibling_map[i])
+		if (i != CPU_TO_PACKAGEINDEX(i))
 			continue;
 		if (max_cpu_irq <= CPU_IRQ(i)) 
 			continue;
@@ -551,9 +551,14 @@
 	 * We seek the least loaded sibling by making the comparison
 	 * (A+B)/2 vs B
 	 */
-	if (physical_balance && (CPU_IRQ(min_loaded) >> 1) >
-					CPU_IRQ(cpu_sibling_map[min_loaded]))
-		min_loaded = cpu_sibling_map[min_loaded];
+	load = CPU_IRQ(min_loaded) >> 1;
+	for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) {
+		if (load > CPU_IRQ(j)) {
+			/* This won't change cpu_sibling_map[min_loaded] */
+			load = CPU_IRQ(j);
+			min_loaded = j;
+		}
+	}
 
 	cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]);
 	target_cpu_mask = cpumask_of_cpu(min_loaded);
@@ -689,9 +694,11 @@
 
 __initcall(balanced_irq_init);
 
-#else /* !SMP */
+#else /* !CONFIG_IRQBALANCE */
 static inline void move_irq(int irq) { }
+#endif /* CONFIG_IRQBALANCE */
 
+#ifndef CONFIG_SMP
 void send_IPI_self(int vector)
 {
 	unsigned int cfg;
@@ -706,7 +713,7 @@
 	 */
 	apic_write_around(APIC_ICR, cfg);
 }
-#endif /* defined(CONFIG_SMP) */
+#endif /* !CONFIG_SMP */
 
 
 /*
@@ -2150,6 +2157,10 @@
 {
 	int pin1, pin2;
 	int vector;
+	unsigned int ver;
+
+	ver = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(ver);
 
 	/*
 	 * get/set the timer IRQ vector:
@@ -2163,11 +2174,17 @@
 	 * mode for the 8259A whenever interrupts are routed
 	 * through I/O APICs.  Also IRQ0 has to be enabled in
 	 * the 8259A which implies the virtual wire has to be
-	 * disabled in the local APIC.
+	 * disabled in the local APIC.  Finally timer interrupts
+	 * need to be acknowledged manually in the 8259A for
+	 * do_slow_timeoffset() and for the i82489DX when using
+	 * the NMI watchdog.
 	 */
 	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 	init_8259A(1);
-	timer_ack = 1;
+	if (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver))
+		timer_ack = 1;
+	else
+		timer_ack = !cpu_has_tsc;
 	enable_8259A_irq(0);
 
 	pin1 = find_isa_irq_pin(0, mp_INT);
@@ -2185,7 +2202,8 @@
 				disable_8259A_irq(0);
 				setup_nmi();
 				enable_8259A_irq(0);
-				check_nmi_watchdog();
+				if (check_nmi_watchdog() < 0);
+					timer_ack = !cpu_has_tsc;
 			}
 			return;
 		}
@@ -2208,7 +2226,8 @@
 				add_pin_to_irq(0, 0, pin2);
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
-				check_nmi_watchdog();
+				if (check_nmi_watchdog() < 0);
+					timer_ack = !cpu_has_tsc;
 			}
 			return;
 		}
--- diff/arch/i386/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -435,7 +435,7 @@
 		long esp;
 
 		__asm__ __volatile__("andl %%esp,%0" :
-					"=r" (esp) : "0" (8191));
+					"=r" (esp) : "0" (THREAD_SIZE - 1));
 		if (unlikely(esp < (sizeof(struct thread_info) + 1024))) {
 			printk("do_IRQ: stack overflow: %ld\n",
 				esp - sizeof(struct thread_info));
@@ -508,6 +508,8 @@
 
 	irq_exit();
 
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
@@ -927,7 +929,7 @@
 static int irq_affinity_read_proc(char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -968,7 +970,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/i386/kernel/ldt.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/ldt.c	2004-02-18 09:03:57.000000000 +0000
@@ -2,7 +2,7 @@
  * linux/kernel/ldt.c
  *
  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 1999, 2003 Ingo Molnar <mingo@redhat.com>
  */
 
 #include <linux/errno.h>
@@ -18,6 +18,8 @@
 #include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
+#include <linux/highmem.h>
+#include <asm/atomic_kmap.h>
 
 #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
 static void flush_ldt(void *null)
@@ -29,34 +31,31 @@
 
 static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 {
-	void *oldldt;
-	void *newldt;
-	int oldsize;
+	int oldsize, newsize, i;
 
 	if (mincount <= pc->size)
 		return 0;
+	/*
+	 * LDT got larger - reallocate if necessary.
+	 */
 	oldsize = pc->size;
 	mincount = (mincount+511)&(~511);
-	if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
-		newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
-	else
-		newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
-
-	if (!newldt)
-		return -ENOMEM;
-
-	if (oldsize)
-		memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
-	oldldt = pc->ldt;
-	memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
-	pc->ldt = newldt;
-	wmb();
+	newsize = mincount*LDT_ENTRY_SIZE;
+	for (i = 0; i < newsize; i += PAGE_SIZE) {
+		int nr = i/PAGE_SIZE;
+		BUG_ON(i >= 64*1024);
+		if (!pc->ldt_pages[nr]) {
+			pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER);
+			if (!pc->ldt_pages[nr])
+				return -ENOMEM;
+			clear_highpage(pc->ldt_pages[nr]);
+		}
+	}
 	pc->size = mincount;
-	wmb();
-
 	if (reload) {
 #ifdef CONFIG_SMP
 		cpumask_t mask;
+
 		preempt_disable();
 		load_LDT(pc);
 		mask = cpumask_of_cpu(smp_processor_id());
@@ -67,21 +66,20 @@
 		load_LDT(pc);
 #endif
 	}
-	if (oldsize) {
-		if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
-			vfree(oldldt);
-		else
-			kfree(oldldt);
-	}
 	return 0;
 }
 
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
-	int err = alloc_ldt(new, old->size, 0);
-	if (err < 0)
+	int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE;
+
+	err = alloc_ldt(new, size, 0);
+	if (err < 0) {
+		new->size = 0;
 		return err;
-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
+	}
+	for (i = 0; i < nr_pages; i++)
+		copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0);
 	return 0;
 }
 
@@ -96,6 +94,7 @@
 
 	init_MUTEX(&mm->context.sem);
 	mm->context.size = 0;
+	memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES);
 	old_mm = current->mm;
 	if (old_mm && old_mm->context.size > 0) {
 		down(&old_mm->context.sem);
@@ -107,23 +106,21 @@
 
 /*
  * No need to lock the MM as we are the last user
+ * Do not touch the ldt register, we are already
+ * in the next thread.
  */
 void destroy_context(struct mm_struct *mm)
 {
-	if (mm->context.size) {
-		if (mm == current->active_mm)
-			clear_LDT();
-		if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
-			vfree(mm->context.ldt);
-		else
-			kfree(mm->context.ldt);
-		mm->context.size = 0;
-	}
+	int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
+
+	for (i = 0; i < nr_pages; i++)
+		__free_page(mm->context.ldt_pages[i]);
+	mm->context.size = 0;
 }
 
 static int read_ldt(void __user * ptr, unsigned long bytecount)
 {
-	int err;
+	int err, i;
 	unsigned long size;
 	struct mm_struct * mm = current->mm;
 
@@ -138,8 +135,25 @@
 		size = bytecount;
 
 	err = 0;
-	if (copy_to_user(ptr, mm->context.ldt, size))
-		err = -EFAULT;
+	/*
+	 * This is necessary just in case we got here straight from a
+	 * context-switch where the ptes were set but no tlb flush
+	 * was done yet. We rather avoid doing a TLB flush in the
+	 * context-switch path and do it here instead.
+	 */
+	__flush_tlb_global();
+
+	for (i = 0; i < size; i += PAGE_SIZE) {
+		int nr = i / PAGE_SIZE, bytes;
+		char *kaddr = kmap(mm->context.ldt_pages[nr]);
+
+		bytes = size - i;
+		if (bytes > PAGE_SIZE)
+			bytes = PAGE_SIZE;
+		if (copy_to_user(ptr + i, kaddr, size - i))
+			err = -EFAULT;
+		kunmap(mm->context.ldt_pages[nr]);
+	}
 	up(&mm->context.sem);
 	if (err < 0)
 		return err;
@@ -158,7 +172,7 @@
 
 	err = 0;
 	address = &default_ldt[0];
-	size = 5*sizeof(struct desc_struct);
+	size = 5*LDT_ENTRY_SIZE;
 	if (size > bytecount)
 		size = bytecount;
 
@@ -200,7 +214,15 @@
 			goto out_unlock;
 	}
 
-	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
+	/*
+	 * No rescheduling allowed from this point to the install.
+	 *
+	 * We do a TLB flush for the same reason as in the read_ldt() path.
+	 */
+	preempt_disable();
+	__flush_tlb_global();
+	lp = (__u32 *) ((ldt_info.entry_number << 3) +
+			(char *) __kmap_atomic_vaddr(KM_LDT_PAGE0));
 
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
@@ -221,6 +243,7 @@
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
 	error = 0;
+	preempt_enable();
 
 out_unlock:
 	up(&mm->context.sem);
@@ -248,3 +271,26 @@
 	}
 	return ret;
 }
+
+/*
+ * load one particular LDT into the current CPU
+ */
+void load_LDT_nolock(mm_context_t *pc, int cpu)
+{
+	struct page **pages = pc->ldt_pages;
+	int count = pc->size;
+	int nr_pages, i;
+
+	if (likely(!count)) {
+		pages = &default_ldt_page;
+		count = 5;
+	}
+       	nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE;
+
+	for (i = 0; i < nr_pages; i++) {
+		__kunmap_atomic_type(KM_LDT_PAGE0 - i);
+		__kmap_atomic(pages[i], KM_LDT_PAGE0 - i);
+	}
+	set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count);
+	load_LDT_desc();
+}
--- diff/arch/i386/kernel/microcode.c	2003-10-27 09:20:43.000000000 +0000
+++ source/arch/i386/kernel/microcode.c	2004-02-18 09:03:57.000000000 +0000
@@ -507,3 +507,4 @@
 
 module_init(microcode_init)
 module_exit(microcode_exit)
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
--- diff/arch/i386/kernel/mpparse.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/mpparse.c	2004-02-18 09:03:57.000000000 +0000
@@ -668,7 +668,7 @@
 		 * Read the physical hardware table.  Anything here will
 		 * override the defaults.
 		 */
-		if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+		if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) {
 			smp_found_config = 0;
 			printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
 			printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
--- diff/arch/i386/kernel/nmi.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/nmi.c	2004-02-18 09:03:57.000000000 +0000
@@ -31,7 +31,16 @@
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
 
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#ifdef CONFIG_SMP
+unsigned int nmi_watchdog = NMI_IO_APIC;
+#else
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
+#endif
+#else
 unsigned int nmi_watchdog = NMI_NONE;
+#endif
 static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 extern void show_registers(struct pt_regs *regs);
@@ -42,7 +51,7 @@
  *     be enabled
  * -1: the lapic NMI watchdog is disabled, but can be enabled
  */
-static int nmi_active;
+int nmi_active;
 
 #define K7_EVNTSEL_ENABLE	(1 << 22)
 #define K7_EVNTSEL_INT		(1 << 20)
@@ -408,6 +417,9 @@
 	for (i = 0; i < NR_CPUS; i++)
 		alert_counter[i] = 0;
 }
+#ifdef CONFIG_KGDB
+int tune_watchdog = 5*HZ;
+#endif
 
 void nmi_watchdog_tick (struct pt_regs * regs)
 {
@@ -421,12 +433,24 @@
 
 	sum = irq_stat[cpu].apic_timer_irqs;
 
+#ifdef CONFIG_KGDB
+ 	if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) {
+
+#else
 	if (last_irq_sums[cpu] == sum) {
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
+#ifdef CONFIG_KGDB
+                if (alert_counter[cpu] == tune_watchdog) {
+                        kgdb_handle_exception(2, SIGPWR, 0, regs);
+                        last_irq_sums[cpu] = sum;
+                        alert_counter[cpu] = 0;
+                }
+#endif
 		if (alert_counter[cpu] == 5*nmi_hz) {
 			spin_lock(&nmi_print_lock);
 			/*
@@ -462,6 +486,7 @@
 	}
 }
 
+EXPORT_SYMBOL(nmi_active);
 EXPORT_SYMBOL(nmi_watchdog);
 EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
 EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
--- diff/arch/i386/kernel/process.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/process.c	2004-02-18 09:03:57.000000000 +0000
@@ -47,6 +47,7 @@
 #include <asm/i387.h>
 #include <asm/irq.h>
 #include <asm/desc.h>
+#include <asm/atomic_kmap.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -304,6 +305,9 @@
 	struct task_struct *tsk = current;
 
 	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+#ifdef CONFIG_X86_HIGH_ENTRY
+	clear_thread_flag(TIF_DB7);
+#endif
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
 	/*
 	 * Forget coprocessor state..
@@ -317,9 +321,8 @@
 	if (dead_task->mm) {
 		// temporary debugging check
 		if (dead_task->mm->context.size) {
-			printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+			printk("WARNING: dead process %8s still has LDT? <%d>\n",
 					dead_task->comm,
-					dead_task->mm->context.ldt,
 					dead_task->mm->context.size);
 			BUG();
 		}
@@ -354,7 +357,17 @@
 	p->thread.esp = (unsigned long) childregs;
 	p->thread.esp0 = (unsigned long) (childregs+1);
 
+	/*
+	 * get the two stack pages, for the virtual stack.
+	 *
+	 * IMPORTANT: this code relies on the fact that the task
+	 * structure is an 8K aligned piece of physical memory.
+	 */
+	p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info);
+	p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE);
+
 	p->thread.eip = (unsigned long) ret_from_fork;
+	p->thread_info->real_stack = p->thread_info;
 
 	savesegment(fs,p->thread.fs);
 	savesegment(gs,p->thread.gs);
@@ -506,10 +519,41 @@
 
 	__unlazy_fpu(prev_p);
 
+#ifdef CONFIG_X86_HIGH_ENTRY
+	/*
+	 * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is
+	 * needed because otherwise NMIs could interrupt the
+	 * user-return code with a virtual stack and stale TLBs.)
+	 */
+	__kunmap_atomic_type(KM_VSTACK0);
+	__kunmap_atomic_type(KM_VSTACK1);
+	__kmap_atomic(next->stack_page0, KM_VSTACK0);
+	__kmap_atomic(next->stack_page1, KM_VSTACK1);
+
+	/*
+	 * NOTE: here we rely on the task being the stack as well
+	 */
+	next_p->thread_info->virtual_stack =
+			(void *)__kmap_atomic_vaddr(KM_VSTACK0);
+
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
+	/*
+	 * If next was preempted on entry from userspace to kernel,
+	 * and now it's on a different cpu, we need to adjust %esp.
+	 * This assumes that entry.S does not copy %esp while on the
+	 * virtual stack (with interrupts enabled): which is so,
+	 * except within __SWITCH_KERNELSPACE itself.
+	 */
+	if (unlikely(next->esp >= TASK_SIZE)) {
+		next->esp &= THREAD_SIZE - 1;
+		next->esp |= (unsigned long) next_p->thread_info->virtual_stack;
+	}
+#endif
+#endif
 	/*
 	 * Reload esp0, LDT and the page table pointer:
 	 */
-	load_esp0(tss, next);
+	load_virtual_esp0(tss, next_p);
 
 	/*
 	 * Load the per-thread Thread-Local Storage descriptor.
@@ -637,6 +681,8 @@
 extern void scheduling_functions_end_here(void);
 #define first_sched	((unsigned long) scheduling_functions_start_here)
 #define last_sched	((unsigned long) scheduling_functions_end_here)
+#define top_esp                (THREAD_SIZE - sizeof(unsigned long))
+#define top_ebp                (THREAD_SIZE - 2*sizeof(unsigned long))
 
 unsigned long get_wchan(struct task_struct *p)
 {
@@ -647,12 +693,12 @@
 		return 0;
 	stack_page = (unsigned long)p->thread_info;
 	esp = p->thread.esp;
-	if (!stack_page || esp < stack_page || esp > 8188+stack_page)
+	if (!stack_page || esp < stack_page || esp > top_esp+stack_page)
 		return 0;
 	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
 	ebp = *(unsigned long *) esp;
 	do {
-		if (ebp < stack_page || ebp > 8184+stack_page)
+		if (ebp < stack_page || ebp > top_ebp+stack_page)
 			return 0;
 		eip = *(unsigned long *) (ebp+4);
 		if (eip < first_sched || eip >= last_sched)
--- diff/arch/i386/kernel/reboot.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/reboot.c	2004-02-18 09:03:57.000000000 +0000
@@ -155,12 +155,11 @@
 	CMOS_WRITE(0x00, 0x8f);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	/* Remap the kernel at virtual address zero, as well as offset zero
-	   from the kernel segment.  This assumes the kernel segment starts at
-	   virtual address PAGE_OFFSET. */
-
-	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
-		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
+	/*
+	 * Remap the first 16 MB of RAM (which includes the kernel image)
+	 * at virtual address zero:
+	 */
+	setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024);
 
 	/*
 	 * Use `swapper_pg_dir' as our page directory.
--- diff/arch/i386/kernel/setup.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/setup.c	2004-02-18 09:03:57.000000000 +0000
@@ -1118,6 +1118,19 @@
 #endif
 	paging_init();
 
+#ifdef CONFIG_EARLY_PRINTK
+	{
+		char *s = strstr(*cmdline_p, "earlyprintk=");
+		if (s) {
+			extern void setup_early_printk(char *);
+
+			setup_early_printk(s);
+			printk("early console enabled\n");
+		}
+	}
+#endif
+
+
 	dmi_scan_machine();
 
 #ifdef CONFIG_X86_GENERICARCH
--- diff/arch/i386/kernel/signal.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/i386/kernel/signal.c	2004-02-18 09:03:57.000000000 +0000
@@ -128,28 +128,29 @@
  */
 
 static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
+restore_sigcontext(struct pt_regs *regs,
+		struct sigcontext __user *__sc, int *peax)
 {
-	unsigned int err = 0;
+	struct sigcontext scratch; /* 88 bytes of scratch area */
 
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)		err |= __get_user(regs->x, &sc->x)
+	if (copy_from_user(&scratch, __sc, sizeof(scratch)))
+		return -EFAULT;
+
+#define COPY(x)		regs->x = scratch.x
 
 #define COPY_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  regs->x##seg = tmp; }
 
 #define COPY_SEG_STRICT(seg)						\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  regs->x##seg = tmp|3; }
 
 #define GET_SEG(seg)							\
-	{ unsigned short tmp;						\
-	  err |= __get_user(tmp, &sc->seg);				\
+	{ unsigned short tmp = scratch.seg;				\
 	  loadsegment(seg,tmp); }
 
 	GET_SEG(gs);
@@ -168,27 +169,23 @@
 	COPY_SEG_STRICT(ss);
 	
 	{
-		unsigned int tmpflags;
-		err |= __get_user(tmpflags, &sc->eflags);
+		unsigned int tmpflags = scratch.eflags;
 		regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
 		regs->orig_eax = -1;		/* disable syscall checks */
 	}
 
 	{
-		struct _fpstate __user * buf;
-		err |= __get_user(buf, &sc->fpstate);
+		struct _fpstate * buf = scratch.fpstate;
 		if (buf) {
 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
-			err |= restore_i387(buf);
+				return -EFAULT;
+			if (restore_i387(buf))
+				return -EFAULT;
 		}
 	}
 
-	err |= __get_user(*peax, &sc->eax);
-	return err;
-
-badframe:
-	return 1;
+	*peax = scratch.eax;
+	return 0;
 }
 
 asmlinkage int sys_sigreturn(unsigned long __unused)
@@ -266,46 +263,47 @@
  */
 
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate,
 		 struct pt_regs *regs, unsigned long mask)
 {
-	int tmp, err = 0;
+	struct sigcontext sc; /* 88 bytes of scratch area */
+	int tmp;
 
 	tmp = 0;
 	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->gs);
+	*(unsigned int *)&sc.gs = tmp;
 	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->fs);
-
-	err |= __put_user(regs->xes, (unsigned int *)&sc->es);
-	err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
-	err |= __put_user(regs->edi, &sc->edi);
-	err |= __put_user(regs->esi, &sc->esi);
-	err |= __put_user(regs->ebp, &sc->ebp);
-	err |= __put_user(regs->esp, &sc->esp);
-	err |= __put_user(regs->ebx, &sc->ebx);
-	err |= __put_user(regs->edx, &sc->edx);
-	err |= __put_user(regs->ecx, &sc->ecx);
-	err |= __put_user(regs->eax, &sc->eax);
-	err |= __put_user(current->thread.trap_no, &sc->trapno);
-	err |= __put_user(current->thread.error_code, &sc->err);
-	err |= __put_user(regs->eip, &sc->eip);
-	err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
-	err |= __put_user(regs->eflags, &sc->eflags);
-	err |= __put_user(regs->esp, &sc->esp_at_signal);
-	err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
+	*(unsigned int *)&sc.fs = tmp;
+	*(unsigned int *)&sc.es = regs->xes;
+	*(unsigned int *)&sc.ds = regs->xds;
+	sc.edi = regs->edi;
+	sc.esi = regs->esi;
+	sc.ebp = regs->ebp;
+	sc.esp = regs->esp;
+	sc.ebx = regs->ebx;
+	sc.edx = regs->edx;
+	sc.ecx = regs->ecx;
+	sc.eax = regs->eax;
+	sc.trapno = current->thread.trap_no;
+	sc.err = current->thread.error_code;
+	sc.eip = regs->eip;
+	*(unsigned int *)&sc.cs = regs->xcs;
+	sc.eflags = regs->eflags;
+	sc.esp_at_signal = regs->esp;
+	*(unsigned int *)&sc.ss = regs->xss;
 
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
-	  err = 1;
-	else
-	  err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+		return 1;
+	sc.fpstate = tmp ? fpstate : NULL;
 
 	/* non-iBCS2 extensions.. */
-	err |= __put_user(mask, &sc->oldmask);
-	err |= __put_user(current->thread.cr2, &sc->cr2);
+	sc.oldmask = mask;
+	sc.cr2 = current->thread.cr2;
 
-	return err;
+	if (copy_to_user(__sc, &sc, sizeof(sc)))
+		return 1;
+	return 0;
 }
 
 /*
@@ -443,7 +441,7 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->esp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
--- diff/arch/i386/kernel/smp.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/smp.c	2004-02-18 09:03:57.000000000 +0000
@@ -327,10 +327,12 @@
 		 
 	if (flush_mm == cpu_tlbstate[cpu].active_mm) {
 		if (cpu_tlbstate[cpu].state == TLBSTATE_OK) {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 			if (flush_va == FLUSH_ALL)
 				local_flush_tlb();
 			else
 				__flush_tlb_one(flush_va);
+#endif
 		} else
 			leave_mm(cpu);
 	}
@@ -396,21 +398,6 @@
 	spin_unlock(&tlbstate_lock);
 }
 	
-void flush_tlb_current_task(void)
-{
-	struct mm_struct *mm = current->mm;
-	cpumask_t cpu_mask;
-
-	preempt_disable();
-	cpu_mask = mm->cpu_vm_mask;
-	cpu_clear(smp_processor_id(), cpu_mask);
-
-	local_flush_tlb();
-	if (!cpus_empty(cpu_mask))
-		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-	preempt_enable();
-}
-
 void flush_tlb_mm (struct mm_struct * mm)
 {
 	cpumask_t cpu_mask;
@@ -442,7 +429,10 @@
 
 	if (current->active_mm == mm) {
 		if(current->mm)
-			__flush_tlb_one(va);
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
+			__flush_tlb_one(va)
+#endif
+				;
 		 else
 		 	leave_mm(smp_processor_id());
 	}
@@ -466,7 +456,17 @@
 {
 	on_each_cpu(do_flush_tlb_all, 0, 1, 1);
 }
-
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
--- diff/arch/i386/kernel/smpboot.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/i386/kernel/smpboot.c	2004-02-18 09:03:57.000000000 +0000
@@ -39,6 +39,7 @@
 #include <linux/kernel.h>
 
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
 #include <linux/irq.h>
@@ -934,7 +935,7 @@
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio;
 
-int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
 
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
@@ -948,10 +949,13 @@
 	printk("CPU%d: ", 0);
 	print_cpu_info(&cpu_data[0]);
 
+	boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
 	boot_cpu_logical_apicid = logical_smp_processor_id();
 
 	current_thread_info()->cpu = 0;
 	smp_tune_scheduling();
+	cpus_clear(cpu_sibling_map[0]);
+	cpu_set(0, cpu_sibling_map[0]);
 
 	/*
 	 * If we couldn't find an SMP configuration at boot time,
@@ -1008,8 +1012,6 @@
 	setup_local_APIC();
 	map_cpu_to_logical_apicid();
 
-	if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid)
-		BUG();
 
 	setup_portio_remap();
 
@@ -1080,32 +1082,34 @@
 	Dprintk("Boot done.\n");
 
 	/*
-	 * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so
-	 * that we can tell the sibling CPU efficiently.
+	 * construct cpu_sibling_map[], so that we can tell sibling CPUs
+	 * efficiently.
 	 */
-	if (cpu_has_ht && smp_num_siblings > 1) {
-		for (cpu = 0; cpu < NR_CPUS; cpu++)
-			cpu_sibling_map[cpu] = NO_PROC_ID;
-		
-		for (cpu = 0; cpu < NR_CPUS; cpu++) {
-			int 	i;
-			if (!cpu_isset(cpu, cpu_callout_map))
-				continue;
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		cpus_clear(cpu_sibling_map[cpu]);
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		int siblings = 0;
+		int i;
+		if (!cpu_isset(cpu, cpu_callout_map))
+			continue;
 
+		if (smp_num_siblings > 1) {
 			for (i = 0; i < NR_CPUS; i++) {
-				if (i == cpu || !cpu_isset(i, cpu_callout_map))
+				if (!cpu_isset(i, cpu_callout_map))
 					continue;
 				if (phys_proc_id[cpu] == phys_proc_id[i]) {
-					cpu_sibling_map[cpu] = i;
-					printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]);
-					break;
+					siblings++;
+					cpu_set(i, cpu_sibling_map[cpu]);
 				}
 			}
-			if (cpu_sibling_map[cpu] == NO_PROC_ID) {
-				smp_num_siblings = 1;
-				printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu);
-			}
+		} else {
+			siblings++;
+			cpu_set(cpu, cpu_sibling_map[cpu]);
 		}
+
+		if (siblings != smp_num_siblings)
+			printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
 	}
 
 	smpboot_setup_io_apic();
@@ -1119,6 +1123,207 @@
 		synchronize_tsc_bp();
 }
 
+#ifdef CONFIG_SCHED_SMT
+#ifdef CONFIG_NUMA
+static struct sched_group sched_group_cpus[NR_CPUS];
+static struct sched_group sched_group_phys[NR_CPUS];
+static struct sched_group sched_group_nodes[MAX_NUMNODES];
+static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+static DEFINE_PER_CPU(struct sched_domain, node_domains);
+__init void arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		int node = cpu_to_node(i);
+		cpumask_t nodemask = node_to_cpumask(node);
+
+		*cpu_domain = SD_SIBLING_INIT;
+		cpu_domain->span = cpu_sibling_map[i];
+
+		*phys_domain = SD_CPU_INIT;
+		phys_domain->span = nodemask;
+		phys_domain->flags |= SD_FLAG_IDLE;
+
+		*node_domain = SD_NODE_INIT;
+		node_domain->span = cpu_online_map;
+	}
+
+	/* Set up CPU (sibling) groups */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		int j;
+		first_cpu = last_cpu = NULL;
+
+		if (i != first_cpu(cpu_domain->span))
+			continue;
+
+		for_each_cpu_mask(j, cpu_domain->span) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpu->cpumask = CPU_MASK_NONE;
+			cpu_set(j, cpu->cpumask);
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		int j;
+		cpumask_t nodemask;
+		cpus_and(nodemask, node_to_cpumask(i), cpu_online_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		first_cpu = last_cpu = NULL;
+		/* Set up physical groups */
+		for_each_cpu_mask(j, nodemask) {
+			struct sched_domain *cpu_domain = cpu_sched_domain(j);
+			struct sched_group *cpu = &sched_group_phys[j];
+
+			if (j != first_cpu(cpu_domain->span))
+				continue;
+
+			cpu->cpumask = cpu_domain->span;
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	/* Set up nodes */
+	first_cpu = last_cpu = NULL;
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		struct sched_group *cpu = &sched_group_nodes[i];
+		cpumask_t nodemask;
+		cpus_and(nodemask, node_to_cpumask(i), cpu_online_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		cpu->cpumask = nodemask;
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+
+	mb();
+	for_each_cpu_mask(i, cpu_online_map) {
+		int node = cpu_to_node(i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_group *cpu_group = &sched_group_cpus[i];
+		struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)];
+		struct sched_group *node_group = &sched_group_nodes[node];
+
+		cpu_domain->parent = phys_domain;
+		phys_domain->parent = node_domain;
+
+		node_domain->groups = node_group;
+		phys_domain->groups = phys_group;
+		cpu_domain->groups = cpu_group;
+	}
+}
+#else /* CONFIG_NUMA */
+static struct sched_group sched_group_cpus[NR_CPUS];
+static struct sched_group sched_group_phys[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+__init void arch_init_sched_domains(void)
+{
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+
+		*cpu_domain = SD_SIBLING_INIT;
+		cpu_domain->span = cpu_sibling_map[i];
+
+		*phys_domain = SD_CPU_INIT;
+		phys_domain->span = cpu_online_map;
+		phys_domain->flags |= SD_FLAG_IDLE;
+	}
+
+	/* Set up CPU (sibling) groups */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		int j;
+		first_cpu = last_cpu = NULL;
+
+		if (i != first_cpu(cpu_domain->span))
+			continue;
+
+		for_each_cpu_mask(j, cpu_domain->span) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpus_clear(cpu->cpumask);
+			cpu_set(j, cpu->cpumask);
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+	}
+
+	first_cpu = last_cpu = NULL;
+	/* Set up physical groups */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_group *cpu = &sched_group_phys[i];
+
+		if (i != first_cpu(cpu_domain->span))
+			continue;
+
+		cpu->cpumask = cpu_domain->span;
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+	mb();
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
+		struct sched_group *cpu_group = &sched_group_cpus[i];
+		struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)];
+		cpu_domain->parent = phys_domain;
+		phys_domain->groups = phys_group;
+		cpu_domain->groups = cpu_group;
+	}
+}
+#endif /* CONFIG_NUMA */
+#endif /* CONFIG_SCHED_SMT */
+
 /* These are wrappers to interface to the new boot process.  Someone
    who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
 void __init smp_prepare_cpus(unsigned int max_cpus)
--- diff/arch/i386/kernel/sys_i386.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/i386/kernel/sys_i386.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -106,8 +107,6 @@
 }
 
 
-extern asmlinkage int sys_select(int, fd_set __user *, fd_set __user *, fd_set __user *, struct timeval __user *);
-
 struct sel_arg_struct {
 	unsigned long n;
 	fd_set __user *inp, *outp, *exp;
--- diff/arch/i386/kernel/sysenter.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/sysenter.c	2004-02-18 09:03:57.000000000 +0000
@@ -18,13 +18,18 @@
 #include <asm/msr.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
+#include <linux/highmem.h>
 
 extern asmlinkage void sysenter_entry(void);
 
 void enable_sep_cpu(void *info)
 {
 	int cpu = get_cpu();
+#ifdef CONFIG_X86_HIGH_ENTRY
+	struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
+#else
 	struct tss_struct *tss = init_tss + cpu;
+#endif
 
 	tss->ss1 = __KERNEL_CS;
 	tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
--- diff/arch/i386/kernel/timers/Makefile	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/i386/kernel/timers/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -6,3 +6,4 @@
 
 obj-$(CONFIG_X86_CYCLONE_TIMER)	+= timer_cyclone.o
 obj-$(CONFIG_HPET_TIMER)	+= timer_hpet.o
+obj-$(CONFIG_X86_PM_TIMER)	+= timer_pm.o
--- diff/arch/i386/kernel/timers/common.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/i386/kernel/timers/common.c	2004-02-18 09:03:57.000000000 +0000
@@ -137,3 +137,23 @@
 }
 #endif
 
+/* calculate cpu_khz */
+void __init init_cpu_khz(void)
+{
+	if (cpu_has_tsc) {
+		unsigned long tsc_quotient = calibrate_tsc();
+		if (tsc_quotient) {
+			/* report CPU clock rate in Hz.
+			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+			 * clock/second. Our precision is about 100 ppm.
+			 */
+			{	unsigned long eax=0, edx=1000;
+				__asm__("divl %2"
+		       		:"=a" (cpu_khz), "=d" (edx)
+        	       		:"r" (tsc_quotient),
+	                	"0" (eax), "1" (edx));
+				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
+			}
+		}
+	}
+}
--- diff/arch/i386/kernel/timers/timer.c	2003-09-17 12:28:01.000000000 +0100
+++ source/arch/i386/kernel/timers/timer.c	2004-02-18 09:03:57.000000000 +0000
@@ -19,6 +19,9 @@
 #ifdef CONFIG_HPET_TIMER
 	&timer_hpet,
 #endif
+#ifdef CONFIG_X86_PM_TIMER
+	&timer_pmtmr,
+#endif
 	&timer_tsc,
 	&timer_pit,
 	NULL,
--- diff/arch/i386/kernel/timers/timer_cyclone.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/timers/timer_cyclone.c	2004-02-18 09:03:57.000000000 +0000
@@ -212,26 +212,7 @@
 		}
 	}
 
-	/* init cpu_khz.
-	 * XXX - This should really be done elsewhere, 
-	 * 		and in a more generic fashion. -johnstul@us.ibm.com
-	 */
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
-			}
-		}
-	}
+	init_cpu_khz();
 
 	/* Everything looks good! */
 	return 0;
--- diff/arch/i386/kernel/traps.c	2003-10-27 09:20:36.000000000 +0000
+++ source/arch/i386/kernel/traps.c	2004-02-18 09:03:57.000000000 +0000
@@ -54,12 +54,8 @@
 
 #include "mach_traps.h"
 
-asmlinkage int system_call(void);
-asmlinkage void lcall7(void);
-asmlinkage void lcall27(void);
-
-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
-		{ 0, 0 }, { 0, 0 } };
+struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+struct page *default_ldt_page;
 
 /* Do we ignore FPU interrupts ? */
 char ignore_fpu_irq = 0;
@@ -91,6 +87,43 @@
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
+#ifdef CONFIG_KGDB
+extern void sysenter_entry(void);
+#include <asm/kgdb.h>
+#include <linux/init.h>
+extern void int3(void);
+extern void debug(void);
+void set_intr_gate(unsigned int n, void *addr);
+static void set_intr_usr_gate(unsigned int n, void *addr);
+/*
+ * Should be able to call this breakpoint() very early in
+ * bring up.  Just hard code the call where needed.
+ * The breakpoint() code is here because set_?_gate() functions
+ * are local (static) to trap.c.  They need be done only once,
+ * but it does not hurt to do them over.
+ */
+void breakpoint(void)
+{
+	init_entry_mappings();
+        set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+
+        BREAKPOINT;
+}
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (!user_mode(regs)  ) \
+	{								\
+		kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+		after;							\
+	} else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
+#endif
+
+
 static int kstack_depth_to_print = 24;
 
 void show_trace(struct task_struct *task, unsigned long * stack)
@@ -119,7 +152,7 @@
 	unsigned long esp = tsk->thread.esp;
 
 	/* User space on another CPU? */
-	if ((esp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1))
+	if ((esp ^ (unsigned long)tsk->thread_info) & ~(THREAD_SIZE - 1))
 		return;
 	show_trace(tsk, (unsigned long *)esp);
 }
@@ -175,8 +208,9 @@
 		ss = regs->xss & 0xffff;
 	}
 	print_modules();
-	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
-		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s VLI\nEFLAGS: %08lx\n",
+		smp_processor_id(), 0xffff & regs->xcs,
+		regs->eip, print_tainted(), regs->eflags);
 
 	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
@@ -192,23 +226,27 @@
 	 * time of the fault..
 	 */
 	if (in_kernel) {
+		u8 *eip;
 
 		printk("\nStack: ");
 		show_stack(NULL, (unsigned long*)esp);
 
 		printk("Code: ");
-		if(regs->eip < PAGE_OFFSET)
-			goto bad;
 
-		for(i=0;i<20;i++)
-		{
-			unsigned char c;
-			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
-bad:
+		eip = (u8 *)regs->eip - 43;
+		for (i = 0; i < 64; i++, eip++) {
+			unsigned char c = 0xff;
+
+			if ((user_mode(regs) && get_user(c, eip)) ||
+			    (!user_mode(regs) && __direct_get_user(c, eip))) {
+
 				printk(" Bad EIP value.");
 				break;
 			}
-			printk("%02x ", c);
+			if (eip == (u8 *)regs->eip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
 		}
 	}
 	printk("\n");
@@ -255,12 +293,36 @@
 void die(const char * str, struct pt_regs * regs, long err)
 {
 	static int die_counter;
+	int nl = 0;
 
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
 	handle_BUG(regs);
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+	nl = 1;
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP ");
+	nl = 1;
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	printk("DEBUG_PAGEALLOC");
+	nl = 1;
+#endif
+	if (nl)
+		printk("\n");
+#ifdef CONFIG_KGDB
+	/* This is about the only place we want to go to kgdb even if in
+	 * user mode.  But we must go in via a trap so within kgdb we will
+	 * always be in kernel mode.
+	 */
+	if (user_mode(regs))
+		BREAKPOINT;
+#endif
+ 	CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -330,6 +392,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -347,7 +410,9 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -394,8 +459,10 @@
 	return;
 
 gp_in_kernel:
-	if (!fixup_exception(regs))
+	if (!fixup_exception(regs)){
+ 		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
+	}
 }
 
 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
@@ -534,10 +601,18 @@
 	if (regs->eflags & X86_EFLAGS_IF)
 		local_irq_enable();
 
-	/* Mask out spurious debug traps due to lazy DR7 setting */
+	/*
+	 * Mask out spurious debug traps due to lazy DR7 setting or
+	 * due to 4G/4G kernel mode:
+	 */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7])
 			goto clear_dr7;
+		if (!user_mode(regs)) {
+			// restore upon return-to-userspace:
+			set_thread_flag(TIF_DB7);
+			goto clear_dr7;
+		}
 	}
 
 	if (regs->eflags & VM_MASK)
@@ -557,8 +632,18 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifdef CONFIG_KGDB
+		/*
+		 * I think this is the only "real" case of a TF in the kernel
+		 * that really belongs to user space.  Others are
+		 * "Ours all ours!"
+		 */
+		if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry))
+			goto clear_TF_reenable;
+#else
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -570,6 +655,17 @@
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
+#ifdef CONFIG_KGDB
+        /*
+	 * If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely ALSO skip the signal delivery
+         */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+        /* if not kernel, allow ints but only if they were on */
+       if ( regs->eflags & 0x200) local_irq_enable();
+#endif
 	/* If this is a kernel mode trap, save the user PC on entry to 
 	 * the kernel, that's what the debugger can make sense of.
 	 */
@@ -584,6 +680,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
@@ -779,19 +876,53 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
-#ifdef CONFIG_X86_F00F_BUG
-void __init trap_init_f00f_bug(void)
+void __init trap_init_virtual_IDT(void)
 {
-	__set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
-
 	/*
-	 * Update the IDT descriptor and reload the IDT so that
-	 * it uses the read-only mapped virtual address.
+	 * "idt" is magic - it overlaps the idt_descr
+	 * variable so that updating idt will automatically
+	 * update the idt descriptor..
 	 */
-	idt_descr.address = fix_to_virt(FIX_F00F_IDT);
+	__set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+	idt_descr.address = __fix_to_virt(FIX_IDT);
+
 	__asm__ __volatile__("lidt %0" : : "m" (idt_descr));
 }
+
+void __init trap_init_virtual_GDT(void)
+{
+	int cpu = smp_processor_id();
+	struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu;
+	struct Xgt_desc_struct tmp_desc = {0, 0};
+	struct tss_struct * t;
+
+	__asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory");
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+	if (!cpu) {
+		__set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL);
+		__set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL);
+		__set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL);
+	}
+
+	gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu;
+#else
+	gdt_desc->address = (unsigned long)cpu_gdt_table[cpu];
+#endif
+	__asm__ __volatile__("lgdt %0": "=m" (*gdt_desc));
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+	t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu;
+#else
+	t = init_tss + cpu;
 #endif
+	set_tss_desc(cpu, t);
+	cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
+	load_TR_desc();
+}
 
 #define _set_gate(gate_addr,type,dpl,addr,seg) \
 do { \
@@ -818,20 +949,26 @@
 	_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
 }
 
-static void __init set_trap_gate(unsigned int n, void *addr)
+void __init set_trap_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
 }
 
-static void __init set_system_gate(unsigned int n, void *addr)
+void __init set_system_gate(unsigned int n, void *addr)
 {
 	_set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
 }
 
-static void __init set_call_gate(void *a, void *addr)
+void __init set_call_gate(void *a, void *addr)
 {
 	_set_gate(a,12,3,addr,__KERNEL_CS);
 }
+#ifdef CONFIG_KGDB
+void set_intr_usr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
+}
+#endif
 
 static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
 {
@@ -850,11 +987,16 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 	init_apic_mappings();
 #endif
+	init_entry_mappings();
 
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
+#ifndef CONFIG_KGDB
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+#else
+	set_intr_usr_gate(3,&int3);	/* int3-5 can be called from all */
+#endif
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
--- diff/arch/i386/kernel/vm86.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/kernel/vm86.c	2004-02-18 09:03:57.000000000 +0000
@@ -125,7 +125,7 @@
 	tss = init_tss + get_cpu();
 	current->thread.esp0 = current->thread.saved_esp0;
 	current->thread.sysenter_cs = __KERNEL_CS;
-	load_esp0(tss, &current->thread);
+	load_virtual_esp0(tss, current);
 	current->thread.saved_esp0 = 0;
 	put_cpu();
 
@@ -305,7 +305,7 @@
 	tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
 	if (cpu_has_sep)
 		tsk->thread.sysenter_cs = 0;
-	load_esp0(tss, &tsk->thread);
+	load_virtual_esp0(tss, tsk);
 	put_cpu();
 
 	tsk->thread.screen_bitmap = info->screen_bitmap;
--- diff/arch/i386/kernel/vmlinux.lds.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vmlinux.lds.S	2004-02-18 09:03:57.000000000 +0000
@@ -3,6 +3,9 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
+#include <linux/config.h>
+#include <asm/page.h>
+#include <asm/asm_offsets.h>
 	
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
@@ -10,7 +13,7 @@
 jiffies = jiffies_64;
 SECTIONS
 {
-  . = 0xC0000000 + 0x100000;
+  . = __PAGE_OFFSET + 0x100000;
   /* read-only */
   _text = .;			/* Text and read-only data */
   .text : {
@@ -19,6 +22,19 @@
 	*(.gnu.warning)
 	} = 0x9090
 
+#ifdef CONFIG_X86_4G
+  . = ALIGN(PAGE_SIZE_asm);
+  __entry_tramp_start = .;
+  . = FIX_ENTRY_TRAMPOLINE_0_addr;
+  __start___entry_text = .;
+  .entry.text : AT (__entry_tramp_start) { *(.entry.text) }
+  __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text);
+  . = __entry_tramp_end;
+  . = ALIGN(PAGE_SIZE_asm);
+#else
+  .entry.text : { *(.entry.text) }
+#endif
+
   _etext = .;			/* End of text section */
 
   . = ALIGN(16);		/* Exception table */
@@ -34,15 +50,12 @@
 	CONSTRUCTORS
 	}
 
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __nosave_begin = .;
   .data_nosave : { *(.data.nosave) }
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __nosave_end = .;
 
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
@@ -52,7 +65,7 @@
   .data.init_task : { *(.data.init_task) }
 
   /* will be freed after init */
-  . = ALIGN(4096);		/* Init code and data */
+  . = ALIGN(PAGE_SIZE_asm);		/* Init code and data */
   __init_begin = .;
   .init.text : { 
 	_sinittext = .;
@@ -91,7 +104,7 @@
      from .altinstructions and .eh_frame */
   .exit.text : { *(.exit.text) }
   .exit.data : { *(.exit.data) }
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
@@ -99,10 +112,22 @@
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
-  . = ALIGN(4096);
+  . = ALIGN(PAGE_SIZE_asm);
   __init_end = .;
   /* freed after init ends here */
-	
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_tss : { *(.data.tss) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_default_ldt : { *(.data.default_ldt) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_idt : { *(.data.idt) }
+
+  . = ALIGN(PAGE_SIZE_asm);
+  .data.page_aligned_gdt : { *(.data.gdt) }
+
   __bss_start = .;		/* BSS */
   .bss : { *(.bss) }
   __bss_stop = .; 
@@ -122,4 +147,6 @@
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
+
+
 }
--- diff/arch/i386/kernel/vsyscall-sysenter.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vsyscall-sysenter.S	2004-02-18 09:03:57.000000000 +0000
@@ -7,6 +7,11 @@
 	.type __kernel_vsyscall,@function
 __kernel_vsyscall:
 .LSTART_vsyscall:
+	cmpl $192, %eax
+	jne 1f
+	int $0x80
+	ret
+1:
 	push %ecx
 .Lpush_ecx:
 	push %edx
--- diff/arch/i386/kernel/vsyscall.lds	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/kernel/vsyscall.lds	2004-02-18 09:03:57.000000000 +0000
@@ -5,7 +5,7 @@
  */
 
 /* This must match <asm/fixmap.h>.  */
-VSYSCALL_BASE = 0xffffe000;
+VSYSCALL_BASE = 0xffffd000;
 
 SECTIONS
 {
--- diff/arch/i386/lib/Makefile	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -9,4 +9,5 @@
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
 lib-$(CONFIG_DEBUG_IOVIRT)  += iodebug.o
--- diff/arch/i386/lib/checksum.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/checksum.S	2004-02-18 09:03:57.000000000 +0000
@@ -280,14 +280,14 @@
 	.previous
 
 .align 4
-.globl csum_partial_copy_generic
+.globl direct_csum_partial_copy_generic
 				
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
 #define ARGBASE 16		
 #define FP		12
 		
-csum_partial_copy_generic:
+direct_csum_partial_copy_generic:
 	subl  $4,%esp	
 	pushl %edi
 	pushl %esi
@@ -422,7 +422,7 @@
 
 #define ARGBASE 12
 		
-csum_partial_copy_generic:
+direct_csum_partial_copy_generic:
 	pushl %ebx
 	pushl %edi
 	pushl %esi
--- diff/arch/i386/lib/dec_and_lock.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/dec_and_lock.c	2004-02-18 09:03:57.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
@@ -38,3 +39,5 @@
 	spin_unlock(lock);
 	return 0;
 }
+#endif
+
--- diff/arch/i386/lib/getuser.S	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/lib/getuser.S	2004-02-18 09:03:57.000000000 +0000
@@ -9,6 +9,7 @@
  * return value.
  */
 #include <asm/thread_info.h>
+#include <asm/asm_offsets.h>
 
 
 /*
@@ -28,7 +29,7 @@
 .globl __get_user_1
 __get_user_1:
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 1:	movzbl (%eax),%edx
 	xorl %eax,%eax
@@ -40,7 +41,7 @@
 	addl $1,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 2:	movzwl -1(%eax),%edx
 	xorl %eax,%eax
@@ -52,7 +53,7 @@
 	addl $3,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
-	cmpl TI_ADDR_LIMIT(%edx),%eax
+	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 3:	movl -3(%eax),%edx
 	xorl %eax,%eax
--- diff/arch/i386/lib/usercopy.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/lib/usercopy.c	2004-02-18 09:03:57.000000000 +0000
@@ -76,7 +76,7 @@
  * and returns @count.
  */
 long
-__strncpy_from_user(char *dst, const char __user *src, long count)
+__direct_strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res;
 	__do_strncpy_from_user(dst, src, count, res);
@@ -102,7 +102,7 @@
  * and returns @count.
  */
 long
-strncpy_from_user(char *dst, const char __user *src, long count)
+direct_strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res = -EFAULT;
 	if (access_ok(VERIFY_READ, src, 1))
@@ -147,7 +147,7 @@
  * On success, this will be zero.
  */
 unsigned long
-clear_user(void __user *to, unsigned long n)
+direct_clear_user(void __user *to, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -167,7 +167,7 @@
  * On success, this will be zero.
  */
 unsigned long
-__clear_user(void __user *to, unsigned long n)
+__direct_clear_user(void __user *to, unsigned long n)
 {
 	__do_clear_user(to, n);
 	return n;
@@ -184,7 +184,7 @@
  * On exception, returns 0.
  * If the string is too long, returns a value greater than @n.
  */
-long strnlen_user(const char __user *s, long n)
+long direct_strnlen_user(const char __user *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
 	unsigned long res, tmp;
@@ -575,3 +575,4 @@
 		n = __copy_user_zeroing_intel(to, (const void *) from, n);
 	return n;
 }
+
--- diff/arch/i386/math-emu/fpu_system.h	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/math-emu/fpu_system.h	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <asm/atomic_kmap.h>
 
 /* This sets the pointer FPU_info to point to the argument part
    of the stack frame of math_emulate() */
@@ -22,7 +23,7 @@
 
 /* s is always from a cpu register, and the cpu does bounds checking
  * during register load --> no further bounds checks needed */
-#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
+#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3])
 #define SEG_D_SIZE(x)		((x).b & (3 << 21))
 #define SEG_G_BIT(x)		((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)	(((x).b & (1 << 23)) ? 4096 : 1)
--- diff/arch/i386/mm/fault.c	2003-12-19 09:51:11.000000000 +0000
+++ source/arch/i386/mm/fault.c	2004-02-18 09:03:57.000000000 +0000
@@ -27,6 +27,7 @@
 #include <asm/pgalloc.h>
 #include <asm/hardirq.h>
 #include <asm/desc.h>
+#include <asm/tlbflush.h>
 
 extern void die(const char *,struct pt_regs *,long);
 
@@ -104,8 +105,17 @@
 	if (seg & (1<<2)) {
 		/* Must lock the LDT while reading it. */
 		down(&current->mm->context.sem);
+#if 1
+		/* horrible hack for 4/4 disabled kernels.
+		   I'm not quite sure what the TLB flush is good for,
+		   it's mindlessly copied from the read_ldt code */
+		__flush_tlb_global();
+		desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]);
+		desc = (void *)desc + ((seg & ~7) % PAGE_SIZE);
+#else
 		desc = current->mm->context.ldt;
 		desc = (void *)desc + (seg & ~7);
+#endif
 	} else {
 		/* Must disable preemption while reading the GDT. */
 		desc = (u32 *)&cpu_gdt_table[get_cpu()];
@@ -118,6 +128,9 @@
 		 (desc[1] & 0xff000000);
 
 	if (seg & (1<<2)) { 
+#if 1
+		kunmap((void *)((unsigned long)desc & PAGE_MASK));
+#endif
 		up(&current->mm->context.sem);
 	} else
 		put_cpu();
@@ -243,6 +256,19 @@
 	 * (error_code & 4) == 0, and that the fault was not a
 	 * protection error (error_code & 1) == 0.
 	 */
+#ifdef CONFIG_X86_4G
+	/*
+	 * On 4/4 all kernels faults are either bugs, vmalloc or prefetch
+	 */
+	if (unlikely((regs->xcs & 3) == 0)) {
+		if (error_code & 3)
+			goto bad_area_nosemaphore;
+
+		/* If it's vm86 fall through */
+		if (!(regs->eflags & VM_MASK))
+			goto vmalloc_fault;
+	}
+#else
 	if (unlikely(address >= TASK_SIZE)) { 
 		if (!(error_code & 5))
 			goto vmalloc_fault;
@@ -252,6 +278,7 @@
 		 */
 		goto bad_area_nosemaphore;
 	} 
+#endif
 
 	mm = tsk->mm;
 
@@ -403,6 +430,12 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
+#ifdef CONFIG_KGDB
+        if (!user_mode(regs)){
+                kgdb_handle_exception(14,SIGBUS, error_code, regs);
+                return;
+        }
+#endif
 
 	bust_spinlocks(1);
 
--- diff/arch/i386/mm/hugetlbpage.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/mm/hugetlbpage.c	2004-02-18 09:03:57.000000000 +0000
@@ -61,6 +61,27 @@
 
 static void free_huge_page(struct page *page);
 
+#ifdef CONFIG_NUMA
+
+static inline void huge_inc_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	mm->pernode_rss[page_to_nid(page)] += (HPAGE_SIZE / PAGE_SIZE);
+}
+
+static inline void huge_dec_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss -= (HPAGE_SIZE / PAGE_SIZE);
+	mm->pernode_rss[page_to_nid(page)] -= (HPAGE_SIZE / PAGE_SIZE);
+}
+
+#else /* !CONFIG_NUMA */
+
+#define huge_inc_rss(mm, page)	((mm)->rss += (HPAGE_SIZE / PAGE_SIZE))
+#define huge_dec_rss(mm, page)	((mm)->rss -= (HPAGE_SIZE / PAGE_SIZE))
+
+#endif /* CONFIG_NUMA */
+
 static struct page *alloc_hugetlb_page(void)
 {
 	int i;
@@ -105,7 +126,7 @@
 {
 	pte_t entry;
 
-	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+	huge_inc_rss(mm, page);
 	if (write_access) {
 		entry =
 		    pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -145,7 +166,7 @@
 		ptepage = pte_page(entry);
 		get_page(ptepage);
 		set_pte(dst_pte, entry);
-		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		huge_inc_rss(dst, ptepage);
 		addr += HPAGE_SIZE;
 	}
 	return 0;
@@ -314,8 +335,8 @@
 		page = pte_page(*pte);
 		huge_page_release(page);
 		pte_clear(pte);
+		huge_dec_rss(mm, page);
 	}
-	mm->rss -= (end - start) >> PAGE_SHIFT;
 	flush_tlb_range(vma, start, end);
 }
 
--- diff/arch/i386/mm/init.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/i386/mm/init.c	2004-02-18 09:03:57.000000000 +0000
@@ -40,125 +40,13 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/desc.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 unsigned long highstart_pfn, highend_pfn;
 
 static int do_test_wp_bit(void);
 
-/*
- * Creates a middle page table and puts a pointer to it in the
- * given global directory entry. This only returns the gd entry
- * in non-PAE compilation mode, since the middle layer is folded.
- */
-static pmd_t * __init one_md_table_init(pgd_t *pgd)
-{
-	pmd_t *pmd_table;
-		
-#ifdef CONFIG_X86_PAE
-	pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-	set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
-	if (pmd_table != pmd_offset(pgd, 0)) 
-		BUG();
-#else
-	pmd_table = pmd_offset(pgd, 0);
-#endif
-
-	return pmd_table;
-}
-
-/*
- * Create a page table and place a pointer to it in a middle page
- * directory entry.
- */
-static pte_t * __init one_page_table_init(pmd_t *pmd)
-{
-	if (pmd_none(*pmd)) {
-		pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
-		if (page_table != pte_offset_kernel(pmd, 0))
-			BUG();	
-
-		return page_table;
-	}
-	
-	return pte_offset_kernel(pmd, 0);
-}
-
-/*
- * This function initializes a certain range of kernel virtual memory 
- * with new bootmem page tables, everywhere page tables are missing in
- * the given range.
- */
-
-/*
- * NOTE: The pagetables are allocated contiguous on the physical space 
- * so we can cache the place of the first one and move around without 
- * checking the pgd every time.
- */
-static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	int pgd_idx, pmd_idx;
-	unsigned long vaddr;
-
-	vaddr = start;
-	pgd_idx = pgd_index(vaddr);
-	pmd_idx = pmd_index(vaddr);
-	pgd = pgd_base + pgd_idx;
-
-	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
-		if (pgd_none(*pgd)) 
-			one_md_table_init(pgd);
-
-		pmd = pmd_offset(pgd, vaddr);
-		for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
-			if (pmd_none(*pmd)) 
-				one_page_table_init(pmd);
-
-			vaddr += PMD_SIZE;
-		}
-		pmd_idx = 0;
-	}
-}
-
-/*
- * This maps the physical memory to kernel virtual address space, a total 
- * of max_low_pfn pages, by creating page tables starting from address 
- * PAGE_OFFSET.
- */
-static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
-{
-	unsigned long pfn;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	int pgd_idx, pmd_idx, pte_ofs;
-
-	pgd_idx = pgd_index(PAGE_OFFSET);
-	pgd = pgd_base + pgd_idx;
-	pfn = 0;
-
-	for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
-		pmd = one_md_table_init(pgd);
-		if (pfn >= max_low_pfn)
-			continue;
-		for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
-			/* Map with big pages if possible, otherwise create normal page tables. */
-			if (cpu_has_pse) {
-				set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
-				pfn += PTRS_PER_PTE;
-			} else {
-				pte = one_page_table_init(pmd);
-
-				for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++)
-					set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
-			}
-		}
-	}	
-}
-
 static inline int page_kills_ppro(unsigned long pagenr)
 {
 	if (pagenr >= 0x70000 && pagenr <= 0x7003F)
@@ -206,11 +94,8 @@
 	return 0;
 }
 
-#ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
-pgprot_t kmap_prot;
 
-EXPORT_SYMBOL(kmap_prot);
 EXPORT_SYMBOL(kmap_pte);
 
 #define kmap_get_fixmap_pte(vaddr)					\
@@ -218,29 +103,7 @@
 
 void __init kmap_init(void)
 {
-	unsigned long kmap_vstart;
-
-	/* cache the first kmap pte */
-	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
-	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
-
-	kmap_prot = PAGE_KERNEL;
-}
-
-void __init permanent_kmaps_init(pgd_t *pgd_base)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long vaddr;
-
-	vaddr = PKMAP_BASE;
-	page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
-
-	pgd = swapper_pg_dir + pgd_index(vaddr);
-	pmd = pmd_offset(pgd, vaddr);
-	pte = pte_offset_kernel(pmd, vaddr);
-	pkmap_page_table = pte;	
+	kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN));
 }
 
 void __init one_highpage_init(struct page *page, int pfn, int bad_ppro)
@@ -255,6 +118,8 @@
 		SetPageReserved(page);
 }
 
+#ifdef CONFIG_HIGHMEM
+
 #ifndef CONFIG_DISCONTIGMEM
 void __init set_highmem_pages_init(int bad_ppro) 
 {
@@ -266,12 +131,9 @@
 #else
 extern void set_highmem_pages_init(int);
 #endif /* !CONFIG_DISCONTIGMEM */
-
 #else
-#define kmap_init() do { } while (0)
-#define permanent_kmaps_init(pgd_base) do { } while (0)
-#define set_highmem_pages_init(bad_ppro) do { } while (0)
-#endif /* CONFIG_HIGHMEM */
+# define set_highmem_pages_init(bad_ppro) do { } while (0)
+#endif
 
 unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
 
@@ -281,30 +143,125 @@
 extern void __init remap_numa_kva(void);
 #endif
 
-static void __init pagetable_init (void)
+static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	pgd = pgd_base + pgd_index(address);
+	pmd = pmd_offset(pgd, address);
+	if (!pmd_present(*pmd)) {
+		pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
+	}
+}
+
+static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
 {
 	unsigned long vaddr;
-	pgd_t *pgd_base = swapper_pg_dir;
 
+	for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE)
+		prepare_pagetables(pgd_base, vaddr);
+}
+
+void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
+{
+	unsigned long vaddr;
+	pgd_t *pgd;
+	int i, j, k;
+	pmd_t *pmd;
+	pte_t *pte, *pte_base;
+
+	pgd = pgd_base;
+
+	for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
+		vaddr = i*PGDIR_SIZE;
+		if (end && (vaddr >= end))
+			break;
+		pmd = pmd_offset(pgd, 0);
+		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
+			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+			if (end && (vaddr >= end))
+				break;
+			if (vaddr < start)
+				continue;
+			if (cpu_has_pse) {
+				unsigned long __pe;
+
+				set_in_cr4(X86_CR4_PSE);
+				boot_cpu_data.wp_works_ok = 1;
+				__pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start;
+				/* Make it "global" too if supported */
+				if (cpu_has_pge) {
+					set_in_cr4(X86_CR4_PGE);
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
+					__pe += _PAGE_GLOBAL;
+					__PAGE_KERNEL |= _PAGE_GLOBAL;
+#endif
+				}
+				set_pmd(pmd, __pmd(__pe));
+				continue;
+			}
+			if (!pmd_present(*pmd))
+				pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			else
+				pte_base = (pte_t *) page_address(pmd_page(*pmd));
+			pte = pte_base;
+			for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
+				vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
+				if (end && (vaddr >= end))
+					break;
+				if (vaddr < start)
+					continue;
+				*pte = mk_pte_phys(vaddr-start, PAGE_KERNEL);
+			}
+			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
+		}
+	}
+}
+
+static void __init pagetable_init (void)
+{
+	unsigned long vaddr, end;
+	pgd_t *pgd_base;
 #ifdef CONFIG_X86_PAE
 	int i;
-	/* Init entries of the first-level page table to the zero page */
-	for (i = 0; i < PTRS_PER_PGD; i++)
-		set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
 #endif
 
-	/* Enable PSE if available */
-	if (cpu_has_pse) {
-		set_in_cr4(X86_CR4_PSE);
-	}
+	/*
+	 * This can be zero as well - no problem, in that case we exit
+	 * the loops anyway due to the PTRS_PER_* conditions.
+	 */
+	end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
 
-	/* Enable PGE if available */
-	if (cpu_has_pge) {
-		set_in_cr4(X86_CR4_PGE);
-		__PAGE_KERNEL |= _PAGE_GLOBAL;
+	pgd_base = swapper_pg_dir;
+#ifdef CONFIG_X86_PAE
+	/*
+	 * It causes too many problems if there's no proper pmd set up
+	 * for all 4 entries of the PGD - so we allocate all of them.
+	 * PAE systems will not miss this extra 4-8K anyway ...
+	 */
+	for (i = 0; i < PTRS_PER_PGD; i++) {
+		pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1));
 	}
+#endif
+	/*
+	 * Set up lowmem-sized identity mappings at PAGE_OFFSET:
+	 */
+	setup_identity_mappings(pgd_base, PAGE_OFFSET, end);
 
-	kernel_physical_mapping_init(pgd_base);
+	/*
+	 * Add flat-mode identity-mappings - SMP needs it when
+	 * starting up on an AP from real-mode. (In the non-PAE
+	 * case we already have these mappings through head.S.)
+	 * All user-space mappings are explicitly cleared after
+	 * SMP startup.
+	 */
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_PAE)
+	setup_identity_mappings(pgd_base, 0, 16*1024*1024);
+#endif
 	remap_numa_kva();
 
 	/*
@@ -312,38 +269,64 @@
 	 * created - mappings will be set by set_fixmap():
 	 */
 	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
-	page_table_range_init(vaddr, 0, pgd_base);
+	fixrange_init(vaddr, 0, pgd_base);
 
-	permanent_kmaps_init(pgd_base);
+#ifdef CONFIG_HIGHMEM
+	{
+		pgd_t *pgd;
+		pmd_t *pmd;
+		pte_t *pte;
 
-#ifdef CONFIG_X86_PAE
-	/*
-	 * Add low memory identity-mappings - SMP needs it when
-	 * starting up on an AP from real-mode. In the non-PAE
-	 * case we already have these mappings through head.S.
-	 * All user-space mappings are explicitly cleared after
-	 * SMP startup.
-	 */
-	pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
+		/*
+		 * Permanent kmaps:
+		 */
+		vaddr = PKMAP_BASE;
+		fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+
+		pgd = swapper_pg_dir + pgd_index(vaddr);
+		pmd = pmd_offset(pgd, vaddr);
+		pte = pte_offset_kernel(pmd, vaddr);
+		pkmap_page_table = pte;
+	}
 #endif
 }
 
-void zap_low_mappings (void)
+/*
+ * Clear kernel pagetables in a PMD_SIZE-aligned range.
+ */
+static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end)
 {
-	int i;
+	unsigned long vaddr;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	int i, j;
+
+	pgd = pgd_base;
+
+	for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
+		vaddr = i*PGDIR_SIZE;
+		if (end && (vaddr >= end))
+			break;
+		pmd = pmd_offset(pgd, 0);
+		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
+			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+			if (end && (vaddr >= end))
+				break;
+			if (vaddr < start)
+				continue;
+			pmd_clear(pmd);
+		}
+	}
+	flush_tlb_all();
+}
+
+void zap_low_mappings(void)
+{
+	printk("zapping low mappings.\n");
 	/*
 	 * Zap initial low-memory mappings.
-	 *
-	 * Note that "pgd_clear()" doesn't do it for
-	 * us, because pgd_clear() is a no-op on i386.
 	 */
-	for (i = 0; i < USER_PTRS_PER_PGD; i++)
-#ifdef CONFIG_X86_PAE
-		set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
-#else
-		set_pgd(swapper_pg_dir+i, __pgd(0));
-#endif
-	flush_tlb_all();
+	clear_mappings(swapper_pg_dir, 0, 16*1024*1024);
 }
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -393,7 +376,15 @@
 		set_in_cr4(X86_CR4_PAE);
 #endif
 	__flush_tlb_all();
-
+	/*
+	 * Subtle. SMP is doing it's boot stuff late (because it has to
+	 * fork idle threads) - but it also needs low mappings for the
+	 * protected-mode entry to work. We zap these entries only after
+	 * the WP-bit has been tested.
+	 */
+#ifndef CONFIG_SMP
+	zap_low_mappings();
+#endif
 	kmap_init();
 	zone_sizes_init();
 }
@@ -515,22 +506,18 @@
 	if (boot_cpu_data.wp_works_ok < 0)
 		test_wp_bit();
 
-	/*
-	 * Subtle. SMP is doing it's boot stuff late (because it has to
-	 * fork idle threads) - but it also needs low mappings for the
-	 * protected-mode entry to work. We zap these entries only after
-	 * the WP-bit has been tested.
-	 */
-#ifndef CONFIG_SMP
-	zap_low_mappings();
-#endif
+	entry_trampoline_setup();
+	default_ldt_page = virt_to_page(default_ldt);
+	load_LDT(&init_mm.context);
 }
 
-kmem_cache_t *pgd_cache;
-kmem_cache_t *pmd_cache;
+kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
 
 void __init pgtable_cache_init(void)
 {
+	void (*ctor)(void *, kmem_cache_t *, unsigned long);
+	void (*dtor)(void *, kmem_cache_t *, unsigned long);
+
 	if (PTRS_PER_PMD > 1) {
 		pmd_cache = kmem_cache_create("pmd",
 					PTRS_PER_PMD*sizeof(pmd_t),
@@ -540,13 +527,36 @@
 					NULL);
 		if (!pmd_cache)
 			panic("pgtable_cache_init(): cannot create pmd cache");
+
+		if (TASK_SIZE > PAGE_OFFSET) {
+			kpmd_cache = kmem_cache_create("kpmd",
+					PTRS_PER_PMD*sizeof(pmd_t),
+					0,
+					SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
+					kpmd_ctor,
+					NULL);
+			if (!kpmd_cache)
+				panic("pgtable_cache_init(): "
+						"cannot create kpmd cache");
+		}
 	}
+
+	if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET)
+		ctor = pgd_ctor;
+	else
+		ctor = NULL;
+
+	if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET)
+		dtor = pgd_dtor;
+	else
+		dtor = NULL;
+
 	pgd_cache = kmem_cache_create("pgd",
 				PTRS_PER_PGD*sizeof(pgd_t),
 				0,
 				SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
-				pgd_ctor,
-				PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
+				ctor,
+				dtor);
 	if (!pgd_cache)
 		panic("pgtable_cache_init(): Cannot create pgd cache");
 }
--- diff/arch/i386/mm/pgtable.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/i386/mm/pgtable.c	2004-02-18 09:03:57.000000000 +0000
@@ -21,6 +21,7 @@
 #include <asm/e820.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
+#include <asm/atomic_kmap.h>
 
 void show_mem(void)
 {
@@ -157,11 +158,20 @@
 	memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
 }
 
+void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags)
+{
+	pmd_t *kpmd, *pmd;
+	kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1],
+				(PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE);
+	pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS);
+
+	memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t));
+	memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t));
+}
+
 /*
- * List of all pgd's needed for non-PAE so it can invalidate entries
- * in both cached and uncached pgd's; not needed for PAE since the
- * kernel pmd is shared. If PAE were not to share the pmd a similar
- * tactic would be needed. This is essentially codepath-based locking
+ * List of all pgd's needed so it can invalidate entries in both cached
+ * and uncached pgd's. This is essentially codepath-based locking
  * against pageattr.c; it is the unique case in which a valid change
  * of kernel pagetables can't be lazily synchronized by vmalloc faults.
  * vmalloc faults work because attached pagetables are never freed.
@@ -170,30 +180,60 @@
  * could be used. The locking scheme was chosen on the basis of
  * manfred's recommendations and having no core impact whatsoever.
  * -- wli
+ *
+ * The entire issue goes away when XKVA is configured.
  */
 spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED;
 LIST_HEAD(pgd_list);
 
-void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
+/*
+ * This is not that hard to figure out.
+ * (a) PTRS_PER_PMD == 1 means non-PAE.
+ * (b) PTRS_PER_PMD > 1 means PAE.
+ * (c) TASK_SIZE > PAGE_OFFSET means XKVA.
+ * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA.
+ *
+ * Do *NOT* back out the preconstruction like the patch I'm cleaning
+ * up after this very instant did, or at all, for that matter.
+ * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET.
+ * -- wli
+ */
+void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused)
 {
+	pgd_t *pgd = (pgd_t *)__pgd;
 	unsigned long flags;
 
-	if (PTRS_PER_PMD == 1)
-		spin_lock_irqsave(&pgd_lock, flags);
+	if (PTRS_PER_PMD == 1) {
+		if (TASK_SIZE <= PAGE_OFFSET)
+			spin_lock_irqsave(&pgd_lock, flags);
+		else
+ 			memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS],
+ 				&swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS],
+ 				NR_SHARED_PMDS * sizeof(pgd_t));
+	}
 
-	memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
-			swapper_pg_dir + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	if (TASK_SIZE <= PAGE_OFFSET)
+ 		memcpy(pgd + USER_PTRS_PER_PGD,
+ 			swapper_pg_dir + USER_PTRS_PER_PGD,
+ 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 
 	if (PTRS_PER_PMD > 1)
 		return;
 
-	list_add(&virt_to_page(pgd)->lru, &pgd_list);
-	spin_unlock_irqrestore(&pgd_lock, flags);
-	memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+	if (TASK_SIZE > PAGE_OFFSET)
+		memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t));
+	else {
+		list_add(&virt_to_page(pgd)->lru, &pgd_list);
+		spin_unlock_irqrestore(&pgd_lock, flags);
+		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+	}
 }
 
-/* never called when PTRS_PER_PMD > 1 */
+/*
+ * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET
+ * for with PAE we would list_del() multiple times, and for non-PAE
+ * with XKVA all the AGP pgd shootdown code is unnecessary.
+ */
 void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
 {
 	unsigned long flags; /* can be called from interrupt context */
@@ -203,6 +243,12 @@
 	spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
+/*
+ * See the comments above pgd_ctor() wrt. preconstruction.
+ * Do *NOT* memcpy() here. If you do, you back out important
+ * anti- cache pollution code.
+ *
+ */
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	int i;
@@ -211,15 +257,33 @@
 	if (PTRS_PER_PMD == 1 || !pgd)
 		return pgd;
 
+	/*
+	 * In the 4G userspace case alias the top 16 MB virtual
+	 * memory range into the user mappings as well (these
+	 * include the trampoline and CPU data structures).
+	 */
 	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
-		pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+		kmem_cache_t *cache;
+		pmd_t *pmd;
+
+		if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
+			cache = kpmd_cache;
+		else
+			cache = pmd_cache;
+
+		pmd = kmem_cache_alloc(cache, GFP_KERNEL);
 		if (!pmd)
 			goto out_oom;
 		set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd))));
 	}
-	return pgd;
 
+	return pgd;
 out_oom:
+	/*
+	 * we don't have to handle the kpmd_cache here, since it's the
+	 * last allocation, and has either nothing to free or when it
+	 * succeeds the whole operation succeeds.
+	 */
 	for (i--; i >= 0; i--)
 		kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
 	kmem_cache_free(pgd_cache, pgd);
@@ -230,10 +294,29 @@
 {
 	int i;
 
-	/* in the PAE case user pgd entries are overwritten before usage */
-	if (PTRS_PER_PMD > 1)
-		for (i = 0; i < USER_PTRS_PER_PGD; ++i)
-			kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
 	/* in the non-PAE case, clear_page_tables() clears user pgd entries */
+	if (PTRS_PER_PMD == 1)
+		goto out_free;
+
+	/* in the PAE case user pgd entries are overwritten before usage */
+	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
+		kmem_cache_t *cache;
+		pmd_t *pmd = __va(pgd_val(pgd[i]) - 1);
+
+		/*
+		 * only userspace pmd's are cleared for us
+		 * by mm/memory.c; it's a slab cache invariant
+		 * that we must separate the kernel pmd slab
+		 * all times, else we'll have bad pmd's.
+		 */
+		if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1)
+			cache = kpmd_cache;
+		else
+			cache = pmd_cache;
+
+		kmem_cache_free(cache, pmd);
+	}
+out_free:
 	kmem_cache_free(pgd_cache, pgd);
 }
+
--- diff/arch/i386/oprofile/nmi_int.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/i386/oprofile/nmi_int.c	2004-02-18 09:03:57.000000000 +0000
@@ -335,7 +335,9 @@
 	if (cpu_model > 0xd)
 		return 0;
 
-	if (cpu_model > 5) {
+	if (cpu_model == 9) {
+		nmi_ops.cpu_type = "i386/p6_mobile";
+	} else if (cpu_model > 5) {
 		nmi_ops.cpu_type = "i386/piii";
 	} else if (cpu_model > 2) {
 		nmi_ops.cpu_type = "i386/pii";
--- diff/arch/i386/oprofile/nmi_timer_int.c	2003-06-30 10:07:32.000000000 +0100
+++ source/arch/i386/oprofile/nmi_timer_int.c	2004-02-18 09:03:57.000000000 +0000
@@ -48,9 +48,13 @@
 	.cpu_type = "timer"
 };
 
- 
 int __init nmi_timer_init(struct oprofile_operations ** ops)
 {
+	extern int nmi_active;
+
+	if (nmi_active <= 0)
+		return -ENODEV;
+
 	*ops = &nmi_timer_ops;
 	printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
 	return 0;
--- diff/arch/i386/oprofile/op_model_p4.c	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/i386/oprofile/op_model_p4.c	2004-02-18 09:03:57.000000000 +0000
@@ -382,11 +382,8 @@
 static unsigned int get_stagger(void)
 {
 #ifdef CONFIG_SMP
-	int cpu;
-	if (smp_num_siblings > 1) {
-		cpu = smp_processor_id();
-		return (cpu_sibling_map[cpu] > cpu) ? 0 : 1;
-	}
+	int cpu = smp_processor_id();
+	return (cpu != first_cpu(cpu_sibling_map[cpu]));
 #endif	
 	return 0;
 }
--- diff/arch/i386/oprofile/op_model_ppro.c	2003-08-26 10:00:51.000000000 +0100
+++ source/arch/i386/oprofile/op_model_ppro.c	2004-02-18 09:03:57.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/oprofile.h>
 #include <asm/ptrace.h>
 #include <asm/msr.h>
+#include <asm/apic.h>
  
 #include "op_x86_model.h"
 #include "op_counter.h"
@@ -101,6 +102,10 @@
 		}
 	}
 
+	/* Only P6 based Pentium M need to re-unmask the apic vector but it
+	 * doesn't hurt other P6 variant */
+	apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
+
 	/* We can't work out if we really handled an interrupt. We
 	 * might have caught a *second* counter just after overflowing
 	 * the interrupt for this counter then arrives
--- diff/arch/i386/pci/Makefile	2003-07-08 09:55:17.000000000 +0100
+++ source/arch/i386/pci/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -1,6 +1,7 @@
 obj-y				:= i386.o
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
+obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
 
 pci-y				:= fixup.o
--- diff/arch/i386/pci/common.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/pci/common.c	2004-02-18 09:03:57.000000000 +0000
@@ -20,7 +20,8 @@
 extern  void pcibios_sort(void);
 #endif
 
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
+				PCI_PROBE_MMCONF;
 
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
@@ -198,6 +199,12 @@
 		return NULL;
 	}
 #endif
+#ifdef CONFIG_PCI_MMCONFIG
+	else if (!strcmp(str, "nommconf")) {
+		pci_probe &= ~PCI_PROBE_MMCONF;
+		return NULL;
+	}
+#endif
 	else if (!strcmp(str, "noacpi")) {
 		acpi_noirq_set();
 		return NULL;
--- diff/arch/i386/pci/pci.h	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/i386/pci/pci.h	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,9 @@
 #define PCI_PROBE_BIOS		0x0001
 #define PCI_PROBE_CONF1		0x0002
 #define PCI_PROBE_CONF2		0x0004
+#define PCI_PROBE_MMCONF	0x0008
+#define PCI_PROBE_MASK		0x000f
+
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_NO_CHECKS		0x0400
--- diff/arch/ia64/Kconfig	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -662,6 +662,13 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 	  
+config LOCKMETER
+       bool "Kernel lock metering"
+       depends on SMP
+       help
+         Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+         but allows you to see various statistics using the lockstat command.
+
 endmenu
 
 source "security/Kconfig"
--- diff/arch/ia64/hp/sim/simeth.c	2003-08-20 14:16:08.000000000 +0100
+++ source/arch/ia64/hp/sim/simeth.c	2004-02-18 09:03:57.000000000 +0000
@@ -224,7 +224,7 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/arch/ia64/ia32/ia32_ioctl.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/ia64/ia32/ia32_ioctl.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,6 +8,7 @@
  */
 
 #include <linux/signal.h>	/* argh, msdos_fs.h isn't self-contained... */
+#include <linux/syscalls.h>
 #include "ia32priv.h"
   
 #define	INCLUDES
@@ -26,8 +27,6 @@
 	_ret;						\
 })
 
-asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-
 #define CODE
 #include "compat_ioctl.c"
 
--- diff/arch/ia64/ia32/ia32_signal.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/ia64/ia32/ia32_signal.c	2004-02-18 09:03:57.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/wait.h>
 #include <linux/compat.h>
@@ -550,9 +551,6 @@
 }
 
 
-extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset,
-					   size_t sigsetsize);
-
 asmlinkage long
 sys32_rt_sigprocmask (int how, compat_sigset_t *set, compat_sigset_t *oset, unsigned int sigsetsize)
 {
@@ -584,8 +582,6 @@
 sys32_rt_sigtimedwait (compat_sigset_t *uthese, siginfo_t32 *uinfo,
 		struct compat_timespec *uts, unsigned int sigsetsize)
 {
-	extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *,
-						    const struct timespec *, size_t);
 	extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *);
 	mm_segment_t old_fs = get_fs();
 	struct timespec t;
@@ -611,7 +607,6 @@
 asmlinkage long
 sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo)
 {
-	extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *);
 	extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from);
 	mm_segment_t old_fs = get_fs();
 	siginfo_t info;
--- diff/arch/ia64/ia32/sys_ia32.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/ia32/sys_ia32.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -55,6 +56,7 @@
 #include <asm/semaphore.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include "ia32priv.h"
 
@@ -81,16 +83,9 @@
 #define high2lowuid(uid) ((uid) > 65535 ? 65534 : (uid))
 #define high2lowgid(gid) ((gid) > 65535 ? 65534 : (gid))
 
-extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);
-extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);
-extern asmlinkage long sys_munmap (unsigned long, size_t);
 extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long,
 					     unsigned long, unsigned long);
 
-/* forward declaration: */
-asmlinkage long sys32_mprotect (unsigned int, unsigned int, int);
-asmlinkage unsigned long sys_brk(unsigned long);
-
 /*
  * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore
  * while doing so.
@@ -949,9 +944,6 @@
 			    (struct compat_timeval *) A(a.tvp));
 }
 
-asmlinkage ssize_t sys_readv (unsigned long,const struct iovec *,unsigned long);
-asmlinkage ssize_t sys_writev (unsigned long,const struct iovec *,unsigned long);
-
 static struct iovec *
 get_compat_iovec (struct compat_iovec *iov32, struct iovec *iov_buf, u32 count, int type)
 {
@@ -2023,9 +2015,6 @@
 	return 0;
 }
 
-extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
-				   long, long);
-
 /*
  *  Note that the IA32 version of `ptrace' calls the IA64 routine for
  *    many of the requests.  This will only work for requests that do
@@ -2284,8 +2273,6 @@
 	return -ERESTARTNOHAND;
 }
 
-asmlinkage long sys_msync (unsigned long start, size_t len, int flags);
-
 asmlinkage int
 sys32_msync (unsigned int start, unsigned int len, int flags)
 {
@@ -2307,8 +2294,6 @@
 	unsigned int	__unused[4];
 };
 
-extern asmlinkage long sys_sysctl(struct __sysctl_args *args);
-
 asmlinkage long
 sys32_sysctl (struct sysctl32 *args)
 {
@@ -2358,7 +2343,6 @@
 asmlinkage long
 sys32_newuname (struct new_utsname *name)
 {
-	extern asmlinkage long sys_newuname(struct new_utsname * name);
 	int ret = sys_newuname(name);
 
 	if (!ret)
@@ -2367,8 +2351,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_getresuid (uid_t *ruid, uid_t *euid, uid_t *suid);
-
 asmlinkage long
 sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid)
 {
@@ -2385,8 +2367,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid);
-
 asmlinkage long
 sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid)
 {
@@ -2407,65 +2387,100 @@
 asmlinkage long
 sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
-	extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
-
 	/* Sign-extension of "offset" is important here... */
 	return sys_lseek(fd, offset, whence);
 }
 
-extern asmlinkage long sys_getgroups (int gidsetsize, gid_t *grouplist);
+static int
+groups16_to_user(short *grouplist, struct group_info *group_info)
+{
+	int i;
+	short group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		group = (short)GROUP_AT(group_info, i);
+		if (put_user(group, grouplist+i))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int
+groups16_from_user(struct group_info *group_info, short *grouplist)
+{
+	int i;
+	short group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		if (get_user(group, grouplist+i))
+			return  -EFAULT;
+		GROUP_AT(group_info, i) = (gid_t)group;
+	}
+
+	return 0;
+}
 
 asmlinkage long
 sys32_getgroups16 (int gidsetsize, short *grouplist)
 {
-	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
-	int ret, i;
+	int i;
 
-	set_fs(KERNEL_DS);
-	ret = sys_getgroups(gidsetsize, gl);
-	set_fs(old_fs);
+	if (gidsetsize < 0)
+		return -EINVAL;
 
-	if (gidsetsize && ret > 0 && ret <= NGROUPS)
-		for (i = 0; i < ret; i++, grouplist++)
-			if (put_user(gl[i], grouplist))
-				return -EFAULT;
-	return ret;
+	get_group_info(current->group_info);
+	i = current->group_info->ngroups;
+	if (gidsetsize) {
+		if (i > gidsetsize) {
+			i = -EINVAL;
+			goto out;
+		}
+		if (groups16_to_user(grouplist, current->group_info)) {
+			i = -EFAULT;
+			goto out;
+		}
+	}
+out:
+	put_group_info(current->group_info);
+	return i;
 }
 
-extern asmlinkage long sys_setgroups (int gidsetsize, gid_t *grouplist);
-
 asmlinkage long
 sys32_setgroups16 (int gidsetsize, short *grouplist)
 {
-	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
-	int ret, i;
+	struct group_info *group_info;
+	int retval;
 
-	if ((unsigned) gidsetsize > NGROUPS)
+	if (!capable(CAP_SETGID))
+		return -EPERM;
+	if ((unsigned)gidsetsize > NGROUPS_MAX)
 		return -EINVAL;
-	for (i = 0; i < gidsetsize; i++, grouplist++)
-		if (get_user(gl[i], grouplist))
-			return -EFAULT;
-	set_fs(KERNEL_DS);
-	ret = sys_setgroups(gidsetsize, gl);
-	set_fs(old_fs);
-	return ret;
+
+	group_info = groups_alloc(gidsetsize);
+	if (!group_info)
+		return -ENOMEM;
+	retval = groups16_from_user(group_info, grouplist);
+	if (retval) {
+		put_group_info(group_info);
+		return retval;
+	}
+
+	retval = set_current_groups(group_info);
+	put_group_info(group_info);
+
+	return retval;
 }
 
 asmlinkage long
 sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi)
 {
-	extern asmlinkage long sys_truncate (const char *path, unsigned long length);
-
 	return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo);
 }
 
 asmlinkage long
 sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi)
 {
-	extern asmlinkage long sys_ftruncate (int fd, unsigned long length);
-
 	return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo);
 }
 
@@ -2554,7 +2569,6 @@
 asmlinkage long
 sys32_sysinfo (struct sysinfo32 *info)
 {
-	extern asmlinkage long sys_sysinfo (struct sysinfo *);
 	struct sysinfo s;
 	long ret, err;
 	int bitcount = 0;
@@ -2606,7 +2620,6 @@
 asmlinkage long
 sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec *interval)
 {
-	extern asmlinkage long sys_sched_rr_get_interval (pid_t, struct timespec *);
 	mm_segment_t old_fs = get_fs();
 	struct timespec t;
 	long ret;
@@ -2622,21 +2635,18 @@
 asmlinkage long
 sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
 {
-	extern asmlinkage long sys_pread64 (unsigned int, char *, size_t, loff_t);
 	return sys_pread64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
 }
 
 asmlinkage long
 sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi)
 {
-	extern asmlinkage long sys_pwrite64 (unsigned int, const char *, size_t, loff_t);
 	return sys_pwrite64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);
 }
 
 asmlinkage long
 sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count)
 {
-	extern asmlinkage long sys_sendfile (int, int, off_t *, size_t);
 	mm_segment_t old_fs = get_fs();
 	long ret;
 	off_t of;
@@ -2657,7 +2667,6 @@
 asmlinkage long
 sys32_personality (unsigned int personality)
 {
-	extern asmlinkage long sys_personality (unsigned long);
 	long ret;
 
 	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
@@ -2949,8 +2958,6 @@
 	return err;
 }
 
-extern long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice);
-
 long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, 
 			__u32 len_low, __u32 len_high, int advice)
 { 
@@ -3049,9 +3056,6 @@
 	return 0;
 }
 
-extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
-				unsigned long new_flags, void *data);
-
 #define SMBFS_NAME	"smbfs"
 #define NCPFS_NAME	"ncpfs"
 
@@ -3116,8 +3120,6 @@
 	}
 }
 
-extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
-
 asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid)
 {
 	uid_t sruid, seuid;
@@ -3127,8 +3129,6 @@
 	return sys_setreuid(sruid, seuid);
 }
 
-extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
-
 asmlinkage long
 sys32_setresuid(compat_uid_t ruid, compat_uid_t euid,
 		compat_uid_t suid)
@@ -3141,8 +3141,6 @@
 	return sys_setresuid(sruid, seuid, ssuid);
 }
 
-extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
-
 asmlinkage long
 sys32_setregid(compat_gid_t rgid, compat_gid_t egid)
 {
@@ -3153,8 +3151,6 @@
 	return sys_setregid(srgid, segid);
 }
 
-extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
-
 asmlinkage long
 sys32_setresgid(compat_gid_t rgid, compat_gid_t egid,
 		compat_gid_t sgid)
@@ -3284,8 +3280,6 @@
 	return err;
 }
 
-extern asmlinkage long sys_nfsservctl(int cmd, void *arg, void *resp);
-
 int asmlinkage
 sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
--- diff/arch/ia64/kernel/irq.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -940,7 +940,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -1005,7 +1005,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/ia64/kernel/sys_ia64.c	2003-09-17 12:28:01.000000000 +0100
+++ source/arch/ia64/kernel/sys_ia64.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/file.h>		/* doh, must come after sched.h... */
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/highuid.h>
 #include <linux/hugetlb.h>
 
@@ -74,7 +75,6 @@
 asmlinkage long
 ia64_getpriority (int which, int who)
 {
-	extern long sys_getpriority (int, int);
 	long prio;
 
 	prio = sys_getpriority(which, who);
--- diff/arch/ia64/lib/dec_and_lock.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/ia64/lib/dec_and_lock.c	2004-02-18 09:03:57.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef CONFIG_LOCKMETER
 /*
  * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock.  Both of these
  * operations have to be done atomically, so that the count doesn't drop to zero without
@@ -40,3 +41,4 @@
 }
 
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
--- diff/arch/ia64/pci/pci.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/pci/pci.c	2004-02-18 09:03:57.000000000 +0000
@@ -55,8 +55,11 @@
 
 #define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \
 	((u64)(seg << 24) | (u64)(bus << 16) | \
-	 (u64)(devfn << 8) | (u64)(reg))
+	 (u64)(devfn << 8) | (u64)(reg)), 0
 
+#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \
+	((u64)(seg << 28) | (u64)(bus << 20) | \
+	 (u64)(devfn << 12) | (u64)(reg)), 1
 
 static int
 pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
@@ -64,10 +67,14 @@
 	int result = 0;
 	u64 data = 0;
 
-	if (!value || (seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255))
+	if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
-	result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, &data);
+	if ((seg < 256) && (reg < 256)) {
+		result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, &data);
+	} else {
+		result = ia64_sal_pci_config_read(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), len, &data);
+	}
 
 	*value = (u32) data;
 
@@ -77,13 +84,17 @@
 static int
 pci_sal_write (int seg, int bus, int devfn, int reg, int len, u32 value)
 {
-	if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255))
+	if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
 		return -EINVAL;
 
-	return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, value);
+	if ((seg < 256) && (reg < 256)) {
+		return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, value);
+	} else {
+		return ia64_sal_pci_config_write(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), len, value);
+	}
 }
 
-struct pci_raw_ops pci_sal_ops = {
+static struct pci_raw_ops pci_sal_ops = {
 	.read = 	pci_sal_read,
 	.write =	pci_sal_write
 };
--- diff/arch/ia64/sn/io/drivers/ioconfig_bus.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/drivers/ioconfig_bus.c	2004-02-18 09:03:57.000000000 +0000
@@ -16,6 +16,7 @@
 
 #include <linux/pci.h>
 
+#include <asm/uaccess.h>
 #include <asm/sn/sgi.h>
 #include <asm/io.h>
 #include <asm/sn/iograph.h>
--- diff/arch/ia64/sn/io/io.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/io.c	2004-02-18 09:03:57.000000000 +0000
@@ -12,7 +12,6 @@
 #include <asm/sn/types.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/driver.h>
-#include <asm/sn/iograph.h>
 #include <asm/param.h>
 #include <asm/sn/pio.h>
 #include <asm/sn/xtalk/xwidget.h>
--- diff/arch/ia64/sn/io/machvec/pci_bus_cvlink.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/machvec/pci_bus_cvlink.c	2004-02-18 09:03:57.000000000 +0000
@@ -9,7 +9,6 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/pci/pci_bus_cvlink.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/simulator.h>
--- diff/arch/ia64/sn/io/sn2/bte_error.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/bte_error.c	2004-02-18 09:03:57.000000000 +0000
@@ -12,7 +12,6 @@
 #include <asm/smp.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/sn_private.h>
--- diff/arch/ia64/sn/io/sn2/geo_op.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/geo_op.c	2004-02-18 09:03:57.000000000 +0000
@@ -27,7 +27,6 @@
 #include <asm/hw_irq.h>
 #include <asm/sn/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/io.h>
--- diff/arch/ia64/sn/io/sn2/klconflib.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/klconflib.c	2004-02-18 09:03:57.000000000 +0000
@@ -474,8 +474,6 @@
 	return(0);
 }
 
-#include "asm/sn/sn_private.h"
-
 /*
  * Format a module id for printing.
  *
--- diff/arch/ia64/sn/io/sn2/ml_SN_init.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/ml_SN_init.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,12 +11,12 @@
 #include <linux/bootmem.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/sn_private.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/sn_cpuid.h>
+#include <asm/sn/simulator.h>
 
 int		maxcpus;
 
@@ -69,12 +69,15 @@
 }
 
 void
-init_platform_hubinfo(nodepda_t **nodepdaindr) {
+init_platform_hubinfo(nodepda_t **nodepdaindr)
+{
 	cnodeid_t       cnode;
 	hubinfo_t hubinfo;
 	nodepda_t *npda;
 	extern int numionodes;
 
+	if (IS_RUNNING_ON_SIMULATOR())
+		return;
 	for (cnode = 0; cnode < numionodes; cnode++) {
 		npda = nodepdaindr[cnode];
 		hubinfo = (hubinfo_t)npda->pdinfo;
--- diff/arch/ia64/sn/io/sn2/ml_SN_intr.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/ml_SN_intr.c	2004-02-18 09:03:57.000000000 +0000
@@ -30,6 +30,7 @@
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/sn2/shub_mmr.h>
+#include <asm/sn/pda.h>
 
 extern irqpda_t	*irqpdaindr;
 extern cnodeid_t master_node_get(vertex_hdl_t vhdl);
@@ -216,7 +217,6 @@
 {
 	cpuid_t		cpu, best_cpu = CPU_NONE;
 	int		slice, min_count = 1000;
-	irqpda_t	*irqs;
 
 	for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) {
 		int intrs;
@@ -227,8 +227,7 @@
 		if (!cpu_online(cpu))
 			continue;
 
-		irqs = irqpdaindr;
-		intrs = irqs->num_irq_used;
+		intrs = pdacpu(cpu)->sn_num_irqs;
 
 		if (min_count > intrs) {
 			min_count = intrs;
@@ -243,6 +242,7 @@
 			}
 		}
 	}
+	pdacpu(best_cpu)->sn_num_irqs++;
 	return best_cpu;
 }
 
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2004-02-18 09:03:57.000000000 +0000
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/arch.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
--- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pcibr_private.h>
--- diff/arch/ia64/sn/io/sn2/shub.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/shub.c	2004-02-18 09:03:57.000000000 +0000
@@ -17,7 +17,6 @@
 #include <asm/system.h>
 #include <asm/sn/sgi.h>
 #include <asm/uaccess.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/io.h>
--- diff/arch/ia64/sn/io/sn2/shub_intr.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/shub_intr.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,7 +11,6 @@
 #include <asm/sn/types.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/driver.h>
-#include <asm/sn/iograph.h>
 #include <asm/param.h>
 #include <asm/sn/pio.h>
 #include <asm/sn/xtalk/xwidget.h>
--- diff/arch/ia64/sn/io/sn2/shuberror.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/sn2/shuberror.c	2004-02-18 09:03:57.000000000 +0000
@@ -16,7 +16,6 @@
 #include <asm/delay.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/sn_private.h>
--- diff/arch/ia64/sn/io/xswitch.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/io/xswitch.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,7 +11,6 @@
 #include <asm/errno.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/driver.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/labelcl.h>
 #include <asm/sn/xtalk/xtalk.h>
--- diff/arch/ia64/sn/kernel/irq.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -18,7 +18,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
 #include <asm/sn/hcl.h>
 #include <asm/sn/types.h>
 #include <asm/sn/pci/pciio.h>
@@ -121,7 +120,7 @@
 static void
 sn_set_affinity_irq(unsigned int irq, unsigned long cpu)
 {
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	int redir = 0;
 	struct sn_intr_list_t *p = sn_intr_list[irq];
 	pcibr_intr_t intr;
--- diff/arch/ia64/sn/kernel/setup.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ia64/sn/kernel/setup.c	2004-02-18 09:03:57.000000000 +0000
@@ -85,6 +85,7 @@
 u64 master_node_bedrock_address;
 
 static void sn_init_pdas(char **);
+static void scan_for_ionodes(void);
 
 
 static nodepda_t	*nodepdaindr[MAX_COMPACT_NODES];
@@ -131,7 +132,7 @@
  * may not be initialized yet.
  */
 
-static int
+static int __init
 pxm_to_nasid(int pxm)
 {
 	int i;
@@ -358,11 +359,10 @@
  *
  * One time setup for Node Data Area.  Called by sn_setup().
  */
-void
+void __init
 sn_init_pdas(char **cmdline_p)
 {
 	cnodeid_t	cnode;
-	void scan_for_ionodes(void);
 
 	/*
 	 * Make sure that the PDA fits entirely in the same page as the 
@@ -498,7 +498,7 @@
  * physical_node_map and the pda and increment numionodes.
  */
 
-void
+static void __init
 scan_for_ionodes(void)
 {
 	int nasid = 0;
--- diff/arch/m68k/Kconfig	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/m68k/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -1030,8 +1030,7 @@
 	  precision in some cases.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called genrtc. To load the module automatically
-	  add 'alias char-major-10-135 genrtc' to your /etc/modules.conf
+	  module will be called genrtc.
 
 config GEN_RTC_X
 	bool "Extended RTC operation"
--- diff/arch/m68k/amiga/amiints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/amiga/amiints.c	2004-02-18 09:03:57.000000000 +0000
@@ -49,6 +49,7 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
+#include <asm/unistd.h>
 
 extern int cia_request_irq(struct ciabase *base,int irq,
                            irqreturn_t (*handler)(int, void *, struct pt_regs *),
--- diff/arch/m68k/bvme6000/bvmeints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/bvme6000/bvmeints.c	2004-02-18 09:03:57.000000000 +0000
@@ -20,6 +20,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/unistd.h>
 
 static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
 
--- diff/arch/m68k/hp300/time.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/hp300/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/traps.h>
+#include <asm/unistd.h>
 #include "ints.h"
 
 /* Clock hardware definitions */
--- diff/arch/m68k/kernel/signal.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/m68k/kernel/signal.c	2004-02-18 09:03:57.000000000 +0000
@@ -32,6 +32,7 @@
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
--- diff/arch/m68k/kernel/sys_m68k.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/kernel/sys_m68k.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -156,8 +157,6 @@
 }
 #endif
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
 struct sel_arg_struct {
 	unsigned long n;
 	fd_set *inp, *outp, *exp;
@@ -262,7 +261,7 @@
 	return -EINVAL;
 }
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
 {
   return -ENOSYS;
 }
--- diff/arch/m68k/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/m68k/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -174,6 +174,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/m68k/mac/iop.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/iop.c	2004-02-18 09:03:57.000000000 +0000
@@ -118,6 +118,7 @@
 #include <asm/macints.h> 
 #include <asm/mac_iop.h>
 #include <asm/mac_oss.h>
+#include <asm/unistd.h>
 
 /*#define DEBUG_IOP*/
 
--- diff/arch/m68k/mac/macints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/macints.c	2004-02-18 09:03:57.000000000 +0000
@@ -132,8 +132,8 @@
 #include <asm/mac_psc.h>
 #include <asm/hwtest.h>
 #include <asm/errno.h>
-
 #include <asm/macints.h>
+#include <asm/unistd.h>
 
 #define DEBUG_SPURIOUS
 #define SHUTUP_SONIC
--- diff/arch/m68k/mac/oss.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/oss.c	2004-02-18 09:03:57.000000000 +0000
@@ -26,6 +26,7 @@
 #include <asm/macints.h>
 #include <asm/mac_via.h>
 #include <asm/mac_oss.h>
+#include <asm/unistd.h>
 
 int oss_present;
 volatile struct mac_oss *oss;
--- diff/arch/m68k/mac/psc.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/psc.c	2004-02-18 09:03:57.000000000 +0000
@@ -24,6 +24,7 @@
 #include <asm/macintosh.h> 
 #include <asm/macints.h> 
 #include <asm/mac_psc.h>
+#include <asm/unistd.h>
 
 #define DEBUG_PSC
 
--- diff/arch/m68k/mac/via.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/mac/via.c	2004-02-18 09:03:57.000000000 +0000
@@ -23,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-
 #include <linux/ide.h>
 
 #include <asm/traps.h>
@@ -33,6 +32,7 @@
 #include <asm/machw.h> 
 #include <asm/mac_via.h>
 #include <asm/mac_psc.h>
+#include <asm/unistd.h>
 
 volatile __u8 *via1, *via2;
 #if 0
--- diff/arch/m68k/q40/q40ints.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/m68k/q40/q40ints.c	2004-02-18 09:03:57.000000000 +0000
@@ -26,6 +26,7 @@
 #include <asm/irq.h>
 #include <asm/hardirq.h>
 #include <asm/traps.h>
+#include <asm/unistd.h>
 
 #include <asm/q40_master.h>
 #include <asm/q40ints.h>
--- diff/arch/m68k/sun3/sun3ints.c	2003-06-09 14:18:17.000000000 +0100
+++ source/arch/m68k/sun3/sun3ints.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <asm/intersil.h>
 #include <asm/oplib.h>
 #include <asm/sun3ints.h>
+#include <asm/unistd.h>
 #include <linux/seq_file.h>
 
 extern void sun3_leds (unsigned char);
--- diff/arch/m68knommu/kernel/signal.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/m68knommu/kernel/signal.c	2004-02-18 09:03:57.000000000 +0000
@@ -32,6 +32,7 @@
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
@@ -50,8 +51,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options,
-			struct rusage * ru);
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
 /*
--- diff/arch/m68knommu/kernel/sys_m68k.c	2002-11-11 11:09:42.000000000 +0000
+++ source/arch/m68knommu/kernel/sys_m68k.c	2004-02-18 09:03:57.000000000 +0000
@@ -15,6 +15,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -111,8 +112,6 @@
 	return error;
 }
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
 struct sel_arg_struct {
 	unsigned long n;
 	fd_set *inp, *outp, *exp;
@@ -194,7 +193,7 @@
 	return -EINVAL;
 }
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
 {
   return -ENOSYS;
 }
--- diff/arch/m68knommu/kernel/time.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/m68knommu/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -199,6 +199,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/mips/kernel/ioctl32.c	2003-09-17 12:28:02.000000000 +0100
+++ source/arch/mips/kernel/ioctl32.c	2004-02-18 09:03:57.000000000 +0000
@@ -60,6 +60,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_bonding.h>
+#include <linux/syscalls.h>
 #include <linux/watchdog.h>
 
 #include <asm/ioctls.h>
@@ -94,8 +95,6 @@
 #include <asm/sibyte/trace_prof.h>
 #endif
 
-long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-
 static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t old_fs = get_fs();
--- diff/arch/mips/kernel/irixioctl.c	2003-07-08 09:55:17.000000000 +0100
+++ source/arch/mips/kernel/irixioctl.c	2004-02-18 09:03:57.000000000 +0000
@@ -11,6 +11,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sockios.h>
+#include <linux/syscalls.h>
 #include <linux/tty.h>
 #include <linux/file.h>
 
@@ -26,9 +27,6 @@
 	cc_t c_cc[NCCS];
 };
 
-extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd,
-				unsigned long arg);
-extern asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count);
 extern void start_tty(struct tty_struct *tty);
 static struct tty_struct *get_tty(int fd)
 {
--- diff/arch/mips/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/mips/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -835,7 +835,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -873,7 +873,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/mips/kernel/linux32.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/mips/kernel/linux32.c	2004-02-18 09:03:57.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/icmpv6.h>
+#include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/utime.h>
 #include <linux/utsname.h>
@@ -123,8 +124,6 @@
 }
 
 
-asmlinkage long sys_truncate(const char * path, unsigned long length);
-
 asmlinkage int sys_truncate64(const char *path, unsigned int high,
 			      unsigned int low)
 {
@@ -133,8 +132,6 @@
 	return sys_truncate(path, ((long) high << 32) | low);
 }
 
-asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-
 asmlinkage int sys_ftruncate64(unsigned int fd, unsigned int high,
 			       unsigned int low)
 {
@@ -375,8 +372,6 @@
 	return;
 }
 
-asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count);
-
 asmlinkage long
 sys32_getdents(unsigned int fd, void * dirent32, unsigned int count)
 {
@@ -497,8 +492,6 @@
 	char _f[8];
 };
 
-extern asmlinkage int sys_sysinfo(struct sysinfo *info);
-
 asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
 {
 	struct sysinfo s;
@@ -633,10 +626,6 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-extern asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
-			          unsigned long offset_low, loff_t * result,
-			          unsigned int origin);
-
 asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
 			    unsigned int offset_low, loff_t * result,
 			    unsigned int origin)
@@ -1018,10 +1007,6 @@
 }
 
 
-
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid,
-	struct timespec *interval);
-
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
 	struct compat_timespec *interval)
 {
@@ -1668,9 +1653,6 @@
 
 #endif /* CONFIG_SYSCTL */
 
-extern asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
-					    unsigned long *user_mask_ptr);
-
 asmlinkage int sys32_sched_setaffinity(compat_pid_t pid, unsigned int len,
 				       u32 *user_mask_ptr)
 {
@@ -1692,9 +1674,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
-					    unsigned long *user_mask_ptr);
-
 asmlinkage int sys32_sched_getaffinity(compat_pid_t pid, unsigned int len,
 				       u32 *user_mask_ptr)
 {
@@ -1734,8 +1713,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_personality(unsigned long);
-
 asmlinkage int sys32_personality(unsigned long personality)
 {
 	int ret;
@@ -1820,8 +1797,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
 	s32 count)
 {
@@ -1842,8 +1817,6 @@
 	return ret;
 }
 
-asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
-
 asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
                                    size_t count)
 {
--- diff/arch/mips/kernel/signal32.c	2003-08-20 14:16:36.000000000 +0100
+++ source/arch/mips/kernel/signal32.c	2004-02-18 09:03:57.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
@@ -761,9 +762,6 @@
 	return ret;
 }
 
-asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
-				   size_t sigsetsize);
-
 asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set,
 	compat_sigset_t *oset, unsigned int sigsetsize)
 {
@@ -785,8 +783,6 @@
 	return ret;
 }
 
-asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-
 asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset,
 	unsigned int sigsetsize)
 {
@@ -895,8 +891,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
-
 asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
 {
 	siginfo_t info;
--- diff/arch/mips/kernel/syscall.c	2003-08-20 14:16:25.000000000 +0100
+++ source/arch/mips/kernel/syscall.c	2004-02-18 09:03:57.000000000 +0000
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/syscalls.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/utsname.h>
--- diff/arch/mips/kernel/sysirix.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/mips/kernel/sysirix.c	2004-02-18 09:03:57.000000000 +0000
@@ -29,6 +29,7 @@
 #include <linux/namei.h>
 #include <linux/socket.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
@@ -235,13 +236,6 @@
 #undef DEBUG_PROCGRPS
 
 extern unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt);
-extern asmlinkage int sys_setpgid(pid_t pid, pid_t pgid);
-extern void sys_sync(void);
-extern asmlinkage int sys_getsid(pid_t pid);
-extern asmlinkage long sys_write (unsigned int fd, const char *buf, unsigned long count);
-extern asmlinkage long sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
-extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
-extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
 extern int getrusage(struct task_struct *p, int who, struct rusage *ru);
 extern char *prom_getenv(char *name);
 extern long prom_setenv(char *name, char *value);
@@ -368,7 +362,7 @@
 			retval = HZ;
 			goto out;
 		case 4:
-			retval = NGROUPS;
+			retval = NGROUPS_MAX;
 			goto out;
 		case 5:
 			retval = NR_OPEN;
@@ -694,9 +688,6 @@
 	return -EINTR;
 }
 
-extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
-				unsigned long new_flags, void * data);
-
 /* XXX need more than this... */
 asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags,
 			  char *type, void *data, int datalen)
@@ -792,9 +783,6 @@
 	return error;
 }
 
-extern asmlinkage int sys_setpgid(pid_t pid, pid_t pgid);
-extern asmlinkage int sys_setsid(void);
-
 asmlinkage int irix_setpgrp(int flags)
 {
 	int error;
@@ -883,8 +871,6 @@
 	return -EINVAL;
 }
 
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-
 asmlinkage int irix_socket(int family, int type, int protocol)
 {
 	switch(type) {
@@ -1356,8 +1342,6 @@
 	return error;
 }
 
-extern asmlinkage int sys_mknod(const char * filename, int mode, unsigned dev);
-
 asmlinkage int irix_xmknod(int ver, char *filename, int mode, unsigned dev)
 {
 	int retval;
@@ -1501,9 +1485,6 @@
 	return -EINVAL;
 }
 
-extern asmlinkage int sys_truncate(const char * path, unsigned long length);
-extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
-
 asmlinkage int irix_truncate64(char *name, int pad, int size1, int size2)
 {
 	int retval;
@@ -1532,10 +1513,6 @@
 	return retval;
 }
 
-extern asmlinkage unsigned long
-sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd,
-         off_t offset);
-
 asmlinkage int irix_mmap64(struct pt_regs *regs)
 {
 	int len, prot, flags, fd, off1, off2, error, base = 0;
@@ -2106,9 +2083,6 @@
 
 #undef DEBUG_FCNTL
 
-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd,
-				 unsigned long arg);
-
 #define IRIX_F_ALLOCSP 10
 
 asmlinkage int irix_fcntl(int fd, int cmd, int arg)
--- diff/arch/mips/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/mips/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -132,7 +132,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
-
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/parisc/hpux/ioctl.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/hpux/ioctl.c	2004-02-18 09:03:57.000000000 +0000
@@ -35,13 +35,12 @@
 
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <asm/errno.h>
 #include <asm/ioctl.h>
 #include <asm/termios.h>
 #include <asm/uaccess.h>
 
-int sys_ioctl(unsigned int, unsigned int, unsigned long);
- 
 static int hpux_ioctl_t(int fd, unsigned long cmd, unsigned long arg)
 {
 	int result = -EOPNOTSUPP;
--- diff/arch/parisc/hpux/sys_hpux.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/hpux/sys_hpux.c	2004-02-18 09:03:57.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/utsname.h>
 #include <linux/vmalloc.h>
 #include <linux/vfs.h>
@@ -34,8 +35,6 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 
-unsigned long sys_brk(unsigned long addr);
- 
 unsigned long hpux_brk(unsigned long addr)
 {
 	/* Sigh.  Looks like HP/UX libc relies on kernel bugs. */
@@ -61,7 +60,6 @@
 
 int hpux_wait(int *stat_loc)
 {
-	extern int sys_waitpid(int, int *, int);
 	return sys_waitpid(-1, stat_loc, 0);
 }
 
@@ -213,7 +211,6 @@
 	kfree(kpath);
 
 	/* just fake it, beginning of structures match */
-	extern int sys_statfs(const char *, struct statfs *);
 	error = sys_statfs(path, (struct statfs *) buf);
 
 	/* ignoring rest of statfs struct, but it should be zeros. Need to do 
@@ -269,9 +266,6 @@
 	return error;
 }
 
-int sys_sethostname(char *, int);
-int sys_gethostname(char *, int);
-
 /*  Note: HP-UX just uses the old suser() function to check perms
  *  in this system call.  We'll use capable(CAP_SYS_ADMIN).
  */
--- diff/arch/parisc/kernel/ioctl32.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/ioctl32.c	2004-02-18 09:03:57.000000000 +0000
@@ -8,6 +8,8 @@
  * ioctls.
  */
 
+#include <linux/syscalls.h>
+
 #define INCLUDES
 #include "compat_ioctl.c"
 
--- diff/arch/parisc/kernel/parisc_ksyms.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/parisc_ksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -27,6 +27,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/syscalls.h>
 
 #include <linux/string.h>
 EXPORT_SYMBOL(memchr);
@@ -83,10 +84,6 @@
 EXPORT_SYMBOL(__memset_io);
 
 #include <asm/unistd.h>
-extern long sys_open(const char *, int, int);
-extern off_t sys_lseek(int, off_t, int);
-extern int sys_read(int, char *, int);
-extern int sys_write(int, const char *, int);
 EXPORT_SYMBOL(sys_open);
 EXPORT_SYMBOL(sys_lseek);
 EXPORT_SYMBOL(sys_read);
--- diff/arch/parisc/kernel/signal32.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/signal32.c	2004-02-18 09:03:57.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 
@@ -92,9 +93,6 @@
 int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
 				    unsigned int sigsetsize)
 {
-	extern long sys_rt_sigprocmask(int how,
-				    sigset_t *set, sigset_t *oset,
-				   size_t sigsetsize);
 	sigset_t old_set, new_set;
 	int ret;
 
@@ -115,7 +113,6 @@
 {
 	int ret;
 	sigset_t set;
-	extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
 
 	KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize);
 
--- diff/arch/parisc/kernel/sys_parisc.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/parisc/kernel/sys_parisc.c	2004-02-18 09:03:57.000000000 +0000
@@ -30,6 +30,7 @@
 #include <linux/mman.h>
 #include <linux/shm.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 int sys_pipe(int *fildes)
 {
@@ -182,10 +183,6 @@
 /* Fucking broken ABI */
 
 #ifdef CONFIG_PARISC64
-extern asmlinkage long sys_truncate(const char *, unsigned long);
-extern asmlinkage long sys_ftruncate(unsigned int, unsigned long);
-extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
-
 asmlinkage long parisc_truncate64(const char * path,
 					unsigned int high, unsigned int low)
 {
@@ -214,9 +211,6 @@
 }
 #else
 
-extern asmlinkage long sys_truncate64(const char *, loff_t);
-extern asmlinkage long sys_ftruncate64(unsigned int, loff_t);
-
 asmlinkage long parisc_truncate64(const char * path,
 					unsigned int high, unsigned int low)
 {
@@ -230,12 +224,6 @@
 }
 #endif
 
-extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
-					size_t count, loff_t pos);
-extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
-					size_t count, loff_t pos);
-extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
-
 asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
 					unsigned int high, unsigned int low)
 {
@@ -257,7 +245,7 @@
 /*
  * This changes the io permissions bitmap in the current task.
  */
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
 	return -ENOSYS;
 }
--- diff/arch/parisc/kernel/sys_parisc32.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/sys_parisc32.c	2004-02-18 09:03:57.000000000 +0000
@@ -47,6 +47,7 @@
 #include <linux/vfs.h>
 #include <linux/ptrace.h>
 #include <linux/swap.h>
+#include <linux/syscalls.h>
 
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -357,7 +358,6 @@
 {
 	struct timespec t;
 	int ret;
-	extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
 	
 	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t);
 	if (put_compat_timespec(&t, interval))
@@ -1089,7 +1089,6 @@
 }
 
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
 {
         mm_segment_t old_fs = get_fs();
@@ -1197,7 +1196,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count);
 typedef long __kernel_loff_t32;		/* move this to asm/posix_types.h? */
 
 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count)
@@ -1345,8 +1343,6 @@
  * half of the argument has been zeroed by syscall.S.
  */
 
-extern asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
-
 asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
 {
 	return sys_lseek(fd, offset, origin);
@@ -1367,8 +1363,6 @@
 	return sys_semctl (semid, semnum, cmd, arg);
 }
 
-extern long sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
-
 long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf,
 			  size_t len)
 {
--- diff/arch/parisc/kernel/time.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/parisc/kernel/time.c	2004-02-18 09:03:57.000000000 +0000
@@ -230,6 +230,7 @@
 		time_esterror = NTP_PHASE_LIMIT;
 	}
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 EXPORT_SYMBOL(do_settimeofday);
--- diff/arch/ppc/8260_io/enet.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/ppc/8260_io/enet.c	2004-02-18 09:03:58.000000000 +0000
@@ -851,7 +851,7 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/arch/ppc/8260_io/fcc_enet.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/ppc/8260_io/fcc_enet.c	2004-02-18 09:03:58.000000000 +0000
@@ -1371,7 +1371,7 @@
 
 		err = register_netdev(dev);
 		if (err) {
-			kfree(dev);
+			free_netdev(dev);
 			return err;
 		}
 
--- diff/arch/ppc/8xx_io/enet.c	2003-09-30 15:46:11.000000000 +0100
+++ source/arch/ppc/8xx_io/enet.c	2004-02-18 09:03:58.000000000 +0000
@@ -949,7 +949,7 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/arch/ppc/8xx_io/fec.c	2003-06-30 10:07:19.000000000 +0100
+++ source/arch/ppc/8xx_io/fec.c	2004-02-18 09:03:58.000000000 +0000
@@ -1748,7 +1748,7 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/arch/ppc/boot/ld.script	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/ppc/boot/ld.script	2004-02-18 09:03:58.000000000 +0000
@@ -82,6 +82,7 @@
     *(__ksymtab)
     *(__ksymtab_strings)
     *(__bug_table)
+    *(__kcrctab)
   }
 
 }
--- diff/arch/ppc/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/ppc/kernel/irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -575,7 +575,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -616,7 +616,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/ppc/kernel/setup.c	2004-02-18 08:54:07.000000000 +0000
+++ source/arch/ppc/kernel/setup.c	2004-02-18 09:03:58.000000000 +0000
@@ -53,7 +53,7 @@
 extern void power4_idle(void);
 
 extern boot_infos_t *boot_infos;
-char saved_command_line[256];
+char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 struct ide_machdep_calls ppc_ide_md;
 char *sysmap;
@@ -501,7 +501,7 @@
 		ulong *data = rec->data;
 		switch (rec->tag) {
 		case BI_CMD_LINE:
-			memcpy(cmd_line, (void *)data, rec->size);
+			strlcpy(cmd_line, (void *)data, sizeof(cmd_line));
 			break;
 		case BI_SYSMAP:
 			sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] :
@@ -538,7 +538,7 @@
 	     unsigned long r6, unsigned long r7)
 {
 #ifdef CONFIG_CMDLINE
-	strcpy(cmd_line, CONFIG_CMDLINE);
+	strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
 #endif /* CONFIG_CMDLINE */
 
 #ifdef CONFIG_6xx
@@ -676,7 +676,7 @@
 	init_mm.brk = (unsigned long) klimit;
 
 	/* Save unparsed command line copy for /proc/cmdline */
-	strcpy(saved_command_line, cmd_line);
+	strlcpy(saved_command_line, cmd_line, sizeof(saved_command_line));
 	*cmdline_p = cmd_line;
 
 	/* set up the bootmem stuff with available memory */
--- diff/arch/ppc/kernel/syscalls.c	2004-02-09 10:36:07.000000000 +0000
+++ source/arch/ppc/kernel/syscalls.c	2004-02-18 09:03:58.000000000 +0000
@@ -29,6 +29,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/sys.h>
 #include <linux/ipc.h>
@@ -200,8 +201,6 @@
 	return err;
 }
 
-extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
 /*
  * Due to some executables calling the wrong select we sometimes
  * get wrong args.  This determines how the args are being passed
--- diff/arch/ppc/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/ppc/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -294,6 +294,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irqrestore(&xtime_lock, flags);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/ppc64/kernel/iSeries_irq.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -57,6 +57,7 @@
 
 void iSeries_init_irq_desc(irq_desc_t *desc)
 {
+	desc->handler = &iSeries_IRQ_handler;
 }
 
 /* This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c */
@@ -87,22 +88,6 @@
 #define IRQ_TO_IDSEL(irq)	(((((irq) - 1) >> 3) & 7) + 1)
 #define IRQ_TO_FUNC(irq)	(((irq) - 1) & 7)
 
-/*
- * This is called out of iSeries_scan_slot to assign the EADS slot
- * to its IRQ number
- */
-int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber,
-		HvSubBusNumber subBusNumber, HvAgentId deviceId)
-{
-	irq_desc_t *desc = get_real_irq_desc(irq);
-
-	if (desc == NULL)
-		return -1;
-	desc->handler = &iSeries_IRQ_handler;
-	return 0;
-}
-
-
 /* This is called by iSeries_activate_IRQs */
 static unsigned int iSeries_startup_IRQ(unsigned int irq)
 {
@@ -125,6 +110,11 @@
 }
 
 /*
+ * Temporary hack
+ */
+#define get_irq_desc(irq)	&irq_desc[(irq)]
+
+/*
  * This is called out of iSeries_fixup to activate interrupt
  * generation for usable slots
  */
--- diff/arch/ppc64/kernel/iSeries_pci.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_pci.c	2004-02-18 09:03:57.000000000 +0000
@@ -406,7 +406,6 @@
 
 	/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
   	Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
-	iSeries_assign_IRQ(Irq, Bus, 0, EADsIdSel);
 	PPCDBG(PPCDBG_BUSWALK,
 		"PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",
 		Bus, 0, EADsIdSel, Irq);
--- diff/arch/ppc64/kernel/iSeries_setup.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/iSeries_setup.c	2004-02-18 09:03:57.000000000 +0000
@@ -315,7 +315,6 @@
 	ppc_md.setup_residual = iSeries_setup_residual;
 	ppc_md.get_cpuinfo = iSeries_get_cpuinfo;
 	ppc_md.init_IRQ = iSeries_init_IRQ;
-	ppc_md.init_irq_desc = iSeries_init_irq_desc;
 	ppc_md.get_irq = iSeries_get_irq;
 	ppc_md.init = NULL;
 
--- diff/arch/ppc64/kernel/ioctl32.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/ppc64/kernel/ioctl32.c	2004-02-18 09:03:57.000000000 +0000
@@ -23,6 +23,7 @@
 #define INCLUDES
 #include "compat_ioctl.c"
 #include <linux/ncp_fs.h>
+#include <linux/syscalls.h>
 #include <asm/ppc32.h>
 
 #define CODE
--- diff/arch/ppc64/kernel/irq.c	2004-02-09 10:36:08.000000000 +0000
+++ source/arch/ppc64/kernel/irq.c	2004-02-18 09:03:57.000000000 +0000
@@ -664,7 +664,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -702,7 +702,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/ppc64/kernel/lparcfg.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/lparcfg.c	2004-02-18 09:03:57.000000000 +0000
@@ -134,7 +134,7 @@
 	memset(buf, 0, size); 
 
 	shared = (int)(lpaca->xLpPacaPtr->xSharedProc);
-	n += snprintf(buf, LPARCFG_BUFF_SIZE - n,
+	n += scnprintf(buf, LPARCFG_BUFF_SIZE - n,
 		      "serial_number=%c%c%c%c%c%c%c\n", 
 		      e2a(xItExtVpdPanel.mfgID[2]),
 		      e2a(xItExtVpdPanel.mfgID[3]),
@@ -144,7 +144,7 @@
 		      e2a(xItExtVpdPanel.systemSerial[4]),
 		      e2a(xItExtVpdPanel.systemSerial[5])); 
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "system_type=%c%c%c%c\n",
 		      e2a(xItExtVpdPanel.machineType[0]),
 		      e2a(xItExtVpdPanel.machineType[1]),
@@ -152,23 +152,23 @@
 		      e2a(xItExtVpdPanel.machineType[3])); 
 
 	lp_index = HvLpConfig_getLpIndex(); 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_id=%d\n", (int)lp_index); 
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "system_active_processors=%d\n", 
 		      (int)HvLpConfig_getSystemPhysicalProcessors()); 
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "system_potential_processors=%d\n", 
 		      (int)HvLpConfig_getSystemPhysicalProcessors()); 
 
 	processors = (int)HvLpConfig_getPhysicalProcessors(); 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_active_processors=%d\n", processors);  
 
 	max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_potential_processors=%d\n", max_processors);  
 
 	if(shared) {
@@ -178,22 +178,22 @@
 		entitled_capacity = processors * 100; 
 		max_entitled_capacity = max_processors * 100; 
 	}
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_entitled_capacity=%d\n", entitled_capacity);
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_max_entitled_capacity=%d\n", 
 		      max_entitled_capacity);
 
 	if(shared) {
 		pool_id = HvLpConfig_getSharedPoolIndex(); 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, "pool=%d\n", 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "pool=%d\n",
 			      (int)pool_id); 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "pool_capacity=%d\n", (int)(HvLpConfig_getNumProcsInSharedPool(pool_id)*100)); 
 	}
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "shared_processor_mode=%d\n", shared);
 
 	return 0;
@@ -297,13 +297,13 @@
 		if(lp_index_ptr) lp_index = *lp_index_ptr;
 	}
 
-	n  = snprintf(buf, LPARCFG_BUFF_SIZE - n,
+	n  = scnprintf(buf, LPARCFG_BUFF_SIZE - n,
 		      "serial_number=%s\n", system_id); 
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "system_type=%s\n", model); 
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_id=%d\n", (int)lp_index); 
 
 	rtas_node = find_path_device("/rtas");
@@ -317,74 +317,74 @@
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
 		h_get_ppp(&h_entitled,&h_unallocated,&h_aggregation,&h_resource);
 #ifdef DEBUG
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "R4=0x%lx\n", h_entitled);
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "R5=0x%lx\n", h_unallocated);
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "R6=0x%lx\n", h_aggregation);
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "R7=0x%lx\n", h_resource);
 #endif /* DEBUG */
 	}
 
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
 		system_potential_processors =  get_splpar_potential_characteristics();
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "system_active_processors=%ld\n", 
 			      (h_resource >> 2*8) & 0xffff);
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "system_potential_processors=%d\n", 
 			      system_potential_processors);
 	} else {
 		system_potential_processors = system_active_processors;
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "system_active_processors=%d\n", 
 			      system_active_processors);
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "system_potential_processors=%d\n", 
 			      system_potential_processors);
 	}
 
 	processors = systemcfg->processorCount;
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_active_processors=%d\n", processors);  
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_potential_processors=%d\n",
 		      system_active_processors);
 
 	/* max_entitled_capacity will come out of get_splpar_potential_characteristics() when that function is complete */
 	max_entitled_capacity = system_active_processors * 100; 
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "partition_entitled_capacity=%ld\n", h_entitled);
 	} else {
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "partition_entitled_capacity=%d\n", system_active_processors*100);
 	}
 
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "partition_max_entitled_capacity=%d\n", 
 		      max_entitled_capacity);
 
 	shared = 0;
-	n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+	n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 		      "shared_processor_mode=%d\n", shared);
 
 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "pool=%ld\n", (h_aggregation >> 0*8)&0xffff);
 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "pool_capacity=%ld\n", (h_resource >> 3*8) &0xffff);
 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "group=%ld\n", (h_aggregation >> 2*8)&0xffff);
 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "capped=%ld\n", (h_resource >> 6*8)&0x40);
 
-		n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, 
+		n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n,
 			      "capacity_weight=%d\n", (int)(h_resource>>5*8)&0xFF);
 	}
 	return 0;
--- diff/arch/ppc64/kernel/ppc_ksyms.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/ppc_ksyms.c	2004-02-18 09:03:57.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 #include <asm/page.h>
 #include <asm/semaphore.h>
@@ -48,7 +49,6 @@
 #include <asm/iSeries/HvLpConfig.h>
 #endif
 
-extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
 int abs(int);
--- diff/arch/ppc64/kernel/prom.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/prom.c	2004-02-18 09:03:57.000000000 +0000
@@ -186,12 +186,13 @@
 
 extern char cmd_line[512];	/* XXX */
 unsigned long dev_tree_size;
+unsigned long _get_PIR(void);
 
 #ifdef CONFIG_HMT
 struct {
 	unsigned int pir;
 	unsigned int threadid;
-} hmt_thread_data[NR_CPUS] = {0};
+} hmt_thread_data[NR_CPUS];
 #endif /* CONFIG_HMT */
 
 char testString[] = "LINUX\n"; 
--- diff/arch/ppc64/kernel/rtas-proc.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/rtas-proc.c	2004-02-18 09:03:57.000000000 +0000
@@ -287,9 +287,9 @@
 	char stkbuf[40];  /* its small, its on stack */
 	int n, sn;
 	if (power_on_time == 0)
-		n = snprintf(stkbuf, 40, "Power on time not set\n");
+		n = scnprintf(stkbuf,sizeof(stkbuf),"Power on time not set\n");
 	else
-		n = snprintf(stkbuf, 40, "%lu\n", power_on_time);
+		n = scnprintf(stkbuf,sizeof(stkbuf),"%lu\n",power_on_time);
 
 	sn = strlen (stkbuf) +1;
 	if (*ppos >= sn)
@@ -410,9 +410,10 @@
 	if (error != 0){
 		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
 				ppc_rtas_process_error(error));
-		n = snprintf (stkbuf, 40, "0");
+		n = scnprintf (stkbuf, sizeof(stkbuf), "0");
 	} else { 
-		n = snprintf (stkbuf, 40, "%lu\n", mktime(year, mon, day, hour, min, sec));
+		n = scnprintf (stkbuf, sizeof(stkbuf), "%lu\n",
+				mktime(year, mon, day, hour, min, sec));
 	}
 	kfree(ret);
 
@@ -819,7 +820,7 @@
 		n += check_location_string(ret, buffer + n);
 		n += sprintf ( buffer+n, " ");
 		/* see how many characters we have printed */
-		snprintf ( t, 50, "%s ", ret);
+		scnprintf(t, sizeof(t), "%s ", ret);
 
 		pos += strlen(t);
 		if (pos >= llen) pos=0;
@@ -863,7 +864,7 @@
 	int n, sn;
 	char stkbuf[40];  /* its small, its on stack */
 
-	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency);
+	n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency);
 
 	sn = strlen (stkbuf) +1;
 	if (*ppos >= sn)
@@ -917,7 +918,7 @@
 	int n, sn;
 	char stkbuf[40];  /* its small, its on stack */
 
-	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume);
+	n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_volume);
 
 	sn = strlen (stkbuf) +1;
 	if (*ppos >= sn)
--- diff/arch/ppc64/kernel/rtasd.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/rtasd.c	2004-02-18 09:03:57.000000000 +0000
@@ -336,8 +336,6 @@
 	return 0;
 }
 
-extern long sys_sched_get_priority_max(int policy);
-
 static int rtasd(void *unused)
 {
 	unsigned int err_type;
--- diff/arch/ppc64/kernel/setup.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/setup.c	2004-02-18 09:03:57.000000000 +0000
@@ -80,7 +80,7 @@
 
 int powersave_nap;
 
-char saved_command_line[256];
+char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 
 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
@@ -536,7 +536,7 @@
 	for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) {
 		switch (rec->tag) {
 		case BI_CMD_LINE:
-			memcpy(cmd_line, (void *)rec->data, rec->size);
+			strlcpy(cmd_line, (void *)rec->data, sizeof(cmd_line));
 			break;
 		case BI_SYSMAP:
 			sysmap = __va(rec->data[0]);
@@ -620,7 +620,7 @@
 	init_mm.brk = klimit;
 	
 	/* Save unparsed command line copy for /proc/cmdline */
-	strcpy(saved_command_line, cmd_line);
+	strlcpy(saved_command_line, cmd_line, sizeof(saved_command_line));
 	*cmdline_p = cmd_line;
 
 	/* set up the bootmem stuff with available memory */
--- diff/arch/ppc64/kernel/signal32.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/ppc64/kernel/signal32.c	2004-02-18 09:03:58.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/errno.h>
 #include <linux/elf.h>
 #include <linux/compat.h>
--- diff/arch/ppc64/kernel/sys_ppc32.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/sys_ppc32.c	2004-02-18 09:03:58.000000000 +0000
@@ -54,6 +54,8 @@
 #include <linux/ipv6.h>
 #include <linux/in.h>
 #include <linux/icmpv6.h>
+#include <linux/syscalls.h>
+#include <linux/unistd.h>
 #include <linux/sysctl.h>
 #include <linux/binfmts.h>
 #include <linux/dnotify.h>
@@ -65,6 +67,7 @@
 #include <asm/types.h>
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include <asm/semaphore.h>
 
@@ -778,8 +781,6 @@
 	return err;
 }
 
-extern asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
-
 /* Note: it is necessary to treat option as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -1155,8 +1156,6 @@
 	char _f[20-2*sizeof(int)-sizeof(int)];
 };
 
-extern asmlinkage long sys_sysinfo(struct sysinfo *info);
-
 asmlinkage long sys32_sysinfo(struct sysinfo32 *info)
 {
 	struct sysinfo s;
@@ -1868,8 +1867,6 @@
 	return err;
 }
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
-
 /* Note: it is necessary to treat out_fd and in_fd as unsigned ints, 
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -1894,8 +1891,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2158,9 +2153,6 @@
 #endif /* CONFIG_ALTIVEC */
 }
 
-extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
-				unsigned long arg4, unsigned long arg5);
-
 /* Note: it is necessary to treat option as an unsigned int, 
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2175,14 +2167,12 @@
 			 (unsigned long) arg5);
 }
 
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
-
 /* Note: it is necessary to treat pid as an unsigned int, 
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
  * and the register representation of a signed int (msr in 64-bit mode) is performed.
  */
-asmlinkage int sys32_sched_rr_get_interval(u32 pid, struct compat_timespec *interval)
+asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec *interval)
 {
 	struct timespec t;
 	int ret;
@@ -2196,9 +2186,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off,
-					 unsigned long len, unsigned char *buf);
-
 asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
 	return sys_pciconfig_read((unsigned long) bus,
@@ -2208,12 +2195,6 @@
 				  (unsigned char *)AA(ubuf));
 }
 
-
-
-
-extern asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off,
-					  unsigned long len, unsigned char *buf);
-
 asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
 	return sys_pciconfig_write((unsigned long) bus,
@@ -2281,8 +2262,6 @@
 }
 
 
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-
 asmlinkage int ppc64_newuname(struct new_utsname * name)
 {
 	int errno = sys_newuname(name);
@@ -2295,8 +2274,6 @@
 	return errno;
 }
 
-extern asmlinkage long sys_personality(unsigned long);
-
 asmlinkage int ppc64_personality(unsigned long personality)
 {
 	int ret;
@@ -2310,8 +2287,6 @@
 
 
 
-extern asmlinkage long sys_access(const char * filename, int mode);
-
 /* Note: it is necessary to treat mode as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2323,8 +2298,6 @@
 }
 
 
-extern asmlinkage long sys_creat(const char * pathname, int mode);
-
 /* Note: it is necessary to treat mode as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2336,8 +2309,6 @@
 }
 
 
-extern asmlinkage long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
-
 /* Note: it is necessary to treat pid and options as unsigned ints,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2349,8 +2320,6 @@
 }
 
 
-extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
-
 /* Note: it is necessary to treat gidsetsize as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2362,8 +2331,6 @@
 }
 
 
-extern asmlinkage long sys_getpgid(pid_t pid);
-
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2375,8 +2342,6 @@
 }
 
 
-extern asmlinkage long sys_getpriority(int which, int who);
-
 /* Note: it is necessary to treat which and who as unsigned ints,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2388,8 +2353,6 @@
 }
 
 
-extern asmlinkage long sys_getsid(pid_t pid);
-
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2400,7 +2363,6 @@
 	return sys_getsid((int)pid);
 }
 
-extern asmlinkage long sys_kill(int pid, int sig);
 
 /* Note: it is necessary to treat pid and sig as unsigned ints,
  * with the corresponding cast to a signed int to insure that the 
@@ -2413,8 +2375,6 @@
 }
 
 
-extern asmlinkage long sys_mkdir(const char * pathname, int mode);
-
 /* Note: it is necessary to treat mode as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2425,16 +2385,12 @@
 	return sys_mkdir(pathname, (int)mode);
 }
 
-extern asmlinkage long sys_nice(int increment);
-
 long sys32_nice(u32 increment)
 {
 	/* sign extend increment */
 	return sys_nice((int)increment);
 }
 
-extern off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
-
 off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
 {
 	/* sign extend n */
@@ -2472,8 +2428,6 @@
 	goto out;
 }
 
-extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
-
 /* Note: it is necessary to treat bufsiz as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2484,8 +2438,6 @@
 	return sys_readlink(path, buf, (int)bufsiz);
 }
 
-extern asmlinkage long sys_sched_get_priority_max(int policy);
-
 /* Note: it is necessary to treat option as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2497,8 +2449,6 @@
 }
 
 
-extern asmlinkage long sys_sched_get_priority_min(int policy);
-
 /* Note: it is necessary to treat policy as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2510,8 +2460,6 @@
 }
 
 
-extern asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param);
-
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2523,8 +2471,6 @@
 }
 
 
-extern asmlinkage long sys_sched_getscheduler(pid_t pid);
-
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2536,8 +2482,6 @@
 }
 
 
-extern asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param *param);
-
 /* Note: it is necessary to treat pid as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2549,8 +2493,6 @@
 }
 
 
-extern asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
-
 /* Note: it is necessary to treat pid and policy as unsigned ints,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2562,8 +2504,6 @@
 }
 
 
-extern asmlinkage long sys_setdomainname(char *name, int len);
-
 /* Note: it is necessary to treat len as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2575,8 +2515,6 @@
 }
 
 
-extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist);
-
 /* Note: it is necessary to treat gidsetsize as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2588,8 +2526,6 @@
 }
 
 
-extern asmlinkage long sys_sethostname(char *name, int len);
-
 asmlinkage long sys32_sethostname(char *name, u32 len)
 {
 	/* sign extend len */
@@ -2597,8 +2533,6 @@
 }
 
 
-extern asmlinkage long sys_setpgid(pid_t pid, pid_t pgid);
-
 /* Note: it is necessary to treat pid and pgid as unsigned ints,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2610,16 +2544,12 @@
 }
 
 
-extern asmlinkage long sys_setpriority(int which, int who, int niceval);
-
 long sys32_setpriority(u32 which, u32 who, u32 niceval)
 {
 	/* sign extend which, who and niceval */
 	return sys_setpriority((int)which, (int)who, (int)niceval);
 }
 
-extern asmlinkage long sys_ssetmask(int newmask);
-
 /* Note: it is necessary to treat newmask as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2630,8 +2560,6 @@
 	return sys_ssetmask((int) newmask);
 }
 
-extern asmlinkage long sys_syslog(int type, char * buf, int len);
-
 long sys32_syslog(u32 type, char * buf, u32 len)
 {
 	/* sign extend len */
@@ -2639,8 +2567,6 @@
 }
 
 
-extern asmlinkage long sys_umask(int mask);
-
 /* Note: it is necessary to treat mask as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2652,8 +2578,6 @@
 }
 
 
-extern asmlinkage long sys_umount(char * name, int flags);
-
 /* Note: it is necessary to treat flags as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -2756,10 +2680,6 @@
 	return error;
 }
 
-extern unsigned long sys_mmap(unsigned long addr, size_t len,
-			      unsigned long prot, unsigned long flags,
-			      unsigned long fd, off_t offset);
-
 unsigned long sys32_mmap2(unsigned long addr, size_t len,
 			  unsigned long prot, unsigned long flags,
 			  unsigned long fd, unsigned long pgoff)
@@ -2801,8 +2721,6 @@
 	return ret;
 }
 
-extern long sys_tgkill(int tgid, int pid, int sig);
-
 long sys32_tgkill(u32 tgid, u32 pid, int sig)
 {
 	/* sign extend tgid, pid */
@@ -2813,11 +2731,6 @@
  * long long munging:
  * The 32 bit ABI passes long longs in an odd even register pair.
  */
-extern ssize_t sys_pread64(unsigned int fd, char *buf, size_t count,
-			   loff_t pos);
-
-extern ssize_t sys_pwrite64(unsigned int fd, const char *buf, size_t count,
-			    loff_t pos);
 
 compat_ssize_t sys32_pread64(unsigned int fd, char *ubuf, compat_size_t count,
 			     u32 reg6, u32 poshi, u32 poslo)
@@ -2831,16 +2744,11 @@
 	return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
 }
 
-extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
-
 compat_ssize_t sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
 {
 	return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count);
 }
 
-extern asmlinkage long sys_truncate(const char * path, unsigned long length);
-extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-
 asmlinkage int sys32_truncate64(const char * path, u32 reg4,
 				unsigned long high, unsigned long low)
 {
@@ -2853,8 +2761,6 @@
 	return sys_ftruncate(fd, (high << 32) | low);
 }
 
-extern long sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
-
 long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf,
 			  size_t len)
 {
@@ -2862,8 +2768,6 @@
 				  buf, len);
 }
 
-extern int sys_fadvise64(int fd, loff_t offset, size_t len, int advice);
-
 long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low,
 		     size_t len, int advice)
 {
--- diff/arch/ppc64/kernel/syscalls.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/ppc64/kernel/syscalls.c	2004-02-18 09:03:58.000000000 +0000
@@ -22,6 +22,7 @@
 
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
--- diff/arch/ppc64/kernel/time.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/ppc64/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -418,6 +418,7 @@
 	}
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/s390/kernel/compat_linux.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/compat_linux.c	2004-02-18 09:03:58.000000000 +0000
@@ -55,6 +55,7 @@
 #include <linux/ipv6.h>
 #include <linux/in.h>
 #include <linux/icmpv6.h>
+#include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/binfmts.h>
 #include <linux/compat.h>
@@ -71,17 +72,6 @@
 
 #include "compat_linux.h"
 
-extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
-extern asmlinkage long sys_setregid(gid_t, gid_t);
-extern asmlinkage long sys_setgid(gid_t);
-extern asmlinkage long sys_setreuid(uid_t, uid_t);
-extern asmlinkage long sys_setuid(uid_t);
-extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);
-extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);
-extern asmlinkage long sys_setfsuid(uid_t);
-extern asmlinkage long sys_setfsgid(gid_t);
  
 /* For this source file, we want overflow handling. */
 
@@ -190,40 +180,81 @@
 	return sys_setfsgid((gid_t)gid);
 }
 
+static int groups16_to_user(u16 *grouplist, struct group_info *group_info)
+{
+	int i;
+	u16 group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		group = (u16)GROUP_AT(group_info, i);
+		if (put_user(group, grouplist+i))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int groups16_from_user(struct group_info *group_info, u16 *grouplist)
+{
+	int i;
+	u16 group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		if (get_user(group, grouplist+i))
+			return  -EFAULT;
+		GROUP_AT(group_info, i) = (gid_t)group;
+	}
+
+	return 0;
+}
+
 asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist)
 {
-	u16 groups[NGROUPS];
-	int i,j;
+	int i;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+
+	get_group_info(current->group_info);
+	i = current->group_info->ngroups;
 	if (gidsetsize) {
-		if (i > gidsetsize)
-			return -EINVAL;
-		for(j=0;j<i;j++)
-			groups[j] = current->groups[j];
-		if (copy_to_user(grouplist, groups, sizeof(u16)*i))
-			return -EFAULT;
+		if (i > gidsetsize) {
+			i = -EINVAL;
+			goto out;
+		}
+		if (groups16_to_user(grouplist, current->group_info)) {
+			i = -EFAULT;
+			goto out;
+		}
 	}
+out:
+	put_group_info(current->group_info);
 	return i;
 }
 
 asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist)
 {
-	u16 groups[NGROUPS];
-	int i;
+	struct group_info *group_info;
+	int retval;
 
 	if (!capable(CAP_SETGID))
 		return -EPERM;
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned)gidsetsize > NGROUPS_MAX)
 		return -EINVAL;
-	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16)))
-		return -EFAULT;
-	for (i = 0 ; i < gidsetsize ; i++)
-		current->groups[i] = (gid_t)groups[i];
-	current->ngroups = gidsetsize;
-	return 0;
+
+	group_info = groups_alloc(gidsetsize);
+	if (!group_info)
+		return -ENOMEM;
+	retval = groups16_from_user(group_info, grouplist);
+	if (retval) {
+		put_group_info(group_info);
+		return retval;
+	}
+
+	retval = set_current_groups(group_info);
+	put_group_info(group_info);
+
+	return retval;
 }
 
 asmlinkage long sys32_getuid16(void)
@@ -884,9 +915,6 @@
 	return err;
 }
 
-extern asmlinkage long sys_truncate(const char * path, unsigned long length);
-extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-
 asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
 {
 	if ((int)high < 0)
@@ -1356,8 +1384,6 @@
 	return err;
 }
 
-extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
-
 asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
 {
 	return sys_sysfs(option, arg1, arg2);
@@ -1531,9 +1557,7 @@
         char _f[8];
 };
 
-extern asmlinkage int sys_sysinfo(struct sysinfo *info);
-
-asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
 {
 	struct sysinfo s;
 	int ret, err;
@@ -1561,10 +1585,8 @@
 	return ret;
 }
 
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
-
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
-		struct compat_timespec *interval)
+				struct compat_timespec __user *interval)
 {
 	struct timespec t;
 	int ret;
@@ -1578,9 +1600,8 @@
 	return ret;
 }
 
-extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);
-
-asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset, compat_size_t sigsetsize)
+asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
+			compat_sigset_t __user *oset, compat_size_t sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -1614,9 +1635,8 @@
 	return 0;
 }
 
-extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-
-asmlinkage int sys32_rt_sigpending(compat_sigset_t *set, compat_size_t sigsetsize)
+asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *set,
+				compat_size_t sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -1723,11 +1743,8 @@
 	return ret;
 }
 
-extern asmlinkage int
-sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
-
 asmlinkage int
-sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
+sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo)
 {
 	siginfo_t info;
 	int ret;
@@ -1956,40 +1973,30 @@
 
 #ifdef CONFIG_MODULES
 
-extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user);
-
-/* Hey, when you're trying to init module, take time and prepare us a nice 64bit
- * module structure, even if from 32bit modutils... Why to pollute kernel... :))
- */
-asmlinkage int sys32_init_module(const char *name_user, struct module *mod_user)
+asmlinkage int
+sys32_init_module(void __user *umod, unsigned long len,
+		const char __user *uargs)
 {
-	return sys_init_module(name_user, mod_user);
+	return sys_init_module(umod, len, uargs);
 }
 
-extern asmlinkage int sys_delete_module(const char *name_user);
-
-asmlinkage int sys32_delete_module(const char *name_user)
+asmlinkage int
+sys32_delete_module(const char __user *name_user, unsigned int flags)
 {
-	return sys_delete_module(name_user);
+	return sys_delete_module(name_user, flags);
 }
 
-struct module_info32 {
-	u32 addr;
-	u32 size;
-	u32 flags;
-	s32 usecount;
-};
-
 #else /* CONFIG_MODULES */
 
 asmlinkage int
-sys32_init_module(const char *name_user, struct module *mod_user)
+sys32_init_module(void __user *umod, unsigned long len,
+		const char __user *uargs)
 {
 	return -ENOSYS;
 }
 
 asmlinkage int
-sys32_delete_module(const char *name_user)
+sys32_delete_module(const char __user *name_user, unsigned int flags)
 {
 	return -ENOSYS;
 }
@@ -2153,10 +2160,6 @@
 	return copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0;
 }
 
-/*
-asmlinkage long sys_ni_syscall(void); 
-*/
-
 int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
 	struct nfsctl_arg *karg = NULL;
@@ -2271,9 +2274,8 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-asmlinkage int sys_utimes(char *, struct timeval *);
-
-asmlinkage int sys32_utimes(char *filename, struct compat_timeval *tvs)
+asmlinkage int sys32_utimes(char __user *filename,
+			struct compat_timeval __user *tvs)
 {
 	char *kfilename;
 	struct timeval ktvs[2];
@@ -2307,8 +2309,6 @@
 	return -ERESTARTNOHAND;
 }
 
-extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
-				unsigned long arg4, unsigned long arg5);
 
 asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
 {
@@ -2320,12 +2320,6 @@
 }
 
 
-extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
-				    size_t count, loff_t pos);
-
-extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
-				     size_t count, loff_t pos);
-
 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, char *ubuf,
 				 compat_size_t count, u32 poshi, u32 poslo)
 {
@@ -2342,15 +2336,11 @@
 	return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
-
 asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
 {
 	return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
 }
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2370,9 +2360,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, 
-					 loff_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, 
 				compat_loff_t *offset, s32 count)
 {
@@ -2466,8 +2453,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_setpriority(int which, int who, int niceval);
-
 asmlinkage int sys_setpriority32(u32 which, u32 who, u32 niceval)
 {
 	return sys_setpriority((int) which,
@@ -2485,7 +2470,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;
@@ -2677,8 +2662,6 @@
 	return error;
 }
 
-asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
-
 asmlinkage compat_ssize_t sys32_read(unsigned int fd, char * buf, size_t count)
 {
 	if ((compat_ssize_t) count < 0)
@@ -2687,8 +2670,6 @@
 	return sys_read(fd, buf, count);
 }
 
-asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
-
 asmlinkage compat_ssize_t sys32_write(unsigned int fd, char * buf, size_t count)
 {
 	if ((compat_ssize_t) count < 0)
--- diff/arch/s390/kernel/compat_linux.h	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/compat_linux.h	2004-02-18 09:03:58.000000000 +0000
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/compat.h>
 #include <linux/socket.h>
+#include <linux/syscalls.h>
 #include <linux/nfs_fs.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
--- diff/arch/s390/kernel/compat_wrapper.S	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/compat_wrapper.S	2004-02-18 09:03:58.000000000 +0000
@@ -567,13 +567,15 @@
 
 	.globl  sys32_init_module_wrapper 
 sys32_init_module_wrapper:
-	llgtr	%r2,%r2			# const char *
-	llgtr	%r3,%r3			# struct module *
+	llgtr	%r2,%r2			# void *
+	llgfr	%r3,%r3			# unsigned long
+	llgtr	%r4,%r4			# char *
 	jg	sys32_init_module	# branch to system call
 
 	.globl  sys32_delete_module_wrapper 
 sys32_delete_module_wrapper:
 	llgtr	%r2,%r2			# const char *
+	llgfr	%r3,%r3			# unsigned int
 	jg	sys32_delete_module	# branch to system call
 
 	.globl  sys32_quotactl_wrapper 
--- diff/arch/s390/kernel/s390_ksyms.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/s390_ksyms.c	2004-02-18 09:03:58.000000000 +0000
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/syscalls.h>
 #include <linux/interrupt.h>
 #include <linux/ioctl32.h>
 #include <asm/checksum.h>
--- diff/arch/s390/kernel/sys_s390.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/s390/kernel/sys_s390.c	2004-02-18 09:03:58.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -125,8 +126,6 @@
 	return error;
 }
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
 #ifndef CONFIG_ARCH_S390X
 struct sel_arg_struct {
 	unsigned long n;
@@ -290,15 +289,13 @@
 	return error;
 }
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
 {
 	return -ENOSYS;
 }
 
 #else /* CONFIG_ARCH_S390X */
 
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-
 asmlinkage int s390x_newuname(struct new_utsname * name)
 {
 	int ret = sys_newuname(name);
@@ -310,8 +307,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_personality(unsigned long);
-
 asmlinkage int s390x_personality(unsigned long personality)
 {
 	int ret;
@@ -331,8 +326,6 @@
  */
 #ifndef CONFIG_ARCH_S390X
 
-extern asmlinkage long sys_fadvise64(int, loff_t, size_t, int);
-
 asmlinkage long
 s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice)
 {
@@ -342,8 +335,6 @@
 
 #endif
 
-extern asmlinkage long sys_fadvise64_64(int, loff_t, loff_t, int);
-
 struct fadvise64_64_args {
 	int fd;
 	long long offset;
--- diff/arch/s390/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/s390/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -142,6 +142,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/sh/kernel/sys_sh.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/sh/kernel/sys_sh.c	2004-02-18 09:03:58.000000000 +0000
@@ -17,6 +17,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
@@ -240,16 +241,12 @@
 asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
 			     size_t count, long dummy, loff_t pos)
 {
-	extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
-					size_t count, loff_t pos);
 	return sys_pread64(fd, buf, count, pos);
 }
 
 asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
 			      size_t count, long dummy, loff_t pos)
 {
-	extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
-					size_t count, loff_t pos);
 	return sys_pwrite64(fd, buf, count, pos);
 }
 
--- diff/arch/sparc/kernel/setup.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/sparc/kernel/setup.c	2004-02-18 09:03:58.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/syscalls.h>
 #include <linux/kdev_t.h>
 #include <linux/major.h>
 #include <linux/string.h>
@@ -66,7 +67,6 @@
 
 extern unsigned long trapbase;
 void (*prom_palette)(int);
-asmlinkage void sys_sync(void);	/* it's really int */
 
 /* Pretty sick eh? */
 void prom_sync_me(void)
--- diff/arch/sparc/kernel/sunos_ioctl.c	2002-10-16 04:27:53.000000000 +0100
+++ source/arch/sparc/kernel/sunos_ioctl.c	2004-02-18 09:03:58.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/file.h>
 #include <asm/kbio.h>
 
@@ -32,7 +33,6 @@
 /* NR_OPEN is now larger and dynamic in recent kernels. */
 #define SUNOS_NR_OPEN	256
 
-extern asmlinkage int sys_ioctl(unsigned int, unsigned int, unsigned long);
 extern asmlinkage int sys_setsid(void);
 
 asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
--- diff/arch/sparc/kernel/sys_sparc.c	2003-07-22 18:54:27.000000000 +0100
+++ source/arch/sparc/kernel/sys_sparc.c	2004-02-18 09:03:58.000000000 +0000
@@ -16,6 +16,7 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/utsname.h>
 #include <linux/smp.h>
@@ -78,8 +79,6 @@
 	}
 }
 
-extern asmlinkage unsigned long sys_brk(unsigned long brk);
-
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
 	if(ARCH_SUN4C_SUN4) {
--- diff/arch/sparc/kernel/sys_sunos.c	2003-09-17 12:28:03.000000000 +0100
+++ source/arch/sparc/kernel/sys_sunos.c	2004-02-18 09:03:58.000000000 +0000
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 #include <net/sock.h>
 
@@ -564,8 +565,6 @@
 }
 
 /* SunOS mount system call emulation */
-extern asmlinkage int
-sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
 
 asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
@@ -621,11 +620,6 @@
 };
 
 
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-
-
 /* Bind the socket on a local reserved port and connect it to the
  * remote server.  This on Linux/i386 is done by the mount program,
  * not by the kernel.
@@ -814,8 +808,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_setsid(void);
-extern asmlinkage int sys_setpgid(pid_t, pid_t);
 
 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
 {
@@ -1050,15 +1042,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_read(unsigned int fd,char *buf,int count);
-extern asmlinkage ssize_t sys_write(unsigned int fd,char *buf,int count);
-extern asmlinkage int sys_recv(int fd, void * ubuf, int size, unsigned flags);
-extern asmlinkage int sys_send(int fd, void * buff, int len, unsigned flags);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);
-extern asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count);
-extern asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count);
-
-
 asmlinkage int sunos_read(unsigned int fd,char *buf,int count)
 {
 	int ret;
@@ -1164,9 +1147,6 @@
 }
 
 
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
-extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
-
 asmlinkage int sunos_setsockopt(int fd, int level, int optname, char *optval,
 				int optlen)
 {
--- diff/arch/sparc/kernel/time.c	2003-12-19 09:51:02.000000000 +0000
+++ source/arch/sparc/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -535,6 +535,7 @@
 	write_seqlock_irq(&xtime_lock);
 	ret = bus_do_settimeofday(tv);
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return ret;
 }
 
--- diff/arch/sparc/prom/printf.c	2002-10-16 04:27:16.000000000 +0100
+++ source/arch/sparc/prom/printf.c	2004-02-18 09:03:58.000000000 +0000
@@ -39,7 +39,7 @@
 	int i;
 
 	va_start(args, fmt);
-	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
+	i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
 
 	prom_write(ppbuf, i);
--- diff/arch/sparc64/Kconfig	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/sparc64/Kconfig	2004-02-18 09:03:58.000000000 +0000
@@ -718,12 +718,19 @@
 	depends on DEBUG_KERNEL
 	bool "Debug BOOTMEM initialization"
 
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP && !PREEMPT
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 # We have a custom atomic_dec_and_lock() implementation but it's not
 # compatible with spinlock debugging so we need to fall back on
 # the generic version in that case.
 config HAVE_DEC_LOCK
 	bool
-	depends on SMP && !DEBUG_SPINLOCK
+	depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER
 	default y
 
 config MCOUNT
--- diff/arch/sparc64/kernel/ioctl32.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/sparc64/kernel/ioctl32.c	2004-02-18 09:03:58.000000000 +0000
@@ -12,6 +12,7 @@
 #define INCLUDES
 #include "compat_ioctl.c"
 #include <linux/ncp_fs.h>
+#include <linux/syscalls.h>
 #include <asm/fbio.h>
 #include <asm/kbio.h>
 #include <asm/vuid_event.h>
--- diff/arch/sparc64/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/sparc64/kernel/irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -1211,7 +1211,7 @@
 	if (cpus_empty(mask))
 		mask = cpu_online_map;
 
-	len = cpumask_snprintf(page, count, mask);
+	len = cpumask_scnprintf(page, count, mask);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/sparc64/kernel/setup.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/sparc64/kernel/setup.c	2004-02-18 09:03:58.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/syscalls.h>
 #include <linux/kdev_t.h>
 #include <linux/major.h>
 #include <linux/string.h>
@@ -71,7 +72,6 @@
 
 void (*prom_palette)(int);
 void (*prom_keyboard)(void);
-asmlinkage void sys_sync(void);	/* it's really int */
 
 static void
 prom_console_write(struct console *con, const char *s, unsigned n)
@@ -603,7 +603,7 @@
 }
 console_initcall(set_preferred_console);
 
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on)
 {
 	return -EIO;
 }
--- diff/arch/sparc64/kernel/sparc64_ksyms.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/sparc64/kernel/sparc64_ksyms.c	2004-02-18 09:03:58.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/socket.h>
+#include <linux/syscalls.h>
 #include <linux/percpu.h>
 #include <net/compat.h>
 
@@ -84,21 +85,13 @@
 extern u32 sunos_sys_table[], sys_call_table32[];
 extern void tl0_solaris(void);
 extern void sys_sigsuspend(void);
-extern int sys_getppid(void);
-extern int sys_getpid(void);
-extern int sys_geteuid(void);
-extern int sys_getuid(void);
-extern int sys_getegid(void);
-extern int sys_getgid(void);
 extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
 extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
-extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char * filename, int flags, int mode);
 extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
-extern long sys_close(unsigned int);
-                
+
 extern int __ashrdi3(int, int);
 
 extern void dump_thread(struct pt_regs *, struct user *);
--- diff/arch/sparc64/kernel/sunos_ioctl32.c	2003-05-21 11:50:14.000000000 +0100
+++ source/arch/sparc64/kernel/sunos_ioctl32.c	2004-02-18 09:03:58.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <asm/kbio.h>
 
@@ -90,8 +91,6 @@
         compat_caddr_t  ifcbuf;
 };
 
-extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-
 extern asmlinkage int compat_sys_ioctl(unsigned int, unsigned int, u32);
 extern asmlinkage int sys_setsid(void);
 
--- diff/arch/sparc64/kernel/sys_sparc.c	2003-07-22 18:54:27.000000000 +0100
+++ source/arch/sparc64/kernel/sys_sparc.c	2004-02-18 09:03:58.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/ipc.h>
 #include <linux/personality.h>
 
@@ -161,8 +162,6 @@
 	return addr;
 }
 
-extern asmlinkage unsigned long sys_brk(unsigned long brk);
-
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
 	/* People could try to be nasty and use ta 0x6d in 32bit programs */
@@ -280,8 +279,6 @@
 	return err;
 }
 
-extern asmlinkage int sys_newuname(struct new_utsname __user *name);
-
 asmlinkage int sparc64_newuname(struct new_utsname __user *name)
 {
 	int ret = sys_newuname(name);
@@ -292,8 +289,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_personality(unsigned long);
-
 asmlinkage int sparc64_personality(unsigned long personality)
 {
 	int ret;
--- diff/arch/sparc64/kernel/sys_sparc32.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/sparc64/kernel/sys_sparc32.c	2004-02-18 09:03:58.000000000 +0000
@@ -47,6 +47,7 @@
 #include <linux/ipv6.h>
 #include <linux/in.h>
 #include <linux/icmpv6.h>
+#include <linux/syscalls.h>
 #include <linux/sysctl.h>
 #include <linux/binfmts.h>
 #include <linux/dnotify.h>
@@ -88,17 +89,6 @@
 	__ret;				\
 })
 
-extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
-extern asmlinkage long sys_setregid(gid_t, gid_t);
-extern asmlinkage long sys_setgid(gid_t);
-extern asmlinkage long sys_setreuid(uid_t, uid_t);
-extern asmlinkage long sys_setuid(uid_t);
-extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);
-extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);
-extern asmlinkage long sys_setfsuid(uid_t);
-extern asmlinkage long sys_setfsgid(gid_t);
  
 asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group)
 {
@@ -179,40 +169,81 @@
 	return sys_setfsgid((gid_t)gid);
 }
 
+static int groups16_to_user(u16 *grouplist, struct group_info *group_info)
+{
+	int i;
+	u16 group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		group = (u16)GROUP_AT(group_info, i);
+		if (put_user(group, grouplist+i))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int groups16_from_user(struct group_info *group_info, u16 *grouplist)
+{
+	int i;
+	u16 group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		if (get_user(group, grouplist+i))
+			return  -EFAULT;
+		GROUP_AT(group_info, i) = (gid_t)group;
+	}
+
+	return 0;
+}
+
 asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist)
 {
-	u16 groups[NGROUPS];
-	int i,j;
+	int i;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+
+	get_group_info(current->group_info);
+	i = current->group_info->ngroups;
 	if (gidsetsize) {
-		if (i > gidsetsize)
-			return -EINVAL;
-		for(j=0;j<i;j++)
-			groups[j] = current->groups[j];
-		if (copy_to_user(grouplist, groups, sizeof(u16)*i))
-			return -EFAULT;
+		if (i > gidsetsize) {
+			i = -EINVAL;
+			goto out;
+		}
+		if (groups16_to_user(grouplist, current->group_info)) {
+			i = -EFAULT;
+			goto out;
+		}
 	}
+out:
+	put_group_info(current->group_info);
 	return i;
 }
 
 asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist)
 {
-	u16 groups[NGROUPS];
-	int i;
+	struct group_info *group_info;
+	int retval;
 
 	if (!capable(CAP_SETGID))
 		return -EPERM;
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned)gidsetsize > NGROUPS_MAX)
 		return -EINVAL;
-	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16)))
-		return -EFAULT;
-	for (i = 0 ; i < gidsetsize ; i++)
-		current->groups[i] = (gid_t)groups[i];
-	current->ngroups = gidsetsize;
-	return 0;
+
+	group_info = groups_alloc(gidsetsize);
+	if (!group_info)
+		return -ENOMEM;
+	retval = groups16_from_user(group_info, grouplist);
+	if (retval) {
+		put_group_info(group_info);
+		return retval;
+	}
+
+	retval = set_current_groups(group_info);
+	put_group_info(group_info);
+
+	return retval;
 }
 
 asmlinkage long sys32_getuid16(void)
@@ -251,9 +282,7 @@
 		 __put_user(i->tv_usec, &o->tv_usec)));
 }
 
-extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
-
-asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
+asmlinkage long sys32_ioperm(u32 from, u32 num, int on)
 {
 	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
 }
@@ -795,9 +824,6 @@
 	return err;
 }
 
-extern asmlinkage long sys_truncate(const char * path, unsigned long length);
-extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-
 asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
 {
 	if ((int)high < 0)
@@ -1303,8 +1329,6 @@
 	return err;
 }
 
-extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
-
 asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
 {
 	return sys_sysfs(option, arg1, arg2);
@@ -1530,8 +1554,6 @@
 	char _f[20-2*sizeof(int)-sizeof(int)];
 };
 
-extern asmlinkage int sys_sysinfo(struct sysinfo *info);
-
 asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
 {
 	struct sysinfo s;
@@ -1579,8 +1601,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
-
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec *interval)
 {
 	struct timespec t;
@@ -1595,8 +1615,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);
-
 asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset, compat_size_t sigsetsize)
 {
 	sigset_t s;
@@ -1631,8 +1649,6 @@
 	return 0;
 }
 
-extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-
 asmlinkage int sys32_rt_sigpending(compat_sigset_t *set, compat_size_t sigsetsize)
 {
 	sigset_t s;
@@ -1740,9 +1756,6 @@
 	return ret;
 }
 
-extern asmlinkage int
-sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
-
 asmlinkage int
 sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
 {
@@ -2073,15 +2086,11 @@
 
 #ifdef CONFIG_MODULES
 
-extern asmlinkage long sys_init_module(void *, unsigned long, const char *);
-
 asmlinkage int sys32_init_module(void *umod, u32 len, const char *uargs)
 {
 	return sys_init_module(umod, len, uargs);
 }
 
-extern asmlinkage long sys_delete_module(const char *, unsigned int);
-
 asmlinkage int sys32_delete_module(const char *name_user, unsigned int flags)
 {
 	return sys_delete_module(name_user, flags);
@@ -2323,7 +2332,6 @@
 	return err;
 }
 #else /* !NFSD */
-extern asmlinkage long sys_ni_syscall(void);
 int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
 {
 	return sys_ni_syscall();
@@ -2416,17 +2424,6 @@
 }
 
 /* PCI config space poking. */
-extern asmlinkage int sys_pciconfig_read(unsigned long bus,
-					 unsigned long dfn,
-					 unsigned long off,
-					 unsigned long len,
-					 unsigned char *buf);
-
-extern asmlinkage int sys_pciconfig_write(unsigned long bus,
-					  unsigned long dfn,
-					  unsigned long off,
-					  unsigned long len,
-					  unsigned char *buf);
 
 asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
@@ -2446,9 +2443,6 @@
 				   (unsigned char *)AA(ubuf));
 }
 
-extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
-				unsigned long arg4, unsigned long arg5);
-
 asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
 {
 	return sys_prctl(option,
@@ -2459,12 +2453,6 @@
 }
 
 
-extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
-				    size_t count, loff_t pos);
-
-extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
-				     size_t count, loff_t pos);
-
 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, char *ubuf,
 				   compat_size_t count, u32 poshi, u32 poslo)
 {
@@ -2477,8 +2465,6 @@
 	return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
-
 asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
 {
 	return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
@@ -2495,8 +2481,6 @@
 				((loff_t)AA(lenhi)<<32)|AA(lenlo), advice);
 }
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2516,8 +2500,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count);
-
 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2692,8 +2674,6 @@
 	return ret;       
 }
 
-extern asmlinkage long sys_setpriority(int which, int who, int niceval);
-
 asmlinkage int sys_setpriority32(u32 which, u32 who, u32 niceval)
 {
 	return sys_setpriority((int) which,
@@ -2753,8 +2733,6 @@
 #endif
 }
 
-extern long sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
-
 long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf, size_t len)
 {
 	return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
--- diff/arch/sparc64/kernel/sys_sunos32.c	2003-09-17 12:28:03.000000000 +0100
+++ source/arch/sparc64/kernel/sys_sunos32.c	2004-02-18 09:03:58.000000000 +0000
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -584,11 +585,6 @@
 	char       *netname;   /* server's netname */
 };
 
-extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-
 
 /* Bind the socket on a local reserved port and connect it to the
  * remote server.  This on Linux/i386 is done by the mount program,
@@ -781,8 +777,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_setsid(void);
-extern asmlinkage int sys_setpgid(pid_t, pid_t);
 
 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
 {
@@ -1200,11 +1194,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_read(unsigned int fd, char *buf, unsigned long count);
-extern asmlinkage ssize_t sys_write(unsigned int fd, char *buf, unsigned long count);
-extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
-extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);
 extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
 extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
 
@@ -1302,9 +1291,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
-				     char *optval, int optlen);
-
 asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval,
 				int optlen)
 {
--- diff/arch/sparc64/kernel/time.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/sparc64/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -1126,6 +1126,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/sparc64/lib/rwlock.S	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/sparc64/lib/rwlock.S	2004-02-18 09:03:58.000000000 +0000
@@ -85,5 +85,20 @@
 __write_trylock_fail:
 	retl
 	 mov		0, %o0
+
+	.globl	__read_trylock
+__read_trylock: /* %o0 = lock_ptr */
+	ldsw		[%o0], %g5
+	brlz,pn		%g5, 100f
+	add		%g5, 1, %g7
+	cas		[%o0], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, __read_trylock
+	 membar		#StoreLoad | #StoreStore
+	retl
+	mov		1, %o0
+100:	retl
+	mov		0, %o0
+
 rwlock_impl_end:
 
--- diff/arch/sparc64/prom/printf.c	2003-05-21 11:50:14.000000000 +0100
+++ source/arch/sparc64/prom/printf.c	2004-02-18 09:03:58.000000000 +0000
@@ -40,7 +40,7 @@
 	int i;
 
 	va_start(args, fmt);
-	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
+	i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
 
 	prom_write(ppbuf, i);
--- diff/arch/sparc64/solaris/ioctl.c	2003-05-21 11:50:14.000000000 +0100
+++ source/arch/sparc64/solaris/ioctl.c	2004-02-18 09:03:58.000000000 +0000
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/ioctl.h>
 #include <linux/fs.h>
 #include <linux/file.h>
@@ -34,8 +35,6 @@
 #include "conv.h"
 #include "socksys.h"
 
-extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
-	unsigned long arg);
 extern asmlinkage int compat_sys_ioctl(unsigned int fd, unsigned int cmd,
 	u32 arg);
 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
--- diff/arch/sparc64/solaris/socksys.c	2003-09-17 12:28:03.000000000 +0100
+++ source/arch/sparc64/solaris/socksys.c	2004-02-18 09:03:58.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/in.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -35,9 +36,6 @@
 #include "conv.h"
 #include "socksys.h"
 
-extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
-	unsigned long arg);
-	
 static int af_inet_protocols[] = {
 IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
 IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
--- diff/arch/sparc64/solaris/timod.c	2003-09-17 12:28:03.000000000 +0100
+++ source/arch/sparc64/solaris/timod.c	2004-02-18 09:03:58.000000000 +0000
@@ -27,8 +27,6 @@
 #include "conv.h"
 #include "socksys.h"
 
-extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
-	unsigned long arg);
 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 
 static spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED;
--- diff/arch/um/drivers/net_kern.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/um/drivers/net_kern.c	2004-02-18 09:03:58.000000000 +0000
@@ -358,8 +358,12 @@
 	rtnl_lock();
 	err = register_netdevice(dev);
 	rtnl_unlock();
-	if (err)
+	if (err) {
+		device->dev = NULL;
+		/* XXX: should we call ->remove() here? */
+		free_netdev(dev);
 		return 1;
+	}
 	lp = dev->priv;
 
 	INIT_LIST_HEAD(&lp->list);
--- diff/arch/um/include/kern_util.h	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/um/include/kern_util.h	2004-02-18 09:03:58.000000000 +0000
@@ -45,7 +45,6 @@
 extern int need_finish_fork(void);
 extern void free_stack(unsigned long stack, int order);
 extern void add_input_request(int op, void (*proc)(int), void *arg);
-extern int sys_execve(char *file, char **argv, char **env);
 extern char *current_cmd(void);
 extern void timer_handler(int sig, union uml_pt_regs *regs);
 extern int set_signals(int enable);
--- diff/arch/um/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/um/kernel/irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -575,7 +575,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -613,7 +613,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/um/kernel/sys_call_table.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/um/kernel/sys_call_table.c	2004-02-18 09:03:58.000000000 +0000
@@ -8,6 +8,7 @@
 #include "linux/version.h"
 #include "linux/sys.h"
 #include "linux/swap.h"
+#include "linux/syscalls.h"
 #include "linux/sysctl.h"
 #include "asm/signal.h"
 #include "sysdep/syscalls.h"
@@ -268,9 +269,9 @@
 	[ __NR_creat ] = sys_creat,
 	[ __NR_link ] = sys_link,
 	[ __NR_unlink ] = sys_unlink,
+	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
 
 	/* declared differently in kern_util.h */
-	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
 	[ __NR_chdir ] = sys_chdir,
 	[ __NR_time ] = um_time,
 	[ __NR_mknod ] = sys_mknod,
--- diff/arch/um/kernel/syscall_kern.c	2003-10-09 09:47:16.000000000 +0100
+++ source/arch/um/kernel/syscall_kern.c	2004-02-18 09:03:58.000000000 +0000
@@ -11,6 +11,7 @@
 #include "linux/msg.h"
 #include "linux/shm.h"
 #include "linux/sys.h"
+#include "linux/syscalls.h"
 #include "linux/unistd.h"
 #include "linux/slab.h"
 #include "linux/utime.h"
--- diff/arch/um/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/um/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -93,6 +93,7 @@
 	gettimeofday(tv, NULL);
 	timeradd(tv, &local_offset, tv);
 	time_unlock(flags);
+	clock_was_set();
 }
 
 EXPORT_SYMBOL(do_gettimeofday);
--- diff/arch/v850/kernel/syscalls.c	2002-12-30 10:17:12.000000000 +0000
+++ source/arch/v850/kernel/syscalls.c	2004-02-18 09:03:58.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
--- diff/arch/v850/kernel/time.c	2003-10-09 09:47:33.000000000 +0100
+++ source/arch/v850/kernel/time.c	2004-02-18 09:03:58.000000000 +0000
@@ -193,6 +193,7 @@
 	time_esterror = NTP_PHASE_LIMIT;
 
 	write_sequnlock_irq (&xtime_lock);
+	clock_was_set();
 	return 0;
 }
 
--- diff/arch/x86_64/Kconfig	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/Kconfig	2004-02-18 09:03:58.000000000 +0000
@@ -48,12 +48,14 @@
 	bool
 	default y
 	help
-	  Write kernel log output directly into the VGA buffer. This is useful
-	  for kernel debugging when your machine crashes very early before
-	  the console code is initialized. For normal operation it is not
-	  recommended because it looks ugly and doesn't cooperate with 
-	  klogd/syslogd or the X server. You should normally N here, unless
-	  you want to debug such a crash.
+	  Write kernel log output directly into the VGA buffer or to a serial
+	  port.
+
+	  This is useful for kernel debugging when your machine crashes very
+	  early before the console code is initialized. For normal operation
+	  it is not recommended because it looks ugly and doesn't cooperate
+	  with klogd/syslogd or the X server. You should normally N here,
+	  unless you want to debug such a crash.
 	  
 config HPET_TIMER
 	bool
@@ -433,6 +435,7 @@
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
 	depends on DEBUG_KERNEL
+	default n
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
@@ -464,9 +467,8 @@
        help
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
-       
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
+
+source "arch/x86_64/Kconfig.kgdb"
 
 endmenu
 
--- diff/arch/x86_64/Makefile	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -52,7 +52,10 @@
 ifneq ($(CONFIG_DEBUG_INFO),y)
 CFLAGS += -fno-asynchronous-unwind-tables
 endif
-#CFLAGS += $(call check_gcc,-funit-at-a-time,)
+
+# Enable unit-at-a-time mode when possible. It shrinks the
+# kernel considerably.
+CFLAGS += $(call check_gcc,-funit-at-a-time,)
 
 head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
 
--- diff/arch/x86_64/ia32/ia32_ioctl.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/x86_64/ia32/ia32_ioctl.c	2004-02-18 09:03:58.000000000 +0000
@@ -10,12 +10,11 @@
  */
 
 #define INCLUDES
+#include <linux/syscalls.h>
 #include "compat_ioctl.c"
 #include <asm/mtrr.h>
 #include <asm/ia32.h>
 
-extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-
 #define CODE
 #include "compat_ioctl.c"
   
--- diff/arch/x86_64/ia32/ipc32.c	2003-08-20 14:16:26.000000000 +0100
+++ source/arch/x86_64/ia32/ipc32.c	2004-02-18 09:03:58.000000000 +0000
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/fs.h> 
 #include <linux/file.h> 
 #include <linux/sem.h>
--- diff/arch/x86_64/ia32/ptrace32.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/ia32/ptrace32.c	2004-02-18 09:03:58.000000000 +0000
@@ -14,6 +14,8 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/unistd.h>
 #include <linux/mm.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
@@ -223,8 +225,6 @@
 	
 } 
 
-extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
-
 asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 {
 	struct task_struct *child;
--- diff/arch/x86_64/ia32/sys_ia32.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/x86_64/ia32/sys_ia32.c	2004-02-18 09:03:58.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/fs.h> 
 #include <linux/file.h> 
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
@@ -110,9 +111,6 @@
 	return 0;
 }
 
-extern long sys_truncate(char *, loff_t);
-extern long sys_ftruncate(int, loff_t);
-
 asmlinkage long
 sys32_truncate64(char * filename, unsigned long offset_low, unsigned long offset_high)
 {
@@ -236,8 +234,6 @@
 	return retval;
 }
 
-extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
-
 asmlinkage long 
 sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
@@ -363,12 +359,9 @@
 	return ret;
 }
 
-extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
-					  size_t sigsetsize);
-
 asmlinkage long
-sys32_rt_sigprocmask(int how, compat_sigset_t *set, compat_sigset_t *oset,
-		     unsigned int sigsetsize)
+sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
+			compat_sigset_t __user *oset, unsigned int sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -734,9 +727,6 @@
 			    (struct compat_timeval *)A(a.tvp));
 }
 
-asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
-asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
-
 static struct iovec *
 get_compat_iovec(struct compat_iovec *iov32, struct iovec *iov_buf, u32 *count, int type, int *errp)
 {
@@ -878,18 +868,12 @@
 
 /* 32-bit timeval and related flotsam.  */
 
-extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
-				unsigned long arg2);
-
 asmlinkage long
 sys32_sysfs(int option, u32 arg1, u32 arg2)
 {
 	return sys_sysfs(option, arg1, arg2);
 }
 
-extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
-				unsigned long new_flags, void *data);
-
 static char *badfs[] = {
 	"smbfs", "ncpfs", NULL
 }; 	
@@ -940,8 +924,6 @@
         char _f[20-2*sizeof(u32)-sizeof(int)];
 };
 
-extern asmlinkage long sys_sysinfo(struct sysinfo *info);
-
 asmlinkage long
 sys32_sysinfo(struct sysinfo32 *info)
 {
@@ -991,9 +973,6 @@
 	return 0;
 }
                 
-extern asmlinkage long sys_sched_rr_get_interval(pid_t pid,
-						struct timespec *interval);
-
 asmlinkage long
 sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec *interval)
 {
@@ -1009,10 +988,8 @@
 	return ret;
 }
 
-extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-
 asmlinkage long
-sys32_rt_sigpending(compat_sigset_t *set, compat_size_t sigsetsize)
+sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -1035,9 +1012,6 @@
 	return ret;
 }
 
-extern asmlinkage long
-sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
-		    const struct timespec *uts, size_t sigsetsize);
 
 asmlinkage long
 sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo,
@@ -1077,9 +1051,6 @@
 	return ret;
 }
 
-extern asmlinkage long
-sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
-
 asmlinkage long
 sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
 {
@@ -1165,12 +1136,6 @@
 #endif
 }
 
-extern asmlinkage ssize_t sys_pread64(unsigned int fd, char * buf,
-				    size_t count, loff_t pos);
-
-extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
-				     size_t count, loff_t pos);
-
 /* warning: next two assume little endian */ 
 asmlinkage long
 sys32_pread(unsigned int fd, char *ubuf, u32 count, u32 poslo, u32 poshi)
@@ -1187,8 +1152,6 @@
 }
 
 
-extern asmlinkage long sys_personality(unsigned long);
-
 asmlinkage long
 sys32_personality(unsigned long personality)
 {
@@ -1202,9 +1165,6 @@
 	return ret;
 }
 
-extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset,
-				       size_t count); 
-
 asmlinkage long
 sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
 {
@@ -1375,9 +1335,7 @@
 	return err?-EFAULT:0;
 }
 
-extern int sys_ustat(dev_t, struct ustat *);
-
-long sys32_ustat(unsigned dev, struct ustat32 *u32p)
+long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
 {
 	struct ustat u;
 	mm_segment_t seg;
@@ -1500,15 +1458,11 @@
  * Some system calls that need sign extended arguments. This could be done by a generic wrapper.
  */ 
 
-extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
-
 long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
 	return sys_lseek(fd, offset, whence);
 }
 
-extern int sys_kill(pid_t pid, int sig); 
-
 long sys32_kill(int pid, int sig)
 {
 	return sys_kill(pid, sig);
@@ -1736,15 +1690,12 @@
 	return err;
 }
 #else /* !NFSD */
-extern asmlinkage long sys_ni_syscall(void);
 long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
 {
 	return sys_ni_syscall();
 }
 #endif
 
-extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
-
 long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
 { 
 	long ret; 
@@ -1802,11 +1753,6 @@
 	return i ? i : ret;
 }
 
-extern asmlinkage long sys_io_getevents(aio_context_t ctx_id,
-					  long min_nr,
-					  long nr,
-					  struct io_event *events,
-					  struct timespec *timeout);
 
 asmlinkage long sys32_io_getevents(aio_context_t ctx_id,
 				 unsigned long min_nr,
@@ -1895,8 +1841,6 @@
 	return err; 
 } 
 
-extern long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice);
-
 long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, 
 			__u32 len_low, __u32 len_high, int advice)
 { 
--- diff/arch/x86_64/kernel/Makefile	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/x86_64/kernel/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -24,6 +24,7 @@
 obj-$(CONFIG_DUMMY_IOMMU)	+= pci-nommu.o pci-dma.o
 
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 obj-y				+= topology.o
 
--- diff/arch/x86_64/kernel/early_printk.c	2003-06-09 14:18:18.000000000 +0100
+++ source/arch/x86_64/kernel/early_printk.c	2004-02-18 09:03:58.000000000 +0000
@@ -7,7 +7,11 @@
 
 /* Simple VGA output */
 
+#ifdef __i386__
+#define VGABASE		__pa(__PAGE_OFFSET + 0xb8000UL)
+#else
 #define VGABASE		0xffffffff800b8000UL
+#endif
 
 #define MAX_YPOS	25
 #define MAX_XPOS	80
@@ -22,15 +26,14 @@
 	while ((c = *str++) != '\0' && n-- > 0) {
 		if (current_ypos >= MAX_YPOS) {
 			/* scroll 1 line up */
-			for(k = 1, j = 0; k < MAX_YPOS; k++, j++) {
-				for(i = 0; i < MAX_XPOS; i++) {
+			for (k = 1, j = 0; k < MAX_YPOS; k++, j++) {
+				for (i = 0; i < MAX_XPOS; i++) {
 					writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
 					       VGABASE + 2*(MAX_XPOS*j + i));
 				}
 			}
-			for(i = 0; i < MAX_XPOS; i++) {
+			for (i = 0; i < MAX_XPOS; i++)
 				writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
-			}
 			current_ypos = MAX_YPOS-1;
 		}
 		if (c == '\n') {
@@ -38,7 +41,8 @@
 			current_ypos++;
 		} else if (c != '\r')  {
 			writew(((0x7 << 8) | (unsigned short) c),
-			       VGABASE + 2*(MAX_XPOS*current_ypos + current_xpos++));
+			       VGABASE + 2*(MAX_XPOS*current_ypos +
+						current_xpos++));
 			if (current_xpos >= MAX_XPOS) {
 				current_xpos = 0;
 				current_ypos++;
@@ -78,7 +82,7 @@
 { 
 	unsigned timeout = 0xffff; 
 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 
-		rep_nop(); 
+		cpu_relax();
 	outb(ch, early_serial_base + TXR);
 	return timeout ? 0 : -1;
 } 
@@ -93,10 +97,13 @@
 	} 
 } 
 
+#define DEFAULT_BAUD 9600
+
 static __init void early_serial_init(char *opt)
 {
 	unsigned char c; 
-	unsigned divisor, baud = 38400;
+	unsigned divisor;
+	unsigned baud = DEFAULT_BAUD;
 	char *s, *e;
 
 	if (*opt == ',') 
@@ -109,25 +116,26 @@
 			early_serial_base = simple_strtoul(s, &e, 16);
 		} else {
 			static int bases[] = { 0x3f8, 0x2f8 };
-		if (!strncmp(s,"ttyS",4)) 
-			s+=4; 
-		port = simple_strtoul(s, &e, 10); 
-		if (port > 1 || s == e) 
-			port = 0; 
-		early_serial_base = bases[port];
-	}
+
+			if (!strncmp(s,"ttyS",4))
+				s += 4;
+			port = simple_strtoul(s, &e, 10);
+			if (port > 1 || s == e)
+				port = 0;
+			early_serial_base = bases[port];
+		}
 	}
 
-	outb(0x3, early_serial_base + LCR); /* 8n1 */
-	outb(0, early_serial_base + IER); /* no interrupt */ 
-	outb(0, early_serial_base + FCR); /* no fifo */ 
-	outb(0x3, early_serial_base + MCR); /* DTR + RTS */ 
+	outb(0x3, early_serial_base + LCR);	/* 8n1 */
+	outb(0, early_serial_base + IER);	/* no interrupt */
+	outb(0, early_serial_base + FCR);	/* no fifo */
+	outb(0x3, early_serial_base + MCR);	/* DTR + RTS */
 
 	s = strsep(&opt, ","); 
 	if (s != NULL) { 
 		baud = simple_strtoul(s, &e, 0); 
 		if (baud == 0 || s == e) 
-			baud = 38400;
+			baud = DEFAULT_BAUD;
 	} 
 	
 	divisor = 115200 / baud; 
@@ -154,8 +162,9 @@
 	char buf[512]; 
 	int n; 
 	va_list ap;
+
 	va_start(ap,fmt); 
-	n = vsnprintf(buf,512,fmt,ap);
+	n = vscnprintf(buf,512,fmt,ap);
 	early_console->write(early_console,buf,n);
 	va_end(ap); 
 } 
@@ -170,6 +179,8 @@
 	if (early_console_initialized)
 		return -1;
 
+	opt = strchr(opt, '=') + 1;
+
 	strlcpy(buf,opt,sizeof(buf)); 
 	space = strchr(buf, ' '); 
 	if (space)
@@ -200,19 +211,12 @@
 	if (!early_console_initialized || !early_console)
 		return;
 	if (!keep_early) {
-		printk("disabling early console...\n"); 
+		printk("disabling early console\n");
 		unregister_console(early_console);
 		early_console_initialized = 0;
 	} else { 
-		printk("keeping early console.\n"); 
+		printk("keeping early console\n");
 	}
 } 
 
-/* syntax: earlyprintk=vga
-           earlyprintk=serial[,ttySn[,baudrate]] 
-   Append ,keep to not disable it when the real console takes over.
-   Only vga or serial at a time, not both.
-   Currently only ttyS0 and ttyS1 are supported. 
-   Interaction with the standard serial driver is not very good. 
-   The VGA output is eventually overwritten by the real console. */
-__setup("earlyprintk=", setup_early_printk);  
+__setup("earlyprintk=", setup_early_printk);
--- diff/arch/x86_64/kernel/head64.c	2003-05-21 11:50:00.000000000 +0100
+++ source/arch/x86_64/kernel/head64.c	2004-02-18 09:03:58.000000000 +0000
@@ -83,9 +83,9 @@
 	/* default console: */
 	if (!strstr(saved_command_line, "console="))
 		strcat(saved_command_line, " console=tty0"); 
-	s = strstr(saved_command_line, "earlyprintk="); 
+	s = strstr(saved_command_line, "earlyprintk=");
 	if (s != NULL)
-		setup_early_printk(s+12); 
+		setup_early_printk(s);
 #ifdef CONFIG_DISCONTIGMEM
 	s = strstr(saved_command_line, "numa=");
 	if (s != NULL)
--- diff/arch/x86_64/kernel/irq.c	2004-01-19 10:22:55.000000000 +0000
+++ source/arch/x86_64/kernel/irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -405,6 +405,9 @@
 	spin_unlock(&desc->lock);
 
 	irq_exit();
+
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
@@ -826,7 +829,7 @@
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, irq_affinity[(long)data]);
+	int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
@@ -864,7 +867,7 @@
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int len = cpumask_snprintf(page, count, *(cpumask_t *)data);
+	int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
 	if (count - len < 2)
 		return -EINVAL;
 	len += sprintf(page + len, "\n");
--- diff/arch/x86_64/kernel/smp.c	2003-11-25 15:24:57.000000000 +0000
+++ source/arch/x86_64/kernel/smp.c	2004-02-18 09:03:58.000000000 +0000
@@ -362,6 +362,18 @@
 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
+
 /*
  * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
--- diff/arch/x86_64/kernel/sys_x86_64.c	2004-02-18 08:54:08.000000000 +0000
+++ source/arch/x86_64/kernel/sys_x86_64.c	2004-02-18 09:03:58.000000000 +0000
@@ -4,6 +4,7 @@
 
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
--- diff/arch/x86_64/kernel/traps.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/kernel/traps.c	2004-02-18 09:03:58.000000000 +0000
@@ -45,6 +45,9 @@
 #include <asm/proto.h>
 
 #include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
 
 extern struct gate_struct idt_table[256]; 
 
--- diff/arch/x86_64/kernel/x8664_ksyms.c	2004-02-09 10:36:09.000000000 +0000
+++ source/arch/x86_64/kernel/x8664_ksyms.c	2004-02-18 09:03:58.000000000 +0000
@@ -11,6 +11,7 @@
 #include <linux/apm_bios.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/syscalls.h>
 #include <linux/tty.h>
 
 #include <asm/semaphore.h>
@@ -180,8 +181,6 @@
 EXPORT_SYMBOL_NOVERS(__memcpy);
 
 /* syscall export needed for misdesigned sound drivers. */
-extern ssize_t sys_read(unsigned int fd, char * buf, size_t count);
-extern off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
 EXPORT_SYMBOL(sys_read);
 EXPORT_SYMBOL(sys_lseek);
 EXPORT_SYMBOL(sys_open);
--- diff/arch/x86_64/lib/Makefile	2003-06-30 10:07:20.000000000 +0100
+++ source/arch/x86_64/lib/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -11,3 +11,4 @@
 
 lib-$(CONFIG_IO_DEBUG) += iodebug.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/drivers/Makefile	2003-09-17 12:28:03.000000000 +0100
+++ source/drivers/Makefile	2004-02-18 09:04:00.000000000 +0000
@@ -45,7 +45,7 @@
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
-obj-$(CONFIG_ISDN_BOOL)		+= isdn/
+obj-$(CONFIG_ISDN)		+= isdn/
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
--- diff/drivers/acpi/Kconfig	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/Kconfig	2004-02-18 09:03:58.000000000 +0000
@@ -263,5 +263,23 @@
 	  particular, many Toshiba laptops require this for correct operation
 	  of the AC module.
 
+config X86_PM_TIMER
+	bool "Power Management Timer Support"
+	depends on X86 && ACPI
+	depends on ACPI_BOOT && EXPERIMENTAL
+	default n
+	help
+	  The Power Management Timer is available on all ACPI-capable,
+	  in most cases even if ACPI is unusable or blacklisted.
+
+	  This timing source is not affected by powermanagement features
+	  like aggressive processor idling, throttling, frequency and/or
+	  voltage scaling, unlike the commonly used Time Stamp Counter
+	  (TSC) timing source.
+
+	  So, if you see messages like 'Losing too many ticks!' in the
+	  kernel logs, and/or you are using a this on a notebook which
+	  does not yet have an HPET, you should say "Y" here.
+
 endmenu
 
--- diff/drivers/acpi/dispatcher/dsmthdat.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dsmthdat.c	2004-02-18 09:03:58.000000000 +0000
@@ -206,8 +206,7 @@
 		 * Store the argument in the method/walk descriptor.
 		 * Do not copy the arg in order to implement call by reference
 		 */
-		status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index],
-				 walk_state);
+		status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state);
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
 		}
@@ -465,6 +464,7 @@
 			return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL);
 
 		default:
+			ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", opcode));
 			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
 	}
@@ -597,7 +597,10 @@
 
 	/*
 	 * If the reference count on the object is more than one, we must
-	 * take a copy of the object before we store.
+	 * take a copy of the object before we store.  A reference count
+	 * of exactly 1 means that the object was just created during the
+	 * evaluation of an expression, and we can safely use it since it
+	 * is not used anywhere else.
 	 */
 	new_obj_desc = obj_desc;
 	if (obj_desc->common.reference_count > 1) {
--- diff/drivers/acpi/dispatcher/dsobject.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dsobject.c	2004-02-18 09:03:58.000000000 +0000
@@ -582,6 +582,11 @@
 
 			obj_desc->reference.opcode = AML_ARG_OP;
 			obj_desc->reference.offset = opcode - AML_ARG_OP;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+			status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset,
+					 walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object);
+#endif
 			break;
 
 		default: /* Other literals, etc.. */
--- diff/drivers/acpi/dispatcher/dsopcode.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dsopcode.c	2004-02-18 09:03:58.000000000 +0000
@@ -243,8 +243,8 @@
 
 	node = obj_desc->buffer.node;
 	if (!node) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-				"No pointer back to NS node in buffer %p\n", obj_desc));
+		ACPI_REPORT_ERROR ((
+				"No pointer back to NS node in buffer obj %p\n", obj_desc));
 		return_ACPI_STATUS (AE_AML_INTERNAL);
 	}
 
@@ -290,7 +290,7 @@
 
 	node = obj_desc->package.node;
 	if (!node) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+		ACPI_REPORT_ERROR ((
 				"No pointer back to NS node in package %p\n", obj_desc));
 		return_ACPI_STATUS (AE_AML_INTERNAL);
 	}
--- diff/drivers/acpi/dispatcher/dsutils.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dsutils.c	2004-02-18 09:03:58.000000000 +0000
@@ -280,7 +280,8 @@
 
 	/*
 	 * Attempt to resolve each of the valid operands
-	 * Method arguments are passed by value, not by reference
+	 * Method arguments are passed by reference, not by value.  This means
+	 * that the actual objects are passed, not copies of the objects.
 	 */
 	for (i = 0; i < walk_state->num_operands; i++) {
 		status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state);
--- diff/drivers/acpi/dispatcher/dswstate.c	2004-02-09 10:36:09.000000000 +0000
+++ source/drivers/acpi/dispatcher/dswstate.c	2004-02-18 09:03:58.000000000 +0000
@@ -328,7 +328,7 @@
 
 	state = walk_state->results;
 	if (!state) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result stack frame\n"));
+		ACPI_REPORT_ERROR (("No result stack frame during push\n"));
 		return (AE_AML_INTERNAL);
 	}
 
--- diff/drivers/acpi/executer/exconvrt.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exconvrt.c	2004-02-18 09:03:58.000000000 +0000
@@ -55,8 +55,9 @@
  *
  * FUNCTION:    acpi_ex_convert_to_integer
  *
- * PARAMETERS:  *obj_desc       - Object to be converted.  Must be an
+ * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
+ *              result_desc     - Where the new Integer object is returned
  *              walk_state      - Current method state
  *
  * RETURN:      Status
@@ -189,8 +190,9 @@
  *
  * FUNCTION:    acpi_ex_convert_to_buffer
  *
- * PARAMETERS:  *obj_desc       - Object to be converted.  Must be an
+ * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
+ *              result_desc     - Where the new buffer object is returned
  *              walk_state      - Current method state
  *
  * RETURN:      Status
@@ -319,6 +321,7 @@
 
 	ACPI_FUNCTION_ENTRY ();
 
+
 	if (data_width < sizeof (acpi_integer)) {
 		leading_zero = FALSE;
 		length = data_width;
@@ -328,22 +331,21 @@
 		length = sizeof (acpi_integer);
 	}
 
-
 	switch (base) {
 	case 10:
 
 		remainder = 0;
-		for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0 ; i--) {
+		for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0; i--) {
 			/* Divide by nth factor of 10 */
 
 			digit = integer;
-			for (j = 1; j < i; j++) {
+			for (j = 0; j < i; j++) {
 				(void) acpi_ut_short_divide (&digit, 10, &digit, &remainder);
 			}
 
 			/* Create the decimal digit */
 
-			if (digit != 0) {
+			if (remainder != 0) {
 				leading_zero = FALSE;
 			}
 
@@ -354,6 +356,7 @@
 		}
 		break;
 
+
 	case 16:
 
 		/* Copy the integer to the buffer */
@@ -372,13 +375,14 @@
 		}
 		break;
 
+
 	default:
 		break;
 	}
 
 	/*
 	 * Since leading zeros are supressed, we must check for the case where
-	 * the integer equals 0.
+	 * the integer equals 0
 	 *
 	 * Finally, null terminate the string and return the length
 	 */
@@ -396,8 +400,11 @@
  *
  * FUNCTION:    acpi_ex_convert_to_string
  *
- * PARAMETERS:  *obj_desc       - Object to be converted.  Must be an
- *                                Integer, Buffer, or String
+ * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
+ *                                  Integer, Buffer, or String
+ *              result_desc     - Where the string object is returned
+ *              Base            - 10 or 16
+ *              max_length      - Max length of the returned string
  *              walk_state      - Current method state
  *
  * RETURN:      Status
@@ -415,10 +422,10 @@
 	struct acpi_walk_state          *walk_state)
 {
 	union acpi_operand_object       *ret_desc;
-	u32                             i;
-	u32                             string_length;
 	u8                              *new_buf;
 	u8                              *pointer;
+	u32                             string_length;
+	u32                             i;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc);
@@ -539,7 +546,6 @@
 		return_ACPI_STATUS (AE_TYPE);
 	}
 
-
 	/*
 	 * If we are about to overwrite the original object on the operand stack,
 	 * we must remove a reference on the original object because we are
@@ -562,6 +568,7 @@
  *
  * PARAMETERS:  destination_type    - Current type of the destination
  *              source_desc         - Source object to be converted.
+ *              result_desc         - Where the converted object is returned
  *              walk_state          - Current method state
  *
  * RETURN:      Status
@@ -653,6 +660,8 @@
 
 
 		default:
+			ACPI_REPORT_ERROR (("Bad destination type during conversion: %X\n",
+				destination_type));
 			status = AE_AML_INTERNAL;
 			break;
 		}
@@ -672,6 +681,8 @@
 			GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args),
 			walk_state->op_info->name, acpi_ut_get_type_name (destination_type)));
 
+		ACPI_REPORT_ERROR (("Bad Target Type (ARGI): %X\n",
+			GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)))
 		status = AE_AML_INTERNAL;
 	}
 
--- diff/drivers/acpi/executer/exfldio.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exfldio.c	2004-02-18 09:03:58.000000000 +0000
@@ -507,8 +507,8 @@
 
 	default:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
-			obj_desc, acpi_ut_get_object_type_name (obj_desc)));
+		ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
+			ACPI_GET_OBJECT_TYPE (obj_desc)));
 		status = AE_AML_INTERNAL;
 		break;
 	}
--- diff/drivers/acpi/executer/exmisc.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exmisc.c	2004-02-18 09:03:58.000000000 +0000
@@ -103,7 +103,7 @@
 
 		default:
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference subtype %X\n",
+			ACPI_REPORT_ERROR (("Unknown Reference subtype in get ref %X\n",
 				obj_desc->reference.opcode));
 			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
@@ -121,8 +121,8 @@
 
 	default:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p has invalid descriptor [%s]\n",
-				obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
+		ACPI_REPORT_ERROR (("Invalid descriptor type in get ref: %X\n",
+				ACPI_GET_DESCRIPTOR_TYPE (obj_desc)));
 		return_ACPI_STATUS (AE_TYPE);
 	}
 
@@ -349,6 +349,8 @@
 
 		/* Invalid object type, should not happen here */
 
+		ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n",
+				ACPI_GET_OBJECT_TYPE (obj_desc1)));
 		status = AE_AML_INTERNAL;
 		return_desc = NULL;
 	}
--- diff/drivers/acpi/executer/exoparg2.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exoparg2.c	2004-02-18 09:03:58.000000000 +0000
@@ -329,6 +329,8 @@
 			break;
 
 		default:
+			ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n",
+					ACPI_GET_OBJECT_TYPE (operand[0])));
 			status = AE_AML_INTERNAL;
 		}
 
@@ -433,7 +435,7 @@
 			}
 
 			return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
-			return_desc->reference.object    = operand[0]->package.elements [index];
+			return_desc->reference.object    = operand[0];
 			return_desc->reference.where     = &operand[0]->package.elements [index];
 		}
 		else {
--- diff/drivers/acpi/executer/exprep.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exprep.c	2004-02-18 09:03:58.000000000 +0000
@@ -507,7 +507,7 @@
 			(info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));
 
 		if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Index Object\n"));
+			ACPI_REPORT_ERROR (("Null Index Object during field prep\n"));
 			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
 
--- diff/drivers/acpi/executer/exresolv.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exresolv.c	2004-02-18 09:03:58.000000000 +0000
@@ -238,8 +238,8 @@
 
 				/* Invalid reference object */
 
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-					"Unknown target_type %X in Index/Reference obj %p\n",
+				ACPI_REPORT_ERROR ((
+					"During resolve, Unknown target_type %X in Index/Reference obj %p\n",
 					stack_desc->reference.target_type, stack_desc));
 				status = AE_AML_INTERNAL;
 				break;
@@ -258,7 +258,7 @@
 
 		default:
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X (%s) in %p\n",
+			ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n",
 				opcode, acpi_ps_get_opcode_name (opcode), stack_desc));
 			status = AE_AML_INTERNAL;
 			break;
--- diff/drivers/acpi/executer/exresop.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exresop.c	2004-02-18 09:03:58.000000000 +0000
@@ -154,7 +154,7 @@
 
 	arg_types = op_info->runtime_args;
 	if (arg_types == ARGI_INVALID_OPCODE) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - %X is not a valid AML opcode\n",
+		ACPI_REPORT_ERROR (("resolve_operands: %X is not a valid AML opcode\n",
 			opcode));
 
 		return_ACPI_STATUS (AE_AML_INTERNAL);
@@ -172,7 +172,7 @@
 	 */
 	while (GET_CURRENT_ARG_TYPE (arg_types)) {
 		if (!stack_ptr || !*stack_ptr) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null stack entry at %p\n",
+			ACPI_REPORT_ERROR (("resolve_operands: Null stack entry at %p\n",
 				stack_ptr));
 
 			return_ACPI_STATUS (AE_AML_INTERNAL);
--- diff/drivers/acpi/executer/exstore.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exstore.c	2004-02-18 09:03:58.000000000 +0000
@@ -125,7 +125,7 @@
 
 	default:
 
-		/* Destination is not an Reference */
+		/* Destination is not a Reference object */
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 			"Destination is not a Reference or Constant object [%p]\n", dest_desc));
@@ -189,35 +189,38 @@
 		switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
 		case ACPI_TYPE_INTEGER:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n",
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
 					ACPI_FORMAT_UINT64 (source_desc->integer.value)));
 			break;
 
 
 		case ACPI_TYPE_BUFFER:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length %.2X\n",
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X",
 					(u32) source_desc->buffer.length));
+			ACPI_DUMP_BUFFER (source_desc->buffer.pointer,
+				(source_desc->buffer.length < 32) ? source_desc->buffer.length : 32);
 			break;
 
 
 		case ACPI_TYPE_STRING:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s\n", source_desc->string.pointer));
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X, \"%s\"\n",
+					source_desc->string.length, source_desc->string.pointer));
 			break;
 
 
 		case ACPI_TYPE_PACKAGE:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements Ptr - %p\n",
-					source_desc->package.elements));
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Size 0x%.2X Elements Ptr - %p\n",
+					source_desc->package.count, source_desc->package.elements));
 			break;
 
 
 		default:
 
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Type %s %p\n",
-					acpi_ut_get_object_type_name (source_desc), source_desc));
+			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n",
+					source_desc));
 			break;
 		}
 
@@ -227,7 +230,7 @@
 
 	default:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X\n",
+		ACPI_REPORT_ERROR (("ex_store: Unknown Reference opcode %X\n",
 			ref_desc->reference.opcode));
 		ACPI_DUMP_ENTRY (ref_desc, ACPI_LV_ERROR);
 
@@ -263,6 +266,7 @@
 	union acpi_operand_object       *obj_desc;
 	union acpi_operand_object       *new_desc;
 	u8                              value = 0;
+	u32                             i;
 
 
 	ACPI_FUNCTION_TRACE ("ex_store_object_to_index");
@@ -283,6 +287,7 @@
 		/*
 		 * The object at *(index_desc->Reference.Where) is the
 		 * element within the package that is to be modified.
+		 * The parent package object is at index_desc->Reference.Object
 		 */
 		obj_desc = *(index_desc->reference.where);
 
@@ -309,6 +314,12 @@
 			if (new_desc == source_desc) {
 				acpi_ut_add_reference (new_desc);
 			}
+
+			/* Increment reference count by the ref count of the parent package -1 */
+
+			for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) {
+				acpi_ut_add_reference (new_desc);
+			}
 		}
 		break;
 
--- diff/drivers/acpi/executer/exstoren.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/executer/exstoren.c	2004-02-18 09:03:58.000000000 +0000
@@ -112,6 +112,12 @@
 			}
 		}
 
+		/* For copy_object, no further validation necessary */
+
+		if (walk_state->opcode == AML_COPY_OP) {
+			break;
+		}
+
 		/*
 		 * Must have a Integer, Buffer, or String
 		 */
@@ -136,7 +142,7 @@
 		/*
 		 * Aliases are resolved by acpi_ex_prep_operands
 		 */
-		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into Alias - should never happen\n"));
+		ACPI_REPORT_ERROR (("Store into Alias - should never happen\n"));
 		status = AE_AML_INTERNAL;
 		break;
 
--- diff/drivers/acpi/namespace/nsaccess.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/namespace/nsaccess.c	2004-02-18 09:03:58.000000000 +0000
@@ -314,7 +314,7 @@
 	else {
 		prefix_node = scope_info->scope.node;
 		if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p Not a namespace node [%s]\n",
+			ACPI_REPORT_ERROR (("ns_lookup: %p is not a namespace node [%s]\n",
 					prefix_node, acpi_ut_get_descriptor_name (prefix_node)));
 			return_ACPI_STATUS (AE_AML_INTERNAL);
 		}
--- diff/drivers/acpi/parser/psargs.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/acpi/parser/psargs.c	2004-02-18 09:03:58.000000000 +0000
@@ -315,8 +315,8 @@
 				acpi_ps_append_arg (arg, name_op);
 
 				if (!method_desc) {
-					ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
-						"Control Method - %p has no attached object\n",
+					ACPI_REPORT_ERROR ((
+						"ps_get_next_namepath: Control Method %p has no attached object\n",
 						node));
 					return_ACPI_STATUS (AE_AML_INTERNAL);
 				}
--- diff/drivers/acpi/tables.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/acpi/tables.c	2004-02-18 09:03:58.000000000 +0000
@@ -58,6 +58,7 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
--- diff/drivers/base/Makefile	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/base/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -2,7 +2,8 @@
 
 obj-y			:= core.o sys.o interface.o bus.o \
 			   driver.o class.o class_simple.o platform.o \
-			   cpu.o firmware.o init.o map.o dmapool.o
+			   cpu.o firmware.o init.o map.o
+obj-$(CONFIG_PCI)	+= dmapool.o
 obj-y			+= power/
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
--- diff/drivers/base/cpu.c	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/base/cpu.c	2004-02-18 09:03:58.000000000 +0000
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/topology.h>
+#include <linux/device.h>
 
 
 struct sysdev_class cpu_sysdev_class = {
@@ -14,6 +15,46 @@
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t show_online(struct sys_device *dev, char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+	return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id));
+}
+
+static ssize_t store_online(struct sys_device *dev, const char *buf,
+			    size_t count)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+	ssize_t ret;
+
+	switch (buf[0]) {
+	case '0':
+		ret = cpu_down(cpu->sysdev.id);
+		break;
+	case '1':
+		ret = cpu_up(cpu->sysdev.id);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret >= 0)
+		ret = count;
+	return ret;
+}
+static SYSDEV_ATTR(online, 0600, show_online, store_online);
+
+static void __init register_cpu_control(struct cpu *cpu)
+{
+	sysdev_create_file(&cpu->sysdev, &attr_online);
+}
+#else /* ... !CONFIG_HOTPLUG_CPU */
+static void __init register_cpu_control(struct cpu *cpu)
+{
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*
  * register_cpu - Setup a driverfs device for a CPU.
@@ -34,6 +75,8 @@
 		error = sysfs_create_link(&root->sysdev.kobj,
 					  &cpu->sysdev.kobj,
 					  kobject_name(&cpu->sysdev.kobj));
+	if (!error)
+		register_cpu_control(cpu);
 	return error;
 }
 
--- diff/drivers/base/dmapool.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/base/dmapool.c	2004-02-18 09:03:58.000000000 +0000
@@ -52,7 +52,7 @@
 	next = buf;
 	size = PAGE_SIZE;
 
-	temp = snprintf (next, size, "poolinfo - 0.1\n");
+	temp = scnprintf(next, size, "poolinfo - 0.1\n");
 	size -= temp;
 	next += temp;
 
@@ -67,7 +67,7 @@
 		}
 
 		/* per-pool info, no real statistics yet */
-		temp = snprintf (next, size, "%-16s %4u %4Zu %4Zu %2u\n",
+		temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
 				pool->name,
 				blocks, pages * pool->blocks_per_page,
 				pool->size, pages);
--- diff/drivers/base/node.c	2004-01-19 10:22:55.000000000 +0000
+++ source/drivers/base/node.c	2004-02-18 09:03:58.000000000 +0000
@@ -23,7 +23,7 @@
 
 	/* FIXME - someone should pass us a buffer size (count) or
 	 * use seq_file or something to avoid buffer overrun risk. */
-	len = cpumask_snprintf(buf, 99 /* XXX FIXME */, mask);
+	len = cpumask_scnprintf(buf, 99 /* XXX FIXME */, mask);
 	len += sprintf(buf + len, "\n");
 	return len;
 }
--- diff/drivers/block/Kconfig.iosched	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/block/Kconfig.iosched	2004-02-18 09:03:58.000000000 +0000
@@ -27,3 +27,10 @@
 	  a disk at any one time, its behaviour is almost identical to the
 	  anticipatory I/O scheduler and so is a good choice.
 
+config IOSCHED_CFQ
+	bool "CFQ I/O scheduler" if EMBEDDED
+	default y
+	---help---
+	  The CFQ I/O scheduler tries to distribute bandwidth equally
+	  among all processes in the system. It should provide a fair
+	  working environment, suitable for desktop systems.
--- diff/drivers/block/Makefile	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/block/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -18,6 +18,7 @@
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 obj-$(CONFIG_IOSCHED_AS)	+= as-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE)	+= deadline-iosched.o
+obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
 obj-$(CONFIG_BLK_DEV_FD98)	+= floppy98.o
--- diff/drivers/block/cryptoloop.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/block/cryptoloop.c	2004-02-18 09:03:58.000000000 +0000
@@ -87,43 +87,49 @@
 
 
 static int
-cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, char *raw_buf,
-		     char *loop_buf, int size, sector_t IV)
+cryptoloop_transfer_ecb(struct loop_device *lo, int cmd,
+			struct page *raw_page, unsigned raw_off,
+			struct page *loop_page, unsigned loop_off,
+			int size, sector_t IV)
 {
 	struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
 	struct scatterlist sg_out = { 0, };
 	struct scatterlist sg_in = { 0, };
 
 	encdec_ecb_t encdecfunc;
-	char const *in;
-	char *out;
+	struct page *in_page, *out_page;
+	unsigned in_offs, out_offs;
 
 	if (cmd == READ) {
-		in = raw_buf;
-		out = loop_buf;
+		in_page = raw_page;
+		in_offs = raw_off;
+		out_page = loop_page;
+		out_offs = loop_off;
 		encdecfunc = tfm->crt_u.cipher.cit_decrypt;
 	} else {
-		in = loop_buf;
-		out = raw_buf;
+		in_page = loop_page;
+		in_offs = loop_off;
+		out_page = raw_page;
+		out_offs = raw_off;
 		encdecfunc = tfm->crt_u.cipher.cit_encrypt;
 	}
 
 	while (size > 0) {
 		const int sz = min(size, LOOP_IV_SECTOR_SIZE);
 
-		sg_in.page = virt_to_page(in);
-		sg_in.offset = (unsigned long)in & ~PAGE_MASK;
+		sg_in.page = in_page;
+		sg_in.offset = in_offs;
 		sg_in.length = sz;
 
-		sg_out.page = virt_to_page(out);
-		sg_out.offset = (unsigned long)out & ~PAGE_MASK;
+		sg_out.page = out_page;
+		sg_out.offset = out_offs;
 		sg_out.length = sz;
 
 		encdecfunc(tfm, &sg_out, &sg_in, sz);
 
 		size -= sz;
-		in += sz;
-		out += sz;
+		in_offs += sz;
+		out_offs += sz;
 	}
 
 	return 0;
@@ -135,24 +141,30 @@
 			unsigned int nsg, u8 *iv);
 
 static int
-cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, char *raw_buf,
-		     char *loop_buf, int size, sector_t IV)
+cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
+			struct page *raw_page, unsigned raw_off,
+			struct page *loop_page, unsigned loop_off,
+			int size, sector_t IV)
 {
 	struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
 	struct scatterlist sg_out = { 0, };
 	struct scatterlist sg_in = { 0, };
 
 	encdec_cbc_t encdecfunc;
-	char const *in;
-	char *out;
+	struct page *in_page, *out_page;
+	unsigned in_offs, out_offs;
 
 	if (cmd == READ) {
-		in = raw_buf;
-		out = loop_buf;
+		in_page = raw_page;
+		in_offs = raw_off;
+		out_page = loop_page;
+		out_offs = loop_off;
 		encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
 	} else {
-		in = loop_buf;
-		out = raw_buf;
+		in_page = loop_page;
+		in_offs = loop_off;
+		out_page = raw_page;
+		out_offs = raw_off;
 		encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
 	}
 
@@ -161,39 +173,43 @@
 		u32 iv[4] = { 0, };
 		iv[0] = cpu_to_le32(IV & 0xffffffff);
 
-		sg_in.page = virt_to_page(in);
-		sg_in.offset = offset_in_page(in);
+		sg_in.page = in_page;
+		sg_in.offset = in_offs;
 		sg_in.length = sz;
 
-		sg_out.page = virt_to_page(out);
-		sg_out.offset = offset_in_page(out);
+		sg_out.page = out_page;
+		sg_out.offset = out_offs;
 		sg_out.length = sz;
 
 		encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
 
 		IV++;
 		size -= sz;
-		in += sz;
-		out += sz;
+		in_offs += sz;
+		out_offs += sz;
 	}
 
 	return 0;
 }
 
 static int
-cryptoloop_transfer(struct loop_device *lo, int cmd, char *raw_buf,
-		     char *loop_buf, int size, sector_t IV)
+cryptoloop_transfer(struct loop_device *lo, int cmd,
+		    struct page *raw_page, unsigned raw_off,
+		    struct page *loop_page, unsigned loop_off,
+		    int size, sector_t IV)
 {
 	struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
 	if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB)
 	{
 		lo->transfer = cryptoloop_transfer_ecb;
-		return cryptoloop_transfer_ecb(lo, cmd, raw_buf, loop_buf, size, IV);
+		return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off,
+					       loop_page, loop_off, size, IV);
 	}	
 	if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC)
 	{	
 		lo->transfer = cryptoloop_transfer_cbc;
-		return cryptoloop_transfer_cbc(lo, cmd, raw_buf, loop_buf, size, IV);
+		return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off,
+					       loop_page, loop_off, size, IV);
 	}
 	
 	/*  This is not supposed to happen */
--- diff/drivers/block/genhd.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/block/genhd.c	2004-02-18 09:03:58.000000000 +0000
@@ -262,8 +262,9 @@
 
 	/* Don't show non-partitionable removeable devices or empty devices */
 	if (!get_capacity(sgp) ||
-	    (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))
-		)
+			(sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
+		return 0;
+	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
 		return 0;
 
 	/* show the full disk and all non-0 size partitions of it */
--- diff/drivers/block/ll_rw_blk.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/block/ll_rw_blk.c	2004-02-18 09:03:58.000000000 +0000
@@ -27,6 +27,7 @@
 #include <linux/completion.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
+#include <linux/writeback.h>
 
 static void blk_unplug_work(void *data);
 static void blk_unplug_timeout(unsigned long data);
@@ -521,10 +522,10 @@
 {
 	int bits, i;
 
-	if (depth > q->nr_requests * 2) {
-		depth = q->nr_requests * 2;
-		printk(KERN_ERR "%s: adjusted depth to %d\n",
-				__FUNCTION__, depth);
+	if (depth > q->nr_requests / 2) {
+		q->nr_requests = depth * 2;
+		printk(KERN_INFO "%s: large TCQ depth: adjusted nr_requests "
+				 "to %lu\n", __FUNCTION__, q->nr_requests);
 	}
 
 	tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC);
@@ -1334,6 +1335,8 @@
 	&iosched_as;
 #elif defined(CONFIG_IOSCHED_DEADLINE)
 	&iosched_deadline;
+#elif defined(CONFIG_IOSCHED_CFQ)
+	&iosched_cfq;
 #elif defined(CONFIG_IOSCHED_NOOP)
 	&elevator_noop;
 #else
@@ -1352,6 +1355,10 @@
 	if (!strcmp(str, "as"))
 		chosen_elevator = &iosched_as;
 #endif
+#ifdef CONFIG_IOSCHED_CFQ
+	if (!strcmp(str, "cfq"))
+		chosen_elevator = &iosched_cfq;
+#endif
 #ifdef CONFIG_IOSCHED_NOOP
 	if (!strcmp(str, "noop"))
 		chosen_elevator = &elevator_noop;
@@ -1884,18 +1891,22 @@
  * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
  * If no queues are congested then just wait for the next request to be
  * returned.
+ *
+ * Returns the number of jiffies remaining, this is zero, unless we returned
+ * before @timeout expired.
  */
-void blk_congestion_wait(int rw, long timeout)
+long blk_congestion_wait(int rw, long timeout)
 {
+	long ret;
 	DEFINE_WAIT(wait);
 	wait_queue_head_t *wqh = &congestion_wqh[rw];
 
 	blk_run_queues();
 	prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
-	io_schedule_timeout(timeout);
+	ret = io_schedule_timeout(timeout);
 	finish_wait(wqh, &wait);
+	return ret;
 }
-
 EXPORT_SYMBOL(blk_congestion_wait);
 
 /*
@@ -2305,6 +2316,15 @@
 		mod_page_state(pgpgout, count);
 	else
 		mod_page_state(pgpgin, count);
+
+	if (unlikely(block_dump)) {
+		char b[BDEVNAME_SIZE];
+		printk("%s(%d): %s block %Lu on %s\n",
+			current->comm, current->pid,
+			(rw & WRITE) ? "WRITE" : "READ",
+			(unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b));
+	}
+
 	generic_make_request(bio);
 	return 1;
 }
@@ -2592,10 +2612,22 @@
 		unsigned long duration = jiffies - req->start_time;
 		switch (rq_data_dir(req)) {
 		    case WRITE:
+			/*
+			 * schedule the writeout of pending dirty data when the disk is idle.
+			 * (Writeback is not postponed by writes, only by reads.)
+			 */
+			if (unlikely(laptop_mode))
+				disk_is_spun_up(0);
 			disk_stat_inc(disk, writes);
 			disk_stat_add(disk, write_ticks, duration);
 			break;
 		    case READ:
+			/*
+			 * schedule the writeout of pending dirty data when the disk is idle.
+			 * (postpone writeback until system is quiescent again.)
+			 */
+			if (unlikely(laptop_mode))
+				disk_is_spun_up(1);
 			disk_stat_inc(disk, reads);
 			disk_stat_add(disk, read_ticks, duration);
 			break;
--- diff/drivers/block/loop.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/block/loop.c	2004-02-18 09:03:58.000000000 +0000
@@ -76,24 +76,34 @@
 /*
  * Transfer functions
  */
-static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf,
-			 char *loop_buf, int size, sector_t real_block)
+static int transfer_none(struct loop_device *lo, int cmd,
+			 struct page *raw_page, unsigned raw_off,
+			 struct page *loop_page, unsigned loop_off,
+			 int size, sector_t real_block)
 {
-	if (raw_buf != loop_buf) {
-		if (cmd == READ)
-			memcpy(loop_buf, raw_buf, size);
-		else
-			memcpy(raw_buf, loop_buf, size);
-	}
+	char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off;
+	char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off;
+
+	if (cmd == READ)
+		memcpy(loop_buf, raw_buf, size);
+	else
+		memcpy(raw_buf, loop_buf, size);
 
+	kunmap_atomic(raw_buf, KM_USER0);
+	kunmap_atomic(loop_buf, KM_USER1);
+	cond_resched();
 	return 0;
 }
 
-static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
-			char *loop_buf, int size, sector_t real_block)
+static int transfer_xor(struct loop_device *lo, int cmd,
+			struct page *raw_page, unsigned raw_off,
+			struct page *loop_page, unsigned loop_off,
+			int size, sector_t real_block)
 {
-	char	*in, *out, *key;
-	int	i, keysize;
+	char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off;
+	char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off;
+	char *in, *out, *key;
+	int i, keysize;
 
 	if (cmd == READ) {
 		in = raw_buf;
@@ -107,6 +117,10 @@
 	keysize = lo->lo_encrypt_key_size;
 	for (i = 0; i < size; i++)
 		*out++ = *in++ ^ key[(i & 511) % keysize];
+
+	kunmap_atomic(raw_buf, KM_USER0);
+	kunmap_atomic(loop_buf, KM_USER1);
+	cond_resched();
 	return 0;
 }
 
@@ -162,13 +176,15 @@
 }
 
 static inline int
-lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
-	       char *lbuf, int size, sector_t rblock)
+lo_do_transfer(struct loop_device *lo, int cmd,
+	       struct page *rpage, unsigned roffs,
+	       struct page *lpage, unsigned loffs,
+	       int size, sector_t rblock)
 {
 	if (!lo->transfer)
 		return 0;
 
-	return lo->transfer(lo, cmd, rbuf, lbuf, size, rblock);
+	return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock);
 }
 
 static int
@@ -178,16 +194,15 @@
 	struct address_space *mapping = file->f_mapping;
 	struct address_space_operations *aops = mapping->a_ops;
 	struct page *page;
-	char *kaddr, *data;
 	pgoff_t index;
-	unsigned size, offset;
+	unsigned size, offset, bv_offs;
 	int len;
 	int ret = 0;
 
 	down(&mapping->host->i_sem);
 	index = pos >> PAGE_CACHE_SHIFT;
 	offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1);
-	data = kmap(bvec->bv_page) + bvec->bv_offset;
+	bv_offs = bvec->bv_offset;
 	len = bvec->bv_len;
 	while (len > 0) {
 		sector_t IV;
@@ -204,25 +219,28 @@
 			goto fail;
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
-		kaddr = kmap(page);
-		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset,
-						 data, size, IV);
+		transfer_result = lo_do_transfer(lo, WRITE, page, offset,
+						 bvec->bv_page, bv_offs,
+						 size, IV);
 		if (transfer_result) {
+			char *kaddr;
+
 			/*
 			 * The transfer failed, but we still write the data to
 			 * keep prepare/commit calls balanced.
 			 */
 			printk(KERN_ERR "loop: transfer error block %llu\n",
 			       (unsigned long long)index);
+			kaddr = kmap_atomic(page, KM_USER0);
 			memset(kaddr + offset, 0, size);
+			kunmap_atomic(kaddr, KM_USER0);
 		}
 		flush_dcache_page(page);
-		kunmap(page);
 		if (aops->commit_write(file, page, offset, offset+size))
 			goto unlock;
 		if (transfer_result)
 			goto unlock;
-		data += size;
+		bv_offs += size;
 		len -= size;
 		offset = 0;
 		index++;
@@ -232,7 +250,6 @@
 	}
 	up(&mapping->host->i_sem);
 out:
-	kunmap(bvec->bv_page);
 	return ret;
 
 unlock:
@@ -247,12 +264,10 @@
 static int
 lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
 {
-	unsigned vecnr;
-	int ret = 0;
-
-	for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
-		struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
+	struct bio_vec *bvec;
+	int i, ret = 0;
 
+	bio_for_each_segment(bvec, bio, i) {
 		ret = do_lo_send(lo, bvec, bsize, pos);
 		if (ret < 0)
 			break;
@@ -263,7 +278,8 @@
 
 struct lo_read_data {
 	struct loop_device *lo;
-	char *data;
+	struct page *page;
+	unsigned offset;
 	int bsize;
 };
 
@@ -271,7 +287,6 @@
 lo_read_actor(read_descriptor_t *desc, struct page *page,
 	      unsigned long offset, unsigned long size)
 {
-	char *kaddr;
 	unsigned long count = desc->count;
 	struct lo_read_data *p = (struct lo_read_data*)desc->buf;
 	struct loop_device *lo = p->lo;
@@ -282,18 +297,16 @@
 	if (size > count)
 		size = count;
 
-	kaddr = kmap(page);
-	if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) {
+	if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) {
 		size = 0;
 		printk(KERN_ERR "loop: transfer error block %ld\n",
 		       page->index);
 		desc->error = -EINVAL;
 	}
-	kunmap(page);
 	
 	desc->count = count - size;
 	desc->written += size;
-	p->data += size;
+	p->offset += size;
 	return size;
 }
 
@@ -306,24 +319,22 @@
 	int retval;
 
 	cookie.lo = lo;
-	cookie.data = kmap(bvec->bv_page) + bvec->bv_offset;
+	cookie.page = bvec->bv_page;
+	cookie.offset = bvec->bv_offset;
 	cookie.bsize = bsize;
 	file = lo->lo_backing_file;
 	retval = file->f_op->sendfile(file, &pos, bvec->bv_len,
 			lo_read_actor, &cookie);
-	kunmap(bvec->bv_page);
 	return (retval < 0)? retval: 0;
 }
 
 static int
 lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
 {
-	unsigned vecnr;
-	int ret = 0;
-
-	for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
-		struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
+	struct bio_vec *bvec;
+	int i, ret = 0;
 
+	bio_for_each_segment(bvec, bio, i) {
 		ret = do_lo_receive(lo, bvec, bsize, pos);
 		if (ret < 0)
 			break;
@@ -345,23 +356,6 @@
 	return ret;
 }
 
-static int loop_end_io_transfer(struct bio *, unsigned int, int);
-
-static void loop_put_buffer(struct bio *bio)
-{
-	/*
-	 * check bi_end_io, may just be a remapped bio
-	 */
-	if (bio && bio->bi_end_io == loop_end_io_transfer) {
-		int i;
-
-		for (i = 0; i < bio->bi_vcnt; i++)
-			__free_page(bio->bi_io_vec[i].bv_page);
-
-		bio_put(bio);
-	}
-}
-
 /*
  * Add bio to back of pending list
  */
@@ -399,129 +393,8 @@
 	return bio;
 }
 
-/*
- * if this was a WRITE lo->transfer stuff has already been done. for READs,
- * queue it for the loop thread and let it do the transfer out of
- * bi_end_io context (we don't want to do decrypt of a page with irqs
- * disabled)
- */
-static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err)
-{
-	struct bio *rbh = bio->bi_private;
-	struct loop_device *lo = rbh->bi_bdev->bd_disk->private_data;
-
-	if (bio->bi_size)
-		return 1;
-
-	if (err || bio_rw(bio) == WRITE) {
-		bio_endio(rbh, rbh->bi_size, err);
-		if (atomic_dec_and_test(&lo->lo_pending))
-			up(&lo->lo_bh_mutex);
-		loop_put_buffer(bio);
-	} else
-		loop_add_bio(lo, bio);
-
-	return 0;
-}
-
-static struct bio *loop_copy_bio(struct bio *rbh)
-{
-	struct bio *bio;
-	struct bio_vec *bv;
-	int i;
-
-	bio = bio_alloc(__GFP_NOWARN, rbh->bi_vcnt);
-	if (!bio)
-		return NULL;
-
-	/*
-	 * iterate iovec list and alloc pages
-	 */
-	__bio_for_each_segment(bv, rbh, i, 0) {
-		struct bio_vec *bbv = &bio->bi_io_vec[i];
-
-		bbv->bv_page = alloc_page(__GFP_NOWARN|__GFP_HIGHMEM);
-		if (bbv->bv_page == NULL)
-			goto oom;
-
-		bbv->bv_len = bv->bv_len;
-		bbv->bv_offset = bv->bv_offset;
-	}
-
-	bio->bi_vcnt = rbh->bi_vcnt;
-	bio->bi_size = rbh->bi_size;
-
-	return bio;
-
-oom:
-	while (--i >= 0)
-		__free_page(bio->bi_io_vec[i].bv_page);
-
-	bio_put(bio);
-	return NULL;
-}
-
-static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh)
-{
-	struct bio *bio;
-
-	/*
-	 * When called on the page reclaim -> writepage path, this code can
-	 * trivially consume all memory.  So we drop PF_MEMALLOC to avoid
-	 * stealing all the page reserves and throttle to the writeout rate.
-	 * pdflush will have been woken by page reclaim.  Let it do its work.
-	 */
-	do {
-		int flags = current->flags;
-
-		current->flags &= ~PF_MEMALLOC;
-		bio = loop_copy_bio(rbh);
-		if (flags & PF_MEMALLOC)
-			current->flags |= PF_MEMALLOC;
-
-		if (bio == NULL)
-			blk_congestion_wait(WRITE, HZ/10);
-	} while (bio == NULL);
-
-	bio->bi_end_io = loop_end_io_transfer;
-	bio->bi_private = rbh;
-	bio->bi_sector = rbh->bi_sector + (lo->lo_offset >> 9);
-	bio->bi_rw = rbh->bi_rw;
-	bio->bi_bdev = lo->lo_device;
-
-	return bio;
-}
-
-static int loop_transfer_bio(struct loop_device *lo,
-			     struct bio *to_bio, struct bio *from_bio)
-{
-	sector_t IV;
-	struct bio_vec *from_bvec, *to_bvec;
-	char *vto, *vfrom;
-	int ret = 0, i;
-
-	IV = from_bio->bi_sector + (lo->lo_offset >> 9);
-
-	__bio_for_each_segment(from_bvec, from_bio, i, 0) {
-		to_bvec = &to_bio->bi_io_vec[i];
-
-		kmap(from_bvec->bv_page);
-		kmap(to_bvec->bv_page);
-		vfrom = page_address(from_bvec->bv_page) + from_bvec->bv_offset;
-		vto = page_address(to_bvec->bv_page) + to_bvec->bv_offset;
-		ret |= lo_do_transfer(lo, bio_data_dir(to_bio), vto, vfrom,
-					from_bvec->bv_len, IV);
-		kunmap(from_bvec->bv_page);
-		kunmap(to_bvec->bv_page);
-		IV += from_bvec->bv_len >> 9;
-	}
-
-	return ret;
-}
-		
 static int loop_make_request(request_queue_t *q, struct bio *old_bio)
 {
-	struct bio *new_bio = NULL;
 	struct loop_device *lo = q->queuedata;
 	int rw = bio_rw(old_bio);
 
@@ -543,31 +416,11 @@
 		printk(KERN_ERR "loop: unknown command (%x)\n", rw);
 		goto err;
 	}
-
-	/*
-	 * file backed, queue for loop_thread to handle
-	 */
-	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
-		loop_add_bio(lo, old_bio);
-		return 0;
-	}
-
-	/*
-	 * piggy old buffer on original, and submit for I/O
-	 */
-	new_bio = loop_get_buffer(lo, old_bio);
-	if (rw == WRITE) {
-		if (loop_transfer_bio(lo, new_bio, old_bio))
-			goto err;
-	}
-
-	generic_make_request(new_bio);
+	loop_add_bio(lo, old_bio);
 	return 0;
-
 err:
 	if (atomic_dec_and_test(&lo->lo_pending))
 		up(&lo->lo_bh_mutex);
-	loop_put_buffer(new_bio);
 out:
 	bio_io_error(old_bio, old_bio->bi_size);
 	return 0;
@@ -580,20 +433,8 @@
 {
 	int ret;
 
-	/*
-	 * For block backed loop, we know this is a READ
-	 */
-	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
-		ret = do_bio_filebacked(lo, bio);
-		bio_endio(bio, bio->bi_size, ret);
-	} else {
-		struct bio *rbh = bio->bi_private;
-
-		ret = loop_transfer_bio(lo, bio, rbh);
-
-		bio_endio(rbh, rbh->bi_size, ret);
-		loop_put_buffer(bio);
-	}
+	ret = do_bio_filebacked(lo, bio);
+	bio_endio(bio, bio->bi_size, ret);
 }
 
 /*
@@ -684,31 +525,23 @@
 		lo_flags |= LO_FLAGS_READ_ONLY;
 
 	error = -EINVAL;
-	if (S_ISBLK(inode->i_mode)) {
-		lo_device = I_BDEV(inode);
-		if (lo_device == bdev) {
-			error = -EBUSY;
-			goto out_putf;
-		}
-		lo_blocksize = block_size(lo_device);
-		if (bdev_read_only(lo_device))
-			lo_flags |= LO_FLAGS_READ_ONLY;
-	} else if (S_ISREG(inode->i_mode)) {
+	if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
 		struct address_space_operations *aops = mapping->a_ops;
 		/*
 		 * If we can't read - sorry. If we only can't write - well,
 		 * it's going to be read-only.
 		 */
-		if (!inode->i_fop->sendfile)
+		if (!lo_file->f_op->sendfile)
 			goto out_putf;
 
 		if (!aops->prepare_write || !aops->commit_write)
 			lo_flags |= LO_FLAGS_READ_ONLY;
 
 		lo_blocksize = inode->i_blksize;
-		lo_flags |= LO_FLAGS_DO_BMAP;
-	} else
+		error = 0;
+	} else {
 		goto out_putf;
+	}
 
 	if (!(lo_file->f_mode & FMODE_WRITE))
 		lo_flags |= LO_FLAGS_READ_ONLY;
@@ -738,21 +571,6 @@
 	blk_queue_make_request(lo->lo_queue, loop_make_request);
 	lo->lo_queue->queuedata = lo;
 
-	/*
-	 * we remap to a block device, make sure we correctly stack limits
-	 */
-	if (S_ISBLK(inode->i_mode)) {
-		request_queue_t *q = bdev_get_queue(lo_device);
-
-		blk_queue_max_sectors(lo->lo_queue, q->max_sectors);
-		blk_queue_max_phys_segments(lo->lo_queue,q->max_phys_segments);
-		blk_queue_max_hw_segments(lo->lo_queue, q->max_hw_segments);
-		blk_queue_hardsect_size(lo->lo_queue, queue_hardsect_size(q));
-		blk_queue_max_segment_size(lo->lo_queue, q->max_segment_size);
-		blk_queue_segment_boundary(lo->lo_queue, q->seg_boundary_mask);
-		blk_queue_merge_bvec(lo->lo_queue, q->merge_bvec_fn);
-	}
-
 	set_blocksize(bdev, lo_blocksize);
 
 	kernel_thread(loop_thread, lo, CLONE_KERNEL);
@@ -1196,7 +1014,6 @@
 		lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
 		if (!lo->lo_queue)
 			goto out_mem4;
-		disks[i]->queue = lo->lo_queue;
 		init_MUTEX(&lo->lo_ctl_mutex);
 		init_MUTEX_LOCKED(&lo->lo_sem);
 		init_MUTEX_LOCKED(&lo->lo_bh_mutex);
@@ -1209,14 +1026,18 @@
 		sprintf(disk->devfs_name, "loop/%d", i);
 		disk->private_data = lo;
 		disk->queue = lo->lo_queue;
-		add_disk(disk);
 	}
+
+	/* We cannot fail after we call this, so another loop!*/
+	for (i = 0; i < max_loop; i++)
+		add_disk(disks[i]);
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
 out_mem4:
 	while (i--)
 		blk_put_queue(loop_dev[i].lo_queue);
+	devfs_remove("loop");
 	i = max_loop;
 out_mem3:
 	while (i--)
--- diff/drivers/block/nbd.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/block/nbd.c	2004-02-18 09:03:58.000000000 +0000
@@ -741,6 +741,7 @@
 		disk->first_minor = i;
 		disk->fops = &nbd_fops;
 		disk->private_data = &nbd_dev[i];
+		disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
 		sprintf(disk->disk_name, "nbd%d", i);
 		sprintf(disk->devfs_name, "nbd/%d", i);
 		set_capacity(disk, 0x3ffffe);
--- diff/drivers/block/rd.c	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/block/rd.c	2004-02-18 09:03:58.000000000 +0000
@@ -1,15 +1,15 @@
 /*
  * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta.
- * 
- * (C) Chad Page, Theodore Ts'o, et. al, 1995. 
+ *
+ * (C) Chad Page, Theodore Ts'o, et. al, 1995.
  *
  * This RAM disk is designed to have filesystems created on it and mounted
- * just like a regular floppy disk.  
- *  
+ * just like a regular floppy disk.
+ *
  * It also does something suggested by Linus: use the buffer cache as the
  * RAM disk data.  This makes it possible to dynamically allocate the RAM disk
- * buffer - with some consequences I have to deal with as I write this. 
- * 
+ * buffer - with some consequences I have to deal with as I write this.
+ *
  * This code is based on the original ramdisk.c, written mostly by
  * Theodore Ts'o (TYT) in 1991.  The code was largely rewritten by
  * Chad Page to use the buffer cache to store the RAM disk data in
@@ -33,7 +33,7 @@
  *
  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
  *
- * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
+ * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB)
  *		- Chad Page
  *
  * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
@@ -60,7 +60,7 @@
 #include <asm/uaccess.h>
 
 /* The RAM disk size is now a parameter */
-#define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */ 
+#define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */
 
 /* Various static variables go here.  Most are used only in the RAM disk code.
  */
@@ -73,7 +73,7 @@
  * Parameters for the boot-loading of the RAM disk.  These are set by
  * init/main.c (from arguments to the kernel command line) or from the
  * architecture-specific setup routine (from the stored boot sector
- * information). 
+ * information).
  */
 int rd_size = CONFIG_BLK_DEV_RAM_SIZE;		/* Size of the RAM disks */
 /*
@@ -94,7 +94,7 @@
  *               2000 Transmeta Corp.
  * aops copied from ramfs.
  */
-static int ramdisk_readpage(struct file *file, struct page * page)
+static int ramdisk_readpage(struct file *file, struct page *page)
 {
 	if (!PageUptodate(page)) {
 		void *kaddr = kmap_atomic(page, KM_USER0);
@@ -108,7 +108,8 @@
 	return 0;
 }
 
-static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int ramdisk_prepare_write(struct file *file, struct page *page,
+				unsigned offset, unsigned to)
 {
 	if (!PageUptodate(page)) {
 		void *kaddr = kmap_atomic(page, KM_USER0);
@@ -122,7 +123,8 @@
 	return 0;
 }
 
-static int ramdisk_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int ramdisk_commit_write(struct file *file, struct page *page,
+				unsigned offset, unsigned to)
 {
 	return 0;
 }
@@ -212,7 +214,7 @@
  * 19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Added devfs support
  *
  */
-static int rd_make_request(request_queue_t * q, struct bio *bio)
+static int rd_make_request(request_queue_t *q, struct bio *bio)
 {
 	struct block_device *bdev = bio->bi_bdev;
 	struct address_space * mapping = bdev->bd_inode->i_mapping;
@@ -242,7 +244,8 @@
 	return 0;
 } 
 
-static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int rd_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
 {
 	int error;
 	struct block_device *bdev = inode->i_bdev;
@@ -250,9 +253,11 @@
 	if (cmd != BLKFLSBUF)
 		return -EINVAL;
 
-	/* special: we want to release the ramdisk memory,
-	   it's not like with the other blockdevices where
-	   this ioctl only flushes away the buffer cache. */
+	/*
+	 * special: we want to release the ramdisk memory, it's not like with
+	 * the other blockdevices where this ioctl only flushes away the buffer
+	 * cache
+	 */
 	error = -EBUSY;
 	down(&bdev->bd_sem);
 	if (bdev->bd_openers <= 2) {
@@ -268,7 +273,7 @@
 	.memory_backed	= 1,	/* Does not contribute to dirty memory */
 };
 
-static int rd_open(struct inode * inode, struct file * filp)
+static int rd_open(struct inode *inode, struct file *filp)
 {
 	unsigned unit = iminor(inode);
 
@@ -295,12 +300,14 @@
 	.ioctl =	rd_ioctl,
 };
 
-/* Before freeing the module, invalidate all of the protected buffers! */
-static void __exit rd_cleanup (void)
+/*
+ * Before freeing the module, invalidate all of the protected buffers!
+ */
+static void __exit rd_cleanup(void)
 {
 	int i;
 
-	for (i = 0 ; i < NUM_RAMDISKS; i++) {
+	for (i = 0; i < NUM_RAMDISKS; i++) {
 		struct block_device *bdev = rd_bdev[i];
 		rd_bdev[i] = NULL;
 		if (bdev) {
@@ -311,17 +318,19 @@
 		put_disk(rd_disks[i]);
 	}
 	devfs_remove("rd");
-	unregister_blkdev(RAMDISK_MAJOR, "ramdisk" );
+	unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
 }
 
-/* This is the registration and initialization section of the RAM disk driver */
-static int __init rd_init (void)
+/*
+ * This is the registration and initialization section of the RAM disk driver
+ */
+static int __init rd_init(void)
 {
 	int i;
 	int err = -ENOMEM;
 
 	if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
-	    (rd_blocksize & (rd_blocksize-1))) {
+			(rd_blocksize & (rd_blocksize-1))) {
 		printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
 		       rd_blocksize);
 		rd_blocksize = BLOCK_SIZE;
@@ -354,6 +363,7 @@
 		disk->first_minor = i;
 		disk->fops = &rd_bd_op;
 		disk->queue = rd_queue[i];
+		disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
 		sprintf(disk->disk_name, "ram%d", i);
 		sprintf(disk->devfs_name, "rd/%d", i);
 		set_capacity(disk, rd_size * 2);
@@ -362,8 +372,8 @@
 
 	/* rd_size is given in kB */
 	printk("RAMDISK driver initialized: "
-	       "%d RAM disks of %dK size %d blocksize\n",
-	       NUM_RAMDISKS, rd_size, rd_blocksize);
+		"%d RAM disks of %dK size %d blocksize\n",
+		NUM_RAMDISKS, rd_size, rd_blocksize);
 
 	return 0;
 out_queue:
--- diff/drivers/block/scsi_ioctl.c	2004-02-18 08:54:08.000000000 +0000
+++ source/drivers/block/scsi_ioctl.c	2004-02-18 09:03:58.000000000 +0000
@@ -312,7 +312,7 @@
 		return -EFAULT;
 	if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
 		return -EINVAL;
-	if (get_user(opcode, sic->data))
+	if (get_user(opcode, (int *)sic->data))
 		return -EFAULT;
 
 	bytes = max(in_len, out_len);
--- diff/drivers/char/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/Kconfig	2004-02-18 09:03:58.000000000 +0000
@@ -445,7 +445,8 @@
 source "drivers/serial/Kconfig"
 
 config UNIX98_PTYS
-	bool "Unix98 PTY support"
+	bool "Unix98 PTY support" if EMBEDDED
+	default y
 	---help---
 	  A pseudo terminal (PTY) is a software device consisting of two
 	  halves: a master and a slave. The slave device behaves identical to
@@ -463,28 +464,38 @@
 	  terminal slave can be accessed as /dev/pts/<number>. What was
 	  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
 
-	  The entries in /dev/pts/ are created on the fly by a virtual
-	  file system; therefore, if you say Y here you should say Y to
-	  "/dev/pts file system for Unix98 PTYs" as well.
-
-	  If you want to say Y here, you need to have the C library glibc 2.1
-	  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-	  Read the instructions in <file:Documentation/Changes> pertaining to
-	  pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
-	int "Maximum number of Unix98 PTYs in use (0-2048)"
-	depends on UNIX98_PTYS
+	  All modern Linux systems use the Unix98 ptys.  Say Y unless
+	  you're on an embedded system and want to conserve memory.
+
+config LEGACY_PTYS
+	bool "Legacy (BSD) PTY support"
+	default y
+	---help---
+	  A pseudo terminal (PTY) is a software device consisting of two
+	  halves: a master and a slave. The slave device behaves identical to
+	  a physical terminal; the master device is used by a process to
+	  read data from and write data to the slave, thereby emulating a
+	  terminal. Typical programs for the master side are telnet servers
+	  and xterms.
+
+	  Linux has traditionally used the BSD-like names /dev/ptyxx
+	  for masters and /dev/ttyxx for slaves of pseudo
+	  terminals. This scheme has a number of problems, including
+	  security.  This option enables these legacy devices; on most
+	  systems, it is safe to say N.
+
+
+config LEGACY_PTY_COUNT
+	int "Maximum number of legacy PTY in use"
+	depends on LEGACY_PTYS
 	default "256"
-	help
-	  The maximum number of Unix98 PTYs that can be used at any one time.
-	  The default is 256, and should be enough for desktop systems. Server
-	  machines which support incoming telnet/rlogin/ssh connections and/or
-	  serve several X terminals may want to increase this: every incoming
-	  connection and every xterm uses up one PTY.
+	---help---
+	  The maximum number of legacy PTYs that can be used at any one time.
+	  The default is 256, and should be more than enough.  Embedded
+	  systems may want to reduce this to save memory.
 
-	  When not in use, each additional set of 256 PTYs occupy
-	  approximately 8 KB of kernel memory on 32-bit architectures.
+	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
+	  architectures and 24 bytes on 64-bit architectures.
 
 config PRINTER
 	tristate "Parallel printer support"
@@ -588,30 +599,6 @@
 	bool "Support for console on line printer"
 	depends on PC9800_OLDLP
 
-
-menu "Mice"
-
-config BUSMOUSE
-	tristate "Bus Mouse Support"
-	---help---
-	  Say Y here if your machine has a bus mouse as opposed to a serial
-	  mouse. Most people have a regular serial MouseSystem or
-	  Microsoft mouse (made by Logitech) that plugs into a COM port
-	  (rectangular with 9 or 25 pins). These people say N here. 
-
-	  If you have a laptop, you either have to check the documentation or
-	  experiment a bit to find out whether the trackball is a serial mouse
-	  or not; it's best to say Y here for you.
-
-	  This is the generic bus mouse driver code. If you have a bus mouse,
-	  you will have to say Y here and also to the specific driver for your
-	  mouse below.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called busmouse.
-
-endmenu
-
 config QIC02_TAPE
 	tristate "QIC-02 tape support"
 	help
@@ -794,8 +781,7 @@
 	  precision in some cases.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called genrtc. To load the module automatically
-	  add 'alias char-major-10-135 genrtc' to your /etc/modules.conf
+	  module will be called genrtc.
 
 config GEN_RTC_X
 	bool "Extended RTC operation"
--- diff/drivers/char/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/Makefile	2004-02-18 09:03:58.000000000 +0000
@@ -49,7 +49,6 @@
 obj-$(CONFIG_TIPAR) += tipar.o
 obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o
 
-obj-$(CONFIG_BUSMOUSE) += busmouse.o
 obj-$(CONFIG_DTLK) += dtlk.o
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
--- diff/drivers/char/agp/intel-agp.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/char/agp/intel-agp.c	2004-02-18 09:03:58.000000000 +0000
@@ -1432,6 +1432,8 @@
 		intel_configure();
 	else if (bridge->driver == &intel_845_driver)
 		intel_845_configure();
+	else if (bridge->driver == &intel_830mp_driver)
+		intel_830mp_configure();
 
 	return 0;
 }
--- diff/drivers/char/amiserial.c	2003-10-09 09:47:33.000000000 +0100
+++ source/drivers/char/amiserial.c	2004-02-18 09:03:58.000000000 +0000
@@ -1248,57 +1248,48 @@
 }
 
 
-static int get_modem_info(struct async_struct * info, unsigned int *value)
+static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	unsigned char control, status;
-	unsigned int result;
 	unsigned long flags;
 
+	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
 	control = info->MCR;
 	local_irq_save(flags);
 	status = ciab.pra;
 	local_irq_restore(flags);
-	result =  ((control & SER_RTS) ? TIOCM_RTS : 0)
+	return    ((control & SER_RTS) ? TIOCM_RTS : 0)
 		| ((control & SER_DTR) ? TIOCM_DTR : 0)
 		| (!(status  & SER_DCD) ? TIOCM_CAR : 0)
 		| (!(status  & SER_DSR) ? TIOCM_DSR : 0)
 		| (!(status  & SER_CTS) ? TIOCM_CTS : 0);
-	if (copy_to_user(value, &result, sizeof(int)))
-		return -EFAULT;
-	return 0;
 }
 
-static int set_modem_info(struct async_struct * info, unsigned int cmd,
-			  unsigned int *value)
+static int rs_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
 {
-	unsigned int arg;
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
 
-	if (copy_from_user(&arg, value, sizeof(int)))
-		return -EFAULT;
+	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
-	switch (cmd) {
-	case TIOCMBIS: 
-	        if (arg & TIOCM_RTS)
-			info->MCR |= SER_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR |= SER_DTR;
-		break;
-	case TIOCMBIC:
-	        if (arg & TIOCM_RTS)
-			info->MCR &= ~SER_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR &= ~SER_DTR;
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(SER_RTS | SER_DTR))
-			     | ((arg & TIOCM_RTS) ? SER_RTS : 0)
-			     | ((arg & TIOCM_DTR) ? SER_DTR : 0));
-		break;
-	default:
-		return -EINVAL;
-	}
 	local_irq_save(flags);
+	if (set & TIOCM_RTS)
+		info->MCR |= SER_RTS;
+	if (set & TIOCM_DTR)
+		info->MCR |= SER_DTR;
+	if (clear & TIOCM_RTS)
+		info->MCR &= ~SER_RTS;
+	if (clear & TIOCM_DTR)
+		info->MCR &= ~SER_DTR;
 	rtsdtr_ctrl(info->MCR);
 	local_irq_restore(flags);
 	return 0;
@@ -1344,12 +1335,6 @@
 	}
 
 	switch (cmd) {
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
 			return get_serial_info(info,
 					       (struct serial_struct *) arg);
@@ -2045,6 +2030,8 @@
 	.send_xchar = rs_send_xchar,
 	.wait_until_sent = rs_wait_until_sent,
 	.read_proc = rs_read_proc,
+	.tiocmget = rs_tiocmget,
+	.tiocmset = rs_tiocmset,
 };
 
 /*
--- diff/drivers/char/cyclades.c	2003-10-09 09:47:33.000000000 +0100
+++ source/drivers/char/cyclades.c	2004-02-18 09:03:58.000000000 +0000
@@ -3632,8 +3632,9 @@
 }
 
 static int
-get_modem_info(struct cyclades_port * info, unsigned int *value)
+cy_tiocmget(struct tty_struct *tty, struct file *file)
 {
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   int card,chip,channel,index;
   unsigned char *base_addr;
   unsigned long flags;
@@ -3645,6 +3646,9 @@
   struct BOARD_CTRL *board_ctrl;
   struct CH_CTRL *ch_ctrl;
 
+    if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+	return -ENODEV;
+
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
     if (!IS_CYC_Z(cy_card[card])) {
@@ -3700,24 +3704,27 @@
 	}
 
     }
-    return cy_put_user(result, value);
-} /* get_modem_info */
+    return result;
+} /* cy_tiomget */
 
 
 static int
-set_modem_info(struct cyclades_port * info, unsigned int cmd,
-                          unsigned int *value)
+cy_tiocmset(struct tty_struct *tty, struct file *file,
+            unsigned int set, unsigned int clear)
 {
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   int card,chip,channel,index;
   unsigned char *base_addr;
   unsigned long flags;
-  unsigned int arg = cy_get_user((unsigned long *) value);
   struct FIRM_ID *firm_id;
   struct ZFW_CTRL *zfw_ctrl;
   struct BOARD_CTRL *board_ctrl;
   struct CH_CTRL *ch_ctrl;
   int retval;
 
+    if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+	return -ENODEV;
+
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
     if (!IS_CYC_Z(cy_card[card])) {
@@ -3728,66 +3735,7 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	switch (cmd) {
-	case TIOCMBIS:
-	    if (arg & TIOCM_RTS){
-		CY_LOCK(info, flags);
-		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
-                if (info->rtsdtr_inv) {
-		    cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
-                } else {
-		    cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
-                }
-		CY_UNLOCK(info, flags);
-	    }
-	    if (arg & TIOCM_DTR){
-		CY_LOCK(info, flags);
-		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
-                if (info->rtsdtr_inv) {
-		    cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
-                } else {
-		    cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
-                }
-#ifdef CY_DEBUG_DTR
-		printk("cyc:set_modem_info raising DTR\n");
-		printk("     status: 0x%x, 0x%x\n",
-		    cy_readb(base_addr+(CyMSVR1<<index)), 
-                    cy_readb(base_addr+(CyMSVR2<<index)));
-#endif
-		CY_UNLOCK(info, flags);
-	    }
-	    break;
-	case TIOCMBIC:
-	    if (arg & TIOCM_RTS){
-		CY_LOCK(info, flags);
-		cy_writeb((u_long)base_addr+(CyCAR<<index), 
-                          (u_char)channel);
-                if (info->rtsdtr_inv) {
-		    	cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
-                } else {
-		    	cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
-                }
-		CY_UNLOCK(info, flags);
-	    }
-	    if (arg & TIOCM_DTR){
-		CY_LOCK(info, flags);
-		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
-                if (info->rtsdtr_inv) {
-			cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
-                } else {
-			cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
-                }
-#ifdef CY_DEBUG_DTR
-		printk("cyc:set_modem_info dropping DTR\n");
-		printk("     status: 0x%x, 0x%x\n",
-		    cy_readb(base_addr+(CyMSVR1<<index)), 
-                    cy_readb(base_addr+(CyMSVR2<<index)));
-#endif
-		CY_UNLOCK(info, flags);
-	    }
-	    break;
-	case TIOCMSET:
-	    if (arg & TIOCM_RTS){
+	if (set & TIOCM_RTS){
 		CY_LOCK(info, flags);
 	        cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
@@ -3796,7 +3744,8 @@
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
                 }
 		CY_UNLOCK(info, flags);
-	    }else{
+	}
+	if (clear & TIOCM_RTS) {
 		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
@@ -3805,8 +3754,8 @@
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
                 }
 		CY_UNLOCK(info, flags);
-	    }
-	    if (arg & TIOCM_DTR){
+	}
+	if (set & TIOCM_DTR){
 		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
@@ -3821,7 +3770,8 @@
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 		CY_UNLOCK(info, flags);
-	    }else{
+	}
+	if (clear & TIOCM_DTR) {
 		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
@@ -3837,10 +3787,6 @@
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 		CY_UNLOCK(info, flags);
-	    }
-	    break;
-	default:
-	    return -EINVAL;
 	}
     } else {
 	base_addr = (unsigned char*) (cy_card[card].base_addr);
@@ -3854,54 +3800,19 @@
 	    board_ctrl = &zfw_ctrl->board_ctrl;
 	    ch_ctrl = zfw_ctrl->ch_ctrl;
 
-	    switch (cmd) {
-	    case TIOCMBIS:
-		if (arg & TIOCM_RTS){
-		    CY_LOCK(info, flags);
-		    cy_writel(&ch_ctrl[channel].rs_control,
-                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
-		    CY_UNLOCK(info, flags);
-		}
-		if (arg & TIOCM_DTR){
-		    CY_LOCK(info, flags);
-		    cy_writel(&ch_ctrl[channel].rs_control,
-                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
-#ifdef CY_DEBUG_DTR
-		    printk("cyc:set_modem_info raising Z DTR\n");
-#endif
-		    CY_UNLOCK(info, flags);
-		}
-		break;
-	    case TIOCMBIC:
-		if (arg & TIOCM_RTS){
-		    CY_LOCK(info, flags);
-		    cy_writel(&ch_ctrl[channel].rs_control,
-                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
-		    CY_UNLOCK(info, flags);
-		}
-		if (arg & TIOCM_DTR){
-		    CY_LOCK(info, flags);
-		    cy_writel(&ch_ctrl[channel].rs_control,
-                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
-#ifdef CY_DEBUG_DTR
-		    printk("cyc:set_modem_info clearing Z DTR\n");
-#endif
-		    CY_UNLOCK(info, flags);
-		}
-		break;
-	    case TIOCMSET:
-		if (arg & TIOCM_RTS){
+	    if (set & TIOCM_RTS){
 		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
 		    CY_UNLOCK(info, flags);
-		}else{
+	    }
+	    if (clear & TIOCM_RTS) {
 		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
 		    CY_UNLOCK(info, flags);
-		}
-		if (arg & TIOCM_DTR){
+	    }
+	    if (set & TIOCM_DTR){
 		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
@@ -3909,7 +3820,8 @@
 		    printk("cyc:set_modem_info raising Z DTR\n");
 #endif
 		    CY_UNLOCK(info, flags);
-		}else{
+	    }
+	    if (clear & TIOCM_DTR) {
 		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
@@ -3917,10 +3829,6 @@
 		    printk("cyc:set_modem_info clearing Z DTR\n");
 #endif
 		    CY_UNLOCK(info, flags);
-		}
-		break;
-	    default:
-		return -EINVAL;
 	    }
 	}else{
 	    return -ENODEV;
@@ -3935,7 +3843,7 @@
 	CY_UNLOCK(info, flags);
     }
     return 0;
-} /* set_modem_info */
+} /* cy_tiocmset */
 
 /*
  * cy_break() --- routine which turns the break handling on or off
@@ -4242,14 +4150,6 @@
 	case CYGETWAIT:
 	    ret_val = info->closing_wait / (HZ/100);
 	    break;
-        case TIOCMGET:
-            ret_val = get_modem_info(info, (unsigned int *) arg);
-            break;
-        case TIOCMBIS:
-        case TIOCMBIC:
-        case TIOCMSET:
-            ret_val = set_modem_info(info, cmd, (unsigned int *) arg);
-            break;
         case TIOCGSERIAL:
             ret_val = get_serial_info(info, (struct serial_struct *) arg);
             break;
@@ -5429,6 +5329,8 @@
     .break_ctl = cy_break,
     .wait_until_sent = cy_wait_until_sent,
     .read_proc = cyclades_get_proc_info,
+    .tiocmget = cy_tiocmget,
+    .tiocmset = cy_tiocmset,
 };
 
 static int __init
--- diff/drivers/char/drm/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/drm/Kconfig	2004-02-18 09:03:58.000000000 +0000
@@ -76,7 +76,7 @@
 	tristate "SiS video cards"
 	depends on DRM && AGP
 	help
-	  Choose this option if you have a SiS 630 or compatibel video 
+	  Choose this option if you have a SiS 630 or compatible video 
           chipset. If M is selected the module will be called sis. AGP
           support is required for this driver to work.
 
--- diff/drivers/char/drm/drm.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm.h	2004-02-18 09:03:58.000000000 +0000
@@ -580,6 +580,16 @@
 	unsigned long handle;	/**< Used for mapping / unmapping */
 } drm_scatter_gather_t;
 
+/**
+ * DRM_IOCTL_SET_VERSION ioctl argument type.
+ */
+typedef struct drm_set_version {
+	int drm_di_major;
+	int drm_di_minor;
+	int drm_dd_major;
+	int drm_dd_minor;
+} drm_set_version_t;
+
 
 #define DRM_IOCTL_BASE			'd'
 #define DRM_IO(nr)			_IO(DRM_IOCTL_BASE,nr)
@@ -594,6 +604,7 @@
 #define DRM_IOCTL_GET_MAP               DRM_IOWR(0x04, drm_map_t)
 #define DRM_IOCTL_GET_CLIENT            DRM_IOWR(0x05, drm_client_t)
 #define DRM_IOCTL_GET_STATS             DRM_IOR( 0x06, drm_stats_t)
+#define DRM_IOCTL_SET_VERSION		DRM_IOWR(0x07, drm_set_version_t)
 
 #define DRM_IOCTL_SET_UNIQUE		DRM_IOW( 0x10, drm_unique_t)
 #define DRM_IOCTL_AUTH_MAGIC		DRM_IOW( 0x11, drm_auth_t)
--- diff/drivers/char/drm/drmP.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/char/drm/drmP.h	2004-02-18 09:03:58.000000000 +0000
@@ -92,8 +92,8 @@
 #ifndef __HAVE_DMA
 #define __HAVE_DMA		0
 #endif
-#ifndef __HAVE_DMA_IRQ
-#define __HAVE_DMA_IRQ		0
+#ifndef __HAVE_IRQ
+#define __HAVE_IRQ		0
 #endif
 #ifndef __HAVE_DMA_WAITLIST
 #define __HAVE_DMA_WAITLIST	0
@@ -324,6 +324,7 @@
 #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
 #define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
 
+#define DRM_IF_VERSION(maj, min) ((maj) << 16 | (min))
 /**
  * Get the private SAREA mapping.
  *
@@ -362,10 +363,13 @@
 typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
 			 unsigned int cmd, unsigned long arg );
 
-typedef struct drm_pci_list {
-	u16 vendor;
-	u16 device;
-} drm_pci_list_t;
+typedef struct drm_pci_id_list
+{
+	int vendor;
+	int device;
+	long driver_private;
+	char *name;
+} drm_pci_id_list_t;
 
 typedef struct drm_ioctl_desc {
 	drm_ioctl_t	     *func;
@@ -488,6 +492,9 @@
 	struct drm_device *dev;
 	int 		  remove_auth_on_close;
 	unsigned long     lock_count;
+#ifdef DRIVER_FILE_FIELDS
+	DRIVER_FILE_FIELDS;
+#endif
 } drm_file_t;
 
 /** Wait queue */
@@ -622,6 +629,8 @@
 	int		  unique_len;	/**< Length of unique field */
 	dev_t		  device;	/**< Device number for mknod */
 	char		  *devname;	/**< For /proc/interrupts */
+	int		  minor;        /**< Minor device number */
+	int		  if_version;	/**< Highest interface version set */
 
 	int		  blocked;	/**< Blocked due to VC switch? */
 	struct proc_dir_entry *root;	/**< Root for this device's entries */
@@ -679,6 +688,7 @@
 	/** \name Context support */
 	/*@{*/
 	int		  irq;		/**< Interrupt used by board */
+	int		  irq_enabled;	/**< True if irq handler is enabled */
 	__volatile__ long context_flag;	/**< Context swapping flag */
 	__volatile__ long interrupt_flag; /**< Interruption handler flag */
 	__volatile__ long dma_flag;	/**< DMA dispatch flag */
@@ -714,7 +724,12 @@
 #if __REALLY_HAVE_AGP
 	drm_agp_head_t    *agp;	/**< AGP data */
 #endif
-	struct pci_dev *pdev;		/**< PCI device structure */
+
+	struct pci_dev    *pdev;	/**< PCI device structure */
+	int               pci_domain;	/**< PCI bus domain number */
+	int               pci_bus;	/**< PCI bus number */
+	int               pci_slot;	/**< PCI slot number */
+	int               pci_func;	/**< PCI function number */
 #ifdef __alpha__
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
 	struct pci_controler *hose;
@@ -804,8 +819,8 @@
 #endif
 
 				/* Misc. IOCTL support (drm_ioctl.h) */
-extern int	     DRM(irq_busid)(struct inode *inode, struct file *filp,
-				    unsigned int cmd, unsigned long arg);
+extern int	     DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+				       unsigned int cmd, unsigned long arg);
 extern int	     DRM(getunique)(struct inode *inode, struct file *filp,
 				    unsigned int cmd, unsigned long arg);
 extern int	     DRM(setunique)(struct inode *inode, struct file *filp,
@@ -816,6 +831,8 @@
 				    unsigned int cmd, unsigned long arg);
 extern int	     DRM(getstats)(struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg);
+extern int	     DRM(setversion)(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
 
 				/* Context IOCTL support (drm_context.h) */
 extern int	     DRM(resctx)( struct inode *inode, struct file *filp,
@@ -900,12 +917,17 @@
 extern void	     DRM(dma_takedown)(drm_device_t *dev);
 extern void	     DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf);
 extern void	     DRM(reclaim_buffers)( struct file *filp );
-#if __HAVE_DMA_IRQ
+#endif /* __HAVE_DMA */
+
+				/* IRQ support (drm_irq.h) */
+#if __HAVE_IRQ || __HAVE_DMA
 extern int           DRM(control)( struct inode *inode, struct file *filp,
 				   unsigned int cmd, unsigned long arg );
-extern int           DRM(irq_install)( drm_device_t *dev, int irq );
+#endif
+#if __HAVE_IRQ
+extern int           DRM(irq_install)( drm_device_t *dev );
 extern int           DRM(irq_uninstall)( drm_device_t *dev );
-extern irqreturn_t   DRM(dma_service)( DRM_IRQ_ARGS );
+extern irqreturn_t   DRM(irq_handler)( DRM_IRQ_ARGS );
 extern void          DRM(driver_irq_preinstall)( drm_device_t *dev );
 extern void          DRM(driver_irq_postinstall)( drm_device_t *dev );
 extern void          DRM(driver_irq_uninstall)( drm_device_t *dev );
@@ -915,12 +937,11 @@
 extern int           DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
 extern void          DRM(vbl_send_signals)( drm_device_t *dev );
 #endif
-#if __HAVE_DMA_IRQ_BH
-extern void          DRM(dma_immediate_bh)( void *dev );
+#if __HAVE_IRQ_BH
+extern void          DRM(irq_immediate_bh)( void *dev );
 #endif
 #endif
 
-#endif /* __HAVE_DMA */
 
 #if __REALLY_HAVE_AGP
 				/* AGP/GART support (drm_agpsupport.h) */
--- diff/drivers/char/drm/drm_bufs.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_bufs.h	2004-02-18 09:03:58.000000000 +0000
@@ -147,7 +147,9 @@
 					      MTRR_TYPE_WRCOMB, 1 );
 		}
 #endif
-		map->handle = DRM(ioremap)( map->offset, map->size, dev );
+		if (map->type == _DRM_REGISTERS)
+			map->handle = DRM(ioremap)( map->offset, map->size,
+						    dev );
 		break;
 
 	case _DRM_SHM:
@@ -160,6 +162,12 @@
 		}
 		map->offset = (unsigned long)map->handle;
 		if ( map->flags & _DRM_CONTAINS_LOCK ) {
+			/* Prevent a 2nd X Server from creating a 2nd lock */
+			if (dev->lock.hw_lock != NULL) {
+				vfree( map->handle );
+				DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+				return -EBUSY;
+			}
 			dev->sigdata.lock =
 			dev->lock.hw_lock = map->handle; /* Pointer to lock */
 		}
--- diff/drivers/char/drm/drm_dma.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_dma.h	2004-02-18 09:03:58.000000000 +0000
@@ -43,15 +43,6 @@
 #ifndef __HAVE_DMA_RECLAIM
 #define __HAVE_DMA_RECLAIM	0
 #endif
-#ifndef __HAVE_SHARED_IRQ
-#define __HAVE_SHARED_IRQ	0
-#endif
-
-#if __HAVE_SHARED_IRQ
-#define DRM_IRQ_TYPE		SA_SHIRQ
-#else
-#define DRM_IRQ_TYPE		0
-#endif
 
 #if __HAVE_DMA
 
@@ -214,293 +205,11 @@
 }
 #endif
 
-
-
-
-#if __HAVE_DMA_IRQ
-
-/**
- * Install IRQ handler.
- *
- * \param dev DRM device.
- * \param irq IRQ number.
- *
- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
- * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
- * before and after the installation.
- */
-int DRM(irq_install)( drm_device_t *dev, int irq )
-{
-	int ret;
-
-	if ( !irq )
-		return -EINVAL;
-
-	down( &dev->struct_sem );
-
-	/* Driver must have been initialized */
-	if ( !dev->dev_private ) {
-		up( &dev->struct_sem );
-		return -EINVAL;
-	}
-
-	if ( dev->irq ) {
-		up( &dev->struct_sem );
-		return -EBUSY;
-	}
-	dev->irq = irq;
-	up( &dev->struct_sem );
-
-	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
-
-	dev->context_flag = 0;
-	dev->interrupt_flag = 0;
-	dev->dma_flag = 0;
-
-	dev->dma->next_buffer = NULL;
-	dev->dma->next_queue = NULL;
-	dev->dma->this_buffer = NULL;
-
-#if __HAVE_DMA_IRQ_BH
-	INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev);
-#endif
-
-#if __HAVE_VBL_IRQ
-	init_waitqueue_head(&dev->vbl_queue);
-
-	spin_lock_init( &dev->vbl_lock );
-
-	INIT_LIST_HEAD( &dev->vbl_sigs.head );
-
-	dev->vbl_pending = 0;
-#endif
-
-				/* Before installing handler */
-	DRM(driver_irq_preinstall)(dev);
-
-				/* Install handler */
-	ret = request_irq( dev->irq, DRM(dma_service),
-			   DRM_IRQ_TYPE, dev->devname, dev );
-	if ( ret < 0 ) {
-		down( &dev->struct_sem );
-		dev->irq = 0;
-		up( &dev->struct_sem );
-		return ret;
-	}
-
-				/* After installing handler */
-	DRM(driver_irq_postinstall)(dev);
-
-	return 0;
-}
-
-/**
- * Uninstall the IRQ handler.
- *
- * \param dev DRM device.
- *
- * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq.
- */
-int DRM(irq_uninstall)( drm_device_t *dev )
-{
-	int irq;
-
-	down( &dev->struct_sem );
-	irq = dev->irq;
-	dev->irq = 0;
-	up( &dev->struct_sem );
-
-	if ( !irq )
-		return -EINVAL;
-
-	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
-
-	DRM(driver_irq_uninstall)( dev );
-
-	free_irq( irq, dev );
-
-	return 0;
-}
-
-/**
- * IRQ control ioctl.
- *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_control structure.
- * \return zero on success or a negative number on failure.
- *
- * Calls irq_install() or irq_uninstall() according to \p arg.
- */
-int DRM(control)( struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg )
-{
-	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
-	drm_control_t ctl;
-
-	if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
-		return -EFAULT;
-
-	switch ( ctl.func ) {
-	case DRM_INST_HANDLER:
-		return DRM(irq_install)( dev, ctl.irq );
-	case DRM_UNINST_HANDLER:
-		return DRM(irq_uninstall)( dev );
-	default:
-		return -EINVAL;
-	}
-}
-
-#if __HAVE_VBL_IRQ
-
-/**
- * Wait for VBLANK.
- *
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param data user argument, pointing to a drm_wait_vblank structure.
- * \return zero on success or a negative number on failure.
- *
- * Verifies the IRQ is installed. 
- *
- * If a signal is requested checks if this task has already scheduled the same signal
- * for the same vblank sequence number - nothing to be done in
- * that case. If the number of tasks waiting for the interrupt exceeds 100 the
- * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
- * task.
- *
- * If a signal is not requested, then calls vblank_wait().
- */
-int DRM(wait_vblank)( DRM_IOCTL_ARGS )
-{
-	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
-	drm_wait_vblank_t vblwait;
-	struct timeval now;
-	int ret = 0;
-	unsigned int flags;
-
-	if (!dev->irq)
-		return -EINVAL;
-
-	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
-				  sizeof(vblwait) );
-
-	switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
-	case _DRM_VBLANK_RELATIVE:
-		vblwait.request.sequence += atomic_read( &dev->vbl_received );
-		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
-	case _DRM_VBLANK_ABSOLUTE:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
-	
-	if ( flags & _DRM_VBLANK_SIGNAL ) {
-		unsigned long irqflags;
-		drm_vbl_sig_t *vbl_sig;
-		
-		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
-
-		spin_lock_irqsave( &dev->vbl_lock, irqflags );
-
-		/* Check if this task has already scheduled the same signal
-		 * for the same vblank sequence number; nothing to be done in
-		 * that case
-		 */
-		list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
-			if (vbl_sig->sequence == vblwait.request.sequence
-			    && vbl_sig->info.si_signo == vblwait.request.signal
-			    && vbl_sig->task == current)
-			{
-				spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-				goto done;
-			}
-		}
-
-		if ( dev->vbl_pending >= 100 ) {
-			spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-			return -EBUSY;
-		}
-
-		dev->vbl_pending++;
-
-		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-
-		if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
-			return -ENOMEM;
-		}
-
-		memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
-
-		vbl_sig->sequence = vblwait.request.sequence;
-		vbl_sig->info.si_signo = vblwait.request.signal;
-		vbl_sig->task = current;
-
-		spin_lock_irqsave( &dev->vbl_lock, irqflags );
-
-		list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
-
-		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
-	} else {
-		ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
-
-		do_gettimeofday( &now );
-		vblwait.reply.tval_sec = now.tv_sec;
-		vblwait.reply.tval_usec = now.tv_usec;
-	}
-
-done:
-	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
-				sizeof(vblwait) );
-
-	return ret;
-}
-
-/**
- * Send the VBLANK signals.
- *
- * \param dev DRM device.
- *
- * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
- *
- * If a signal is not requested, then calls vblank_wait().
+#if !__HAVE_IRQ
+/* This stub DRM_IOCTL_CONTROL handler is for the drivers that used to require
+ * IRQs for DMA but no longer do.  It maintains compatibility with the X Servers
+ * that try to use the control ioctl by simply returning success.
  */
-void DRM(vbl_send_signals)( drm_device_t *dev )
-{
-	struct list_head *list, *tmp;
-	drm_vbl_sig_t *vbl_sig;
-	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
-	unsigned long flags;
-
-	spin_lock_irqsave( &dev->vbl_lock, flags );
-
-	list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
-		vbl_sig = list_entry( list, drm_vbl_sig_t, head );
-		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
-			vbl_sig->info.si_code = vbl_seq;
-			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
-
-			list_del( list );
-
-			DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
-
-			dev->vbl_pending--;
-		}
-	}
-
-	spin_unlock_irqrestore( &dev->vbl_lock, flags );
-}
-
-#endif	/* __HAVE_VBL_IRQ */
-
-#else
-
 int DRM(control)( struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg )
 {
@@ -517,7 +226,6 @@
 		return -EINVAL;
 	}
 }
-
-#endif /* __HAVE_DMA_IRQ */
+#endif
 
 #endif /* __HAVE_DMA */
--- diff/drivers/char/drm/drm_drv.h	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/char/drm/drm_drv.h	2004-02-18 09:03:58.000000000 +0000
@@ -58,8 +58,8 @@
 #ifndef __HAVE_CTX_BITMAP
 #define __HAVE_CTX_BITMAP		0
 #endif
-#ifndef __HAVE_DMA_IRQ
-#define __HAVE_DMA_IRQ			0
+#ifndef __HAVE_IRQ
+#define __HAVE_IRQ			0
 #endif
 #ifndef __HAVE_DMA_QUEUE
 #define __HAVE_DMA_QUEUE		0
@@ -126,6 +126,9 @@
 #ifndef DRIVER_IOCTLS
 #define DRIVER_IOCTLS
 #endif
+#ifndef DRIVER_OPEN_HELPER
+#define DRIVER_OPEN_HELPER( priv, dev )
+#endif
 #ifndef DRIVER_FOPS
 #define DRIVER_FOPS				\
 static struct file_operations	DRM(fops) = {	\
@@ -159,15 +162,8 @@
 #undef DRM_OPTIONS_FUNC
 #endif
 
-/**
- * The default number of instances (minor numbers) to initialize.
- */
-#ifndef DRIVER_NUM_CARDS
-#define DRIVER_NUM_CARDS 1
-#endif
-
-static drm_device_t	*DRM(device);
-static int		*DRM(minor);
+#define MAX_DEVICES 4
+static drm_device_t	DRM(device)[MAX_DEVICES];
 static int		DRM(numdevs) = 0;
 
 DRIVER_FOPS;
@@ -177,10 +173,13 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]       = { DRM(version),     0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]    = { DRM(getunique),   0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]     = { DRM(getmagic),    0, 0 },
-	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]     = { DRM(irq_busid),   0, 1 },
+#if __HAVE_IRQ
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]     = { DRM(irq_by_busid), 0, 1 },
+#endif
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)]       = { DRM(getmap),      0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)]    = { DRM(getclient),   0, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)]     = { DRM(getstats),    0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)]   = { DRM(setversion),  0, 1 },
 
 	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]    = { DRM(setunique),   1, 1 },
 	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]         = { DRM(noop),        1, 1 },
@@ -222,9 +221,9 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]     = { DRM(infobufs),    1, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]      = { DRM(mapbufs),     1, 0 },
 	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]     = { DRM(freebufs),    1, 0 },
-
-	/* The DRM_IOCTL_DMA ioctl should be defined by the driver.
-	 */
+	/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
+#endif
+#if __HAVE_IRQ || __HAVE_DMA
 	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]       = { DRM(control),     1, 1 },
 #endif
 
@@ -337,7 +336,7 @@
 	dev->queue_reserved = 0;
 	dev->queue_slots = 0;
 	dev->queuelist = NULL;
-	dev->irq = 0;
+	dev->irq_enabled = 0;
 	dev->context_flag = 0;
 	dev->interrupt_flag = 0;
 	dev->dma_flag = 0;
@@ -345,6 +344,7 @@
 	dev->last_switch = 0;
 	dev->last_checked = 0;
 	init_waitqueue_head( &dev->context_wait );
+	dev->if_version = 0;
 
 	dev->ctx_start = 0;
 	dev->lck_start = 0;
@@ -391,8 +391,8 @@
 	DRM_DEBUG( "\n" );
 
 	DRIVER_PRETAKEDOWN();
-#if __HAVE_DMA_IRQ
-	if ( dev->irq ) DRM(irq_uninstall)( dev );
+#if __HAVE_IRQ
+	if ( dev->irq_enabled ) DRM(irq_uninstall)( dev );
 #endif
 
 	down( &dev->struct_sem );
@@ -534,52 +534,111 @@
 	return 0;
 }
 
-/**
- * Figure out how many instances to initialize.
- *
- * \return number of cards found.
- *
- * Searches for every PCI card in \c DRIVER_CARD_LIST with matching vendor and device ids.
- */
-static int drm_count_cards(void)
+static drm_pci_id_list_t DRM(pciidlist)[] = {
+	DRIVER_PCI_IDS
+};
+
+static int DRM(probe)(struct pci_dev *pdev)
 {
-	int num = 0;
-#if defined(DRIVER_CARD_LIST)
-	int i;
-	drm_pci_list_t *l;
-	u16 device, vendor;
-	struct pci_dev *pdev = NULL;
+	drm_device_t *dev;
+#if __HAVE_CTX_BITMAP
+	int retcode;
 #endif
+	int i;
+	char *desc = NULL;
 
 	DRM_DEBUG( "\n" );
 
-#if defined(DRIVER_COUNT_CARDS)
-	num = DRIVER_COUNT_CARDS();
-#elif defined(DRIVER_CARD_LIST)
-	for (i = 0, l = DRIVER_CARD_LIST; l[i].vendor != 0; i++) {
-		pdev = NULL;
-		vendor = l[i].vendor;
-		device = l[i].device;
-		if(device == 0xffff) device = PCI_ANY_ID;
-		if(vendor == 0xffff) vendor = PCI_ANY_ID;
-		while ((pdev = pci_find_device(vendor, device, pdev))) {
-			num++;
+	for (i = 0; DRM(pciidlist)[i].vendor != 0; i++) {
+		if ((DRM(pciidlist)[i].vendor == pdev->vendor) &&
+		    (DRM(pciidlist)[i].device == pdev->device)) {
+			desc = DRM(pciidlist)[i].name;
 		}
 	}
+	if (desc == NULL)
+		return -ENODEV;
+
+	if (DRM(numdevs) >= MAX_DEVICES)
+		return -ENODEV;
+
+	dev = &(DRM(device)[DRM(numdevs)]);
+
+	memset( (void *)dev, 0, sizeof(*dev) );
+	dev->count_lock = SPIN_LOCK_UNLOCKED;
+	init_timer( &dev->timer );
+	sema_init( &dev->struct_sem, 1 );
+
+	if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
+		return -EPERM;
+	dev->device = MKDEV(DRM_MAJOR, dev->minor );
+	dev->name   = DRIVER_NAME;
+
+	dev->pdev   = pdev;
+#ifdef __alpha__
+	dev->hose   = pdev->sysdata;
+	dev->pci_domain = dev->hose->bus->number;
 #else
-	num = DRIVER_NUM_CARDS;
+	dev->pci_domain = 0;
+#endif
+	dev->pci_bus = pdev->bus->number;
+	dev->pci_slot = PCI_SLOT(pdev->devfn);
+	dev->pci_func = PCI_FUNC(pdev->devfn);
+	dev->irq = pdev->irq;
+
+	DRIVER_PREINIT();
+
+#if __REALLY_HAVE_AGP
+	dev->agp = DRM(agp_init)();
+#if __MUST_HAVE_AGP
+	if ( dev->agp == NULL ) {
+		DRM_ERROR( "Cannot initialize the agpgart module.\n" );
+		DRM(stub_unregister)(dev->minor);
+		DRM(takedown)( dev );
+		return -ENOMEM;
+	}
+#endif
+#if __REALLY_HAVE_MTRR
+	if (dev->agp)
+		dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
+					dev->agp->agp_info.aper_size*1024*1024,
+					MTRR_TYPE_WRCOMB,
+					1 );
+#endif
+#endif
+
+#if __HAVE_CTX_BITMAP
+	retcode = DRM(ctxbitmap_init)( dev );
+	if( retcode ) {
+		DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
+		DRM(stub_unregister)(dev->minor);
+		DRM(takedown)( dev );
+		return retcode;
+ 	}
 #endif
-	DRM_DEBUG("numdevs = %d\n", num);
-	return num;
+	DRM(numdevs)++; /* no errors, mark it reserved */
+	
+	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
+		DRIVER_NAME,
+		DRIVER_MAJOR,
+		DRIVER_MINOR,
+		DRIVER_PATCHLEVEL,
+		DRIVER_DATE,
+		dev->minor,
+		desc );
+
+	DRIVER_POSTINIT();
+
+	return 0;
 }
 
+
 /**
  * Module initialization. Called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported).
  *
  * \return zero on success or a negative number on failure.
  *
- * Allocates and initialize an array of drm_device structures, and attempts to
+ * Initializes an array of drm_device structures, and attempts to
  * initialize all available devices, using consecutive minors, registering the
  * stubs and initializing the AGP device.
  * 
@@ -588,88 +647,19 @@
  */
 static int __init drm_init( void )
 {
+	struct pci_dev *pdev = NULL;
 
-	drm_device_t *dev;
-	int i;
-#if __HAVE_CTX_BITMAP
-	int retcode;
-#endif
 	DRM_DEBUG( "\n" );
 
 #ifdef MODULE
 	DRM(parse_options)( drm_opts );
 #endif
 
-	DRM(numdevs) = drm_count_cards();
-	/* Force at least one instance. */
-	if (DRM(numdevs) <= 0)
-		DRM(numdevs) = 1;
-
-	DRM(device) = kmalloc(sizeof(*DRM(device)) * DRM(numdevs), GFP_KERNEL);
-	if (!DRM(device)) {
-		return -ENOMEM;
-	}
-	DRM(minor) = kmalloc(sizeof(*DRM(minor)) * DRM(numdevs), GFP_KERNEL);
-	if (!DRM(minor)) {
-		kfree(DRM(device));
-		return -ENOMEM;
-	}
-
-	DRIVER_PREINIT();
-
 	DRM(mem_init)();
 
-	for (i = 0; i < DRM(numdevs); i++) {
-		dev = &(DRM(device)[i]);
-		memset( (void *)dev, 0, sizeof(*dev) );
-		dev->count_lock = SPIN_LOCK_UNLOCKED;
-		init_timer( &dev->timer );
-		sema_init( &dev->struct_sem, 1 );
-
-		if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
-			return -EPERM;
-		dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] );
-		dev->name   = DRIVER_NAME;
-
-#if __REALLY_HAVE_AGP
-		dev->agp = DRM(agp_init)();
-#if __MUST_HAVE_AGP
-		if ( dev->agp == NULL ) {
-			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
-			DRM(stub_unregister)(DRM(minor)[i]);
-			DRM(takedown)( dev );
-			return -EINVAL;
-		}
-#endif
-#if __REALLY_HAVE_MTRR
-		if (dev->agp)
-			dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
-				       dev->agp->agp_info.aper_size*1024*1024,
-				       MTRR_TYPE_WRCOMB,
-				       1 );
-#endif
-#endif
-
-#if __HAVE_CTX_BITMAP
-		retcode = DRM(ctxbitmap_init)( dev );
-		if( retcode ) {
-			DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
-			DRM(stub_unregister)(DRM(minor)[i]);
-			DRM(takedown)( dev );
-			return retcode;
-		}
-#endif
-		DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
-		  	DRIVER_NAME,
-		  	DRIVER_MAJOR,
-		  	DRIVER_MINOR,
-		  	DRIVER_PATCHLEVEL,
-		  	DRIVER_DATE,
-		  	DRM(minor)[i] );
+	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+		DRM(probe)(pdev);
 	}
-
-	DRIVER_POSTINIT();
-
 	return 0;
 }
 
@@ -689,10 +679,10 @@
 
 	for (i = DRM(numdevs) - 1; i >= 0; i--) {
 		dev = &(DRM(device)[i]);
-		if ( DRM(stub_unregister)(DRM(minor)[i]) ) {
+		if ( DRM(stub_unregister)(dev->minor) ) {
 			DRM_ERROR( "Cannot unload module\n" );
 		} else {
-			DRM_DEBUG("minor %d unregistered\n", DRM(minor)[i]);
+			DRM_DEBUG("minor %d unregistered\n", dev->minor);
 			if (i == 0) {
 				DRM_INFO( "Module unloaded\n" );
 			}
@@ -722,8 +712,6 @@
 #endif
 	}
 	DRIVER_POSTCLEANUP();
-	kfree(DRM(minor));
-	kfree(DRM(device));
 	DRM(numdevs) = 0;
 }
 
@@ -795,7 +783,7 @@
 	int i;
 
 	for (i = 0; i < DRM(numdevs); i++) {
-		if (iminor(inode) == DRM(minor)[i]) {
+		if (iminor(inode) == DRM(device)[i].minor) {
 			dev = &(DRM(device)[i]);
 			break;
 		}
--- diff/drivers/char/drm/drm_fops.h	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/char/drm/drm_fops.h	2004-02-18 09:03:58.000000000 +0000
@@ -72,6 +72,8 @@
 	priv->authenticated = capable(CAP_SYS_ADMIN);
 	priv->lock_count    = 0;
 
+	DRIVER_OPEN_HELPER( priv, dev );
+
 	down(&dev->struct_sem);
 	if (!dev->file_last) {
 		priv->next	= NULL;
--- diff/drivers/char/drm/drm_ioctl.h	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/drm_ioctl.h	2004-02-18 09:03:58.000000000 +0000
@@ -35,69 +35,7 @@
 
 #include "drmP.h"
 
-
-/**
- * Get interrupt from bus id.
- * 
- * \param inode device inode.
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_irq_busid structure.
- * \return zero on success or a negative number on failure.
- * 
- * Finds the PCI device with the specified bus id and gets its IRQ number.
- */
-int DRM(irq_busid)(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
-{
-	drm_irq_busid_t p;
-	struct pci_dev	*dev;
-
-	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
-		return -EFAULT;
-#ifdef __alpha__
-	{
-		int domain = p.busnum >> 8;
-		p.busnum &= 0xff;
-
-		/*
-		 * Find the hose the device is on (the domain number is the
-		 * hose index) and offset the bus by the root bus of that
-		 * hose.
-		 */
-                for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
-                    dev;
-                    dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) {
-			struct pci_controller *hose = dev->sysdata;
-			
-			if (hose->index == domain) {
-				p.busnum += hose->bus->number;
-				break;
-			}
-		}
-	}
-#endif
-	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
-	if (!dev) {
-		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
-			  p.busnum, p.devnum, p.funcnum);
-		p.irq = 0;
-		goto out;
-	}			
-	if (pci_enable_device(dev) != 0) {
-		DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
-			  p.busnum, p.devnum, p.funcnum);
-		p.irq = 0;
-		goto out;
-	}		
-	p.irq = dev->irq;
- out:
-	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
-		  p.busnum, p.devnum, p.funcnum, p.irq);
-	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
-		return -EFAULT;
-	return 0;
-}
+#include <linux/pci.h>
 
 /**
  * Get the bus id.
@@ -138,8 +76,10 @@
  * \param arg user argument, pointing to a drm_unique structure.
  * \return zero on success or a negative number on failure.
  *
- * Copies the bus id from userspace into drm_device::unique, and searches for
- * the respective PCI device, updating drm_device::pdev.
+ * Copies the bus id from userspace into drm_device::unique, and verifies that
+ * it matches the device this DRM is attached to (EINVAL otherwise).  Deprecated
+ * in interface version 1.1 and will return EBUSY when setversion has requested
+ * version 1.1 or greater.
  */
 int DRM(setunique)(struct inode *inode, struct file *filp,
 		   unsigned int cmd, unsigned long arg)
@@ -147,6 +87,7 @@
 	drm_file_t	 *priv	 = filp->private_data;
 	drm_device_t	 *dev	 = priv->dev;
 	drm_unique_t	 u;
+	int		 domain, bus, slot, func, ret;
 
 	if (dev->unique_len || dev->unique) return -EBUSY;
 
@@ -164,55 +105,42 @@
 
 	dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2,
 				  DRM_MEM_DRIVER);
-	if(!dev->devname) {
-		DRM(free)(dev->devname, sizeof(*dev->devname), DRM_MEM_DRIVER);
+	if (!dev->devname)
 		return -ENOMEM;
-	}
+
 	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
 
-	do {
-		struct pci_dev *pci_dev;
-                int domain, b, d, f;
-                char *p;
- 
-                for(p = dev->unique; p && *p && *p != ':'; p++);
-                if (!p || !*p) break;
-                b = (int)simple_strtoul(p+1, &p, 10);
-                if (*p != ':') break;
-                d = (int)simple_strtoul(p+1, &p, 10);
-                if (*p != ':') break;
-                f = (int)simple_strtoul(p+1, &p, 10);
-                if (*p) break;
- 
-		domain = b >> 8;
-		b &= 0xff;
-
-#ifdef __alpha__
-		/*
-		 * Find the hose the device is on (the domain number is the
-		 * hose index) and offset the bus by the root bus of that
-		 * hose.
-		 */
-                for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
-                    pci_dev;
-                    pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) {
-			struct pci_controller *hose = pci_dev->sysdata;
-			
-			if (hose->index == domain) {
-				b += hose->bus->number;
-				break;
-			}
-		}
-#endif
+	/* Return error if the busid submitted doesn't match the device's actual
+	 * busid.
+	 */
+	ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+	if (ret != 3)
+		return DRM_ERR(EINVAL);
+	domain = bus >> 8;
+	bus &= 0xff;
+	
+	if ((domain != dev->pci_domain) ||
+	    (bus != dev->pci_bus) ||
+	    (slot != dev->pci_slot) ||
+	    (func != dev->pci_func))
+		return -EINVAL;
 
-                pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
-                if (pci_dev) {
-			dev->pdev = pci_dev;
-#ifdef __alpha__
-			dev->hose = pci_dev->sysdata;
-#endif
-		}
-        } while(0);
+	return 0;
+}
+
+static int
+DRM(set_busid)(drm_device_t *dev)
+{
+	if (dev->unique != NULL)
+		return EBUSY;
+
+	dev->unique_len = 20;
+	dev->unique = DRM(alloc)(dev->unique_len + 1, DRM_MEM_DRIVER);
+	if (dev->unique == NULL)
+		return ENOMEM;
+
+	snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+		dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
 
 	return 0;
 }
@@ -363,3 +291,48 @@
 		return -EFAULT;
 	return 0;
 }
+
+#define DRM_IF_MAJOR	1
+#define DRM_IF_MINOR	2
+
+int DRM(setversion)(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_set_version_t sv;
+	drm_set_version_t retv;
+	int if_version;
+
+	DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
+
+	retv.drm_di_major = DRM_IF_MAJOR;
+	retv.drm_di_minor = DRM_IF_MINOR;
+	retv.drm_dd_major = DRIVER_MAJOR;
+	retv.drm_dd_minor = DRIVER_MINOR;
+
+	DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
+
+	if (sv.drm_di_major != -1) {
+		if (sv.drm_di_major != DRM_IF_MAJOR ||
+		    sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
+			return EINVAL;
+		if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+		dev->if_version = DRM_MAX(if_version, dev->if_version);
+		if (sv.drm_di_minor >= 1) {
+			/*
+			 * Version 1.1 includes tying of DRM to specific device
+			 */
+			DRM(set_busid)(dev);
+		}
+	}
+
+	if (sv.drm_dd_major != -1) {
+		if (sv.drm_dd_major != DRIVER_MAJOR ||
+		    sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
+			return EINVAL;
+#ifdef DRIVER_SETVERSION
+		DRIVER_SETVERSION(dev, &sv);
+#endif
+	}
+	return 0;
+}
+
--- diff/drivers/char/drm/drm_os_linux.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/drm_os_linux.h	2004-02-18 09:03:58.000000000 +0000
@@ -62,8 +62,12 @@
 	verify_area( VERIFY_READ, uaddr, size )
 #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) 	\
 	__copy_from_user(arg1, arg2, arg3)
+#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3)	\
+	__copy_to_user(arg1, arg2, arg3)
 #define DRM_GET_USER_UNCHECKED(val, uaddr)		\
 	__get_user(val, uaddr)
+#define DRM_PUT_USER_UNCHECKED(uaddr, val)		\
+	__put_user(val, uaddr)
 
 
 /** 'malloc' without the overhead of DRM(alloc)() */
@@ -71,6 +75,8 @@
 /** 'free' without the overhead of DRM(free)() */
 #define DRM_FREE(x,size) kfree(x)
 
+#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
+
 /** 
  * Get the pointer to the SAREA.
  *
--- diff/drivers/char/drm/gamma.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/gamma.h	2004-02-18 09:03:58.000000000 +0000
@@ -53,6 +53,10 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_GAMMA_INIT)] = { gamma_dma_init,  1, 1 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_GAMMA_COPY)] = { gamma_dma_copy,  1, 1 }
 
+#define DRIVER_PCI_IDS							\
+	{0x3d3d, 0x0008, 0, "3DLabs GLINT Gamma G1"},			\
+	{0, 0, 0, NULL}
+
 #define IOCTL_TABLE_NAME	DRM(ioctls)
 #define IOCTL_FUNC_NAME 	DRM(ioctl)
 
@@ -104,8 +108,8 @@
 	return 0;							\
 } while (0)
 
-#define __HAVE_DMA_IRQ			1
-#define __HAVE_DMA_IRQ_BH		1
+#define __HAVE_IRQ			1
+#define __HAVE_IRQ_BH			1
 
 #define DRIVER_AGP_BUFFERS_MAP( dev )					\
 	((drm_gamma_private_t *)((dev)->dev_private))->buffers
--- diff/drivers/char/drm/gamma_dma.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/gamma_dma.c	2004-02-18 09:03:58.000000000 +0000
@@ -116,7 +116,7 @@
 	return (!GAMMA_READ(GAMMA_DMACOUNT));
 }
 
-irqreturn_t gamma_dma_service( DRM_IRQ_ARGS )
+irqreturn_t gamma_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t	 *dev = (drm_device_t *)arg;
 	drm_device_dma_t *dma = dev->dma;
@@ -262,7 +262,7 @@
 	gamma_dma_schedule((drm_device_t *)dev, 0);
 }
 
-void gamma_dma_immediate_bh(void *dev)
+void gamma_irq_immediate_bh(void *dev)
 {
 	gamma_dma_schedule(dev, 0);
 }
@@ -656,12 +656,12 @@
 {
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/gamma_drv.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/gamma_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -48,6 +48,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "gamma_lists.h"        /* NOTE */
 #include "drm_lock.h"
 #include "gamma_lock.h"		/* NOTE */
--- diff/drivers/char/drm/i810.h	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/char/drm/i810.h	2004-02-18 09:03:58.000000000 +0000
@@ -77,7 +77,14 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] =    { i810_flip_bufs,  1, 0 }
- 
+
+#define DRIVER_PCI_IDS							\
+	{0x8086, 0x7121, 0, "Intel i810 GMCH"},				\
+	{0x8086, 0x7123, 0, "Intel i810-DC100 GMCH"},			\
+	{0x8086, 0x7125, 0, "Intel i810E GMCH"},			\
+	{0x8086, 0x1132, 0, "Intel i815 GMCH"},				\
+	{0, 0, 0, NULL}
+
 
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
@@ -112,7 +119,7 @@
  * a noop stub is generated for compatibility.
  */
 /* XXX: Add vblank support? */
-#define __HAVE_DMA_IRQ		0
+#define __HAVE_IRQ		0
 
 /* Buffer customization:
  */
--- diff/drivers/char/drm/i810_dma.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/i810_dma.c	2004-02-18 09:03:58.000000000 +0000
@@ -53,41 +53,41 @@
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
-   	drm_device_dma_t *dma = dev->dma;
-      	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	u32 *temp = dev_priv->hw_status_page;
-   	int i;
+	int i;
 
-   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
-   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
-   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
-      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
 	DRM_DEBUG(  "hw_status: Last Render: %x\n", temp[4]);
-   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
-   	for(i = 6; i < dma->buf_count + 6; i++) {
-	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+	for(i = 6; i < dma->buf_count + 6; i++) {
+		DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
 	}
 }
 
 static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
-   	drm_device_dma_t *dma = dev->dma;
+	drm_device_dma_t *dma = dev->dma;
 	int		 i;
-   	int 		 used;
+	int		 used;
 
 	/* Linear search might not be the best solution */
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 		/* In use is already a pointer */
-	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
+		used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
 			       I810_BUF_CLIENT);
 		if (used == I810_BUF_FREE) {
 			return buf;
 		}
 	}
-   	return NULL;
+	return NULL;
 }
 
 /* This should only be called if the buffer is not sent to the hardware
@@ -96,17 +96,17 @@
 
 static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
 {
-   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-   	int used;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	int used;
 
-   	/* In use is already a pointer */
-   	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
+	/* In use is already a pointer */
+	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
 	if (used != I810_BUF_CLIENT) {
-	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
-	   	return -EINVAL;
+		DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+		return -EINVAL;
 	}
 
-   	return 0;
+	return 0;
 }
 
 static struct file_operations i810_buffer_fops = {
@@ -135,7 +135,7 @@
 	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
 	vma->vm_file = filp;
 
-   	buf_priv->currently_mapped = I810_BUF_MAPPED;
+	buf_priv->currently_mapped = I810_BUF_MAPPED;
 	unlock_kernel();
 
 	if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
@@ -150,8 +150,8 @@
 	drm_file_t	  *priv	  = filp->private_data;
 	drm_device_t	  *dev	  = priv->dev;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	struct file_operations *old_fops;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	struct file_operations *old_fops;
 	int retcode = 0;
 
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED) 
@@ -192,8 +192,8 @@
 			    (size_t) buf->total);
 	up_write(&current->mm->mmap_sem);
 
-   	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
-   	buf_priv->virtual = 0;
+	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+	buf_priv->virtual = 0;
 
 	return retcode;
 }
@@ -208,22 +208,22 @@
 	buf = i810_freelist_get(dev);
 	if (!buf) {
 		retcode = -ENOMEM;
-	   	DRM_DEBUG("retcode=%d\n", retcode);
+		DRM_DEBUG("retcode=%d\n", retcode);
 		return retcode;
 	}
 
 	retcode = i810_map_buffer(buf, filp);
 	if (retcode) {
 		i810_freelist_put(dev, buf);
-	   	DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
+		DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
 		return retcode;
 	}
 	buf->filp = filp;
 	buf_priv = buf->dev_private;
 	d->granted = 1;
-   	d->request_idx = buf->idx;
-   	d->request_size = buf->total;
-   	d->virtual = buf_priv->virtual;
+	d->request_idx = buf->idx;
+	d->request_size = buf->total;
+	d->virtual = buf_priv->virtual;
 
 	return retcode;
 }
@@ -232,33 +232,33 @@
 {
 	drm_device_dma_t *dma = dev->dma;
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if (dev->irq) DRM(irq_uninstall)(dev);
+	if (dev->irq_enabled) DRM(irq_uninstall)(dev);
 #endif
 
 	if (dev->dev_private) {
 		int i;
-	   	drm_i810_private_t *dev_priv =
-	     		(drm_i810_private_t *) dev->dev_private;
+		drm_i810_private_t *dev_priv =
+			(drm_i810_private_t *) dev->dev_private;
 
 		if (dev_priv->ring.virtual_start) {
-		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+			DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
 					 dev_priv->ring.Size, dev);
 		}
-	   	if (dev_priv->hw_status_page) {
-		   	pci_free_consistent(dev->pdev, PAGE_SIZE,
+		if (dev_priv->hw_status_page) {
+			pci_free_consistent(dev->pdev, PAGE_SIZE,
 					    dev_priv->hw_status_page,
 					    dev_priv->dma_status_page);
-		   	/* Need to rewrite hardware status page */
-		   	I810_WRITE(0x02080, 0x1ffff000);
+			/* Need to rewrite hardware status page */
+			I810_WRITE(0x02080, 0x1ffff000);
 		}
-	   	DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),
+		DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),
 			 DRM_MEM_DRIVER);
-	   	dev->dev_private = NULL;
+		dev->dev_private = NULL;
 
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[ i ];
@@ -267,73 +267,73 @@
 				DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev);
 		}
 	}
-   	return 0;
+	return 0;
 }
 
 static int i810_wait_ring(drm_device_t *dev, int n)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
-   	int iters = 0;
-   	unsigned long end;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+	int iters = 0;
+	unsigned long end;
 	unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 
 	end = jiffies + (HZ*3);
-   	while (ring->space < n) {
-	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-	   	ring->space = ring->head - (ring->tail+8);
+	while (ring->space < n) {
+		ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+		ring->space = ring->head - (ring->tail+8);
 		if (ring->space < 0) ring->space += ring->Size;
-	   
+
 		if (ring->head != last_head) {
 			end = jiffies + (HZ*3);
 			last_head = ring->head;
 		}
 	  
-	   	iters++;
+		iters++;
 		if (time_before(end, jiffies)) {
-		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
-		   	DRM_ERROR("lockup\n");
-		   	goto out_wait_ring;
+			DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+			DRM_ERROR("lockup\n");
+			goto out_wait_ring;
 		}
 		udelay(1);
 	}
 
 out_wait_ring:
-   	return iters;
+	return iters;
 }
 
 static void i810_kernel_lost_context(drm_device_t *dev)
 {
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
 
-   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-     	ring->tail = I810_READ(LP_RING + RING_TAIL);
-     	ring->space = ring->head - (ring->tail+8);
-     	if (ring->space < 0) ring->space += ring->Size;
+	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	ring->tail = I810_READ(LP_RING + RING_TAIL);
+	ring->space = ring->head - (ring->tail+8);
+	if (ring->space < 0) ring->space += ring->Size;
 }
 
 static int i810_freelist_init(drm_device_t *dev, drm_i810_private_t *dev_priv)
 {
-      	drm_device_dma_t *dma = dev->dma;
-   	int my_idx = 24;
-   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
-   	int i;
+	drm_device_dma_t *dma = dev->dma;
+	int my_idx = 24;
+	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+	int i;
 
 	if (dma->buf_count > 1019) {
-	   	/* Not enough space in the status page for the freelist */
-	   	return -EINVAL;
+		/* Not enough space in the status page for the freelist */
+		return -EINVAL;
 	}
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
-	   	buf_priv->in_use = hw_status++;
-	   	buf_priv->my_use_idx = my_idx;
-	   	my_idx += 4;
+		buf_priv->in_use = hw_status++;
+		buf_priv->my_use_idx = my_idx;
+		my_idx += 4;
 
-	   	*buf_priv->in_use = I810_BUF_FREE;
+		*buf_priv->in_use = I810_BUF_FREE;
 
 		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
 							buf->total, dev);
@@ -347,7 +347,7 @@
 {
 	struct list_head *list;
 
-   	memset(dev_priv, 0, sizeof(drm_i810_private_t));
+	memset(dev_priv, 0, sizeof(drm_i810_private_t));
 
 	list_for_each(list, &dev->maplist->head) {
 		drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
@@ -355,51 +355,51 @@
 		    r_list->map->type == _DRM_SHM &&
 		    r_list->map->flags & _DRM_CONTAINS_LOCK ) {
 			dev_priv->sarea_map = r_list->map;
- 			break;
- 		}
- 	}
+			break;
+		}
+	}
 	if (!dev_priv->sarea_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find sarea!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find sarea!\n");
+		return -EINVAL;
 	}
 	DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
 	if (!dev_priv->mmio_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find mmio map!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find mmio map!\n");
+		return -EINVAL;
 	}
 	DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
 	if (!dev_priv->buffer_map) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not find dma buffer map!\n");
-	   	return -EINVAL;
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not find dma buffer map!\n");
+		return -EINVAL;
 	}
 
 	dev_priv->sarea_priv = (drm_i810_sarea_t *)
 		((u8 *)dev_priv->sarea_map->handle +
 		 init->sarea_priv_offset);
 
-   	dev_priv->ring.Start = init->ring_start;
-   	dev_priv->ring.End = init->ring_end;
-   	dev_priv->ring.Size = init->ring_size;
+	dev_priv->ring.Start = init->ring_start;
+	dev_priv->ring.End = init->ring_end;
+	dev_priv->ring.Size = init->ring_size;
 
-   	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
+	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
 						    init->ring_start,
 						    init->ring_size, dev);
 
-   	if (dev_priv->ring.virtual_start == NULL) {
+	if (dev_priv->ring.virtual_start == NULL) {
 		dev->dev_private = (void *) dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("can not ioremap virtual address for"
+		i810_dma_cleanup(dev);
+		DRM_ERROR("can not ioremap virtual address for"
 			  " ring buffer\n");
-	   	return -ENOMEM;
+		return -ENOMEM;
 	}
 
-   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
 	dev_priv->w = init->w;
 	dev_priv->h = init->h;
@@ -415,33 +415,33 @@
 	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
 	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
 
-   	/* Program Hardware Status Page */
-   	dev_priv->hw_status_page =
+	/* Program Hardware Status Page */
+	dev_priv->hw_status_page =
 		pci_alloc_consistent(dev->pdev, PAGE_SIZE,
 						&dev_priv->dma_status_page);
-   	if (!dev_priv->hw_status_page) {
+	if (!dev_priv->hw_status_page) {
 		dev->dev_private = (void *)dev_priv;
 		i810_dma_cleanup(dev);
 		DRM_ERROR("Can not allocate hardware status page\n");
 		return -ENOMEM;
 	}
-   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-   	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
 
 	I810_WRITE(0x02080, dev_priv->dma_status_page);
-   	DRM_DEBUG("Enabled hardware status page\n");
+	DRM_DEBUG("Enabled hardware status page\n");
 
-   	/* Now we need to init our freelist */
+	/* Now we need to init our freelist */
 	if (i810_freelist_init(dev, dev_priv) != 0) {
 		dev->dev_private = (void *)dev_priv;
-	   	i810_dma_cleanup(dev);
-	   	DRM_ERROR("Not enough space in the status page for"
+		i810_dma_cleanup(dev);
+		DRM_ERROR("Not enough space in the status page for"
 			  " the freelist\n");
-	   	return -ENOMEM;
+		return -ENOMEM;
 	}
 	dev->dev_private = (void *)dev_priv;
 
-   	return 0;
+	return 0;
 }
 
 /* i810 DRM version 1.1 used a smaller init structure with different
@@ -476,12 +476,12 @@
 
 		/* This is a v1.1 client, fix the params */
 		DRM_INFO("Using PRE v1.2 init.\n");
-	 	init->pitch_bits = init->h;
-	 	init->pitch = init->w;
-	 	init->h = init->overlay_physical;
-	 	init->w = init->overlay_offset;
-	 	init->overlay_physical = 0;
-	 	init->overlay_offset = 0;
+		init->pitch_bits = init->h;
+		init->pitch = init->w;
+		init->h = init->overlay_physical;
+		init->w = init->overlay_offset;
+		init->overlay_physical = 0;
+		init->overlay_offset = 0;
 	}
 
 	return 0;
@@ -490,55 +490,55 @@
 int i810_dma_init(struct inode *inode, struct file *filp,
 		  unsigned int cmd, unsigned long arg)
 {
-   	drm_file_t *priv = filp->private_data;
-   	drm_device_t *dev = priv->dev;
-   	drm_i810_private_t *dev_priv;
-   	drm_i810_init_t init;
-   	int retcode = 0;
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_private_t *dev_priv;
+	drm_i810_init_t init;
+	int retcode = 0;
 
 	/* Get only the init func */
 	if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t))) 
 		return -EFAULT;
 
-   	switch(init.func) {
-	 	case I810_INIT_DMA:
-	 	       	/* This case is for backward compatibility. It
+	switch(init.func) {
+		case I810_INIT_DMA:
+			/* This case is for backward compatibility. It
 			 * handles XFree 4.1.0 and 4.2.0, and has to
 			 * do some parameter checking as described below.
 			 * It will someday go away.
 			 */
 			retcode = i810_dma_init_compat(&init, arg);
-			if (retcode)
+			if (retcode) 
 				return retcode;
 
-	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
+			dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
 					     DRM_MEM_DRIVER);
-	   		if (dev_priv == NULL)
-				return -ENOMEM;
-	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+			if (dev_priv == NULL)
+			       return -ENOMEM;
+			retcode = i810_dma_initialize(dev, dev_priv, &init);
 			break;
 
 		default:
-	 	case I810_INIT_DMA_1_4:
+		case I810_INIT_DMA_1_4:
 			DRM_INFO("Using v1.4 init.\n");
-  			if (copy_from_user(&init, (drm_i810_init_t *)arg,
+			if (copy_from_user(&init, (drm_i810_init_t *)arg,
 					  sizeof(drm_i810_init_t))) {
 				return -EFAULT;
 			}
-	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
+			dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),
 					     DRM_MEM_DRIVER);
 			if (dev_priv == NULL) 
 				return -ENOMEM;
-	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+			retcode = i810_dma_initialize(dev, dev_priv, &init);
 			break;
 
-	 	case I810_CLEANUP_DMA:
-		        DRM_INFO("DMA Cleanup\n");
-	   		retcode = i810_dma_cleanup(dev);
-              	   	break;
+		case I810_CLEANUP_DMA:
+			DRM_INFO("DMA Cleanup\n");
+			retcode = i810_dma_cleanup(dev);
+			break;
 	}
 
-   	return retcode;
+	return retcode;
 }
 
 
@@ -552,7 +552,7 @@
 static void i810EmitContextVerified( drm_device_t *dev,
 				     volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
@@ -586,7 +586,7 @@
 static void i810EmitTexVerified( drm_device_t *dev,
 				 volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
@@ -622,7 +622,7 @@
 static void i810EmitDestVerified( drm_device_t *dev,
 				  volatile unsigned int *code )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	unsigned int tmp;
 	RING_LOCALS;
 
@@ -658,8 +658,8 @@
 
 static void i810EmitState( drm_device_t *dev )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	unsigned int dirty = sarea_priv->dirty;
 	
 	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
@@ -693,8 +693,8 @@
 				     unsigned int clear_color,
 				     unsigned int clear_zval )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	int nbox = sarea_priv->nbox;
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
@@ -703,17 +703,17 @@
 	RING_LOCALS;
 	
 	if ( dev_priv->current_page == 1 ) {
-	        unsigned int tmp = flags;
-	       
+		unsigned int tmp = flags;
+
 		flags &= ~(I810_FRONT | I810_BACK);
 		if (tmp & I810_FRONT) flags |= I810_BACK;
 		if (tmp & I810_BACK) flags |= I810_FRONT;
 	}
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-      	if (nbox > I810_NR_SAREA_CLIPRECTS)
-     		nbox = I810_NR_SAREA_CLIPRECTS;
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
+		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	for (i = 0 ; i < nbox ; i++, pbox++) {
 		unsigned int x = pbox->x1;
@@ -728,7 +728,7 @@
 		    pbox->y2 > dev_priv->h)
 			continue;
 
-	   	if ( flags & I810_FRONT ) {
+		if ( flags & I810_FRONT ) {
 			BEGIN_LP_RING( 6 );
 			OUT_RING( BR00_BITBLT_CLIENT |
 				  BR00_OP_COLOR_BLT | 0x3 );
@@ -768,8 +768,8 @@
 
 static void i810_dma_dispatch_swap( drm_device_t *dev )
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
-      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	int nbox = sarea_priv->nbox;
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
@@ -779,10 +779,10 @@
 
 	DRM_DEBUG("swapbuffers\n");
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-      	if (nbox > I810_NR_SAREA_CLIPRECTS)
-     		nbox = I810_NR_SAREA_CLIPRECTS;
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
+		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	for (i = 0 ; i < nbox; i++, pbox++)
 	{
@@ -820,19 +820,19 @@
 				     int discard,
 				     int used)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-   	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
-   	drm_clip_rect_t *box = sarea_priv->boxes;
-   	int nbox = sarea_priv->nbox;
+	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_clip_rect_t *box = sarea_priv->boxes;
+	int nbox = sarea_priv->nbox;
 	unsigned long address = (unsigned long)buf->bus_address;
 	unsigned long start = address - dev->agp->base;
 	int i = 0;
-   	RING_LOCALS;
+	RING_LOCALS;
 
-   	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	if (nbox > I810_NR_SAREA_CLIPRECTS)
+	if (nbox > I810_NR_SAREA_CLIPRECTS)
 		nbox = I810_NR_SAREA_CLIPRECTS;
 
 	if (used > 4*1024)
@@ -898,7 +898,7 @@
 
 static void i810_dma_dispatch_flip( drm_device_t *dev )
 {
-        drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	int pitch = dev_priv->pitch;
 	RING_LOCALS;
 
@@ -907,10 +907,10 @@
 		dev_priv->current_page,
 		dev_priv->sarea_priv->pf_current_page);
 	
-        i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
 	BEGIN_LP_RING( 2 );
-   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
 	OUT_RING( 0 );
 	ADVANCE_LP_RING();
 
@@ -945,44 +945,44 @@
 
 void i810_dma_quiescent(drm_device_t *dev)
 {
-      	drm_i810_private_t *dev_priv = dev->dev_private;
-   	RING_LOCALS;
+	drm_i810_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
 
-/*  	printk("%s\n", __FUNCTION__); */
+/*	printk("%s\n", __FUNCTION__); */
 
-  	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	BEGIN_LP_RING(4);
-   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
-   	OUT_RING( CMD_REPORT_HEAD );
-      	OUT_RING( 0 );
-      	OUT_RING( 0 );
-   	ADVANCE_LP_RING();
+	BEGIN_LP_RING(4);
+	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
 
 	i810_wait_ring( dev, dev_priv->ring.Size - 8 );
 }
 
 static int i810_flush_queue(drm_device_t *dev)
 {
-   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_private_t *dev_priv = dev->dev_private;
 	drm_device_dma_t *dma = dev->dma;
-   	int i, ret = 0;
-   	RING_LOCALS;
+	int i, ret = 0;
+	RING_LOCALS;
 	
-/*  	printk("%s\n", __FUNCTION__); */
+/*	printk("%s\n", __FUNCTION__); */
 
-   	i810_kernel_lost_context(dev);
+	i810_kernel_lost_context(dev);
 
-   	BEGIN_LP_RING(2);
-      	OUT_RING( CMD_REPORT_HEAD );
-      	OUT_RING( 0 );
-      	ADVANCE_LP_RING();
+	BEGIN_LP_RING(2);
+	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
 
 	i810_wait_ring( dev, dev_priv->ring.Size - 8 );
 
-   	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
 		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
 				   I810_BUF_FREE);
@@ -993,7 +993,7 @@
 			DRM_DEBUG("still on client\n");
 	}
 
-   	return ret;
+	return ret;
 }
 
 /* Must be called with the lock held */
@@ -1005,14 +1005,14 @@
 	int		 i;
 
 	if (!dma) return;
-      	if (!dev->dev_private) return;
+	if (!dev->dev_private) return;
 	if (!dma->buflist) return;
 
-        i810_flush_queue(dev);
+	i810_flush_queue(dev);
 
 	for (i = 0; i < dma->buf_count; i++) {
-	   	drm_buf_t *buf = dma->buflist[ i ];
-	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+		drm_buf_t *buf = dma->buflist[ i ];
+		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
 
 		if (buf->filp == filp && buf_priv) {
 			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
@@ -1021,7 +1021,7 @@
 			if (used == I810_BUF_CLIENT)
 				DRM_DEBUG("reclaimed from client\n");
 			if (buf_priv->currently_mapped == I810_BUF_MAPPED)
-		     		buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+				buf_priv->currently_mapped = I810_BUF_UNMAPPED;
 		}
 	}
 }
@@ -1029,16 +1029,16 @@
 int i810_flush_ioctl(struct inode *inode, struct file *filp,
 		     unsigned int cmd, unsigned long arg)
 {
-   	drm_file_t	  *priv	  = filp->private_data;
-   	drm_device_t	  *dev	  = priv->dev;
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
 		DRM_ERROR("i810_flush_ioctl called without lock held\n");
 		return -EINVAL;
 	}
 
-   	i810_flush_queue(dev);
-   	return 0;
+	i810_flush_queue(dev);
+	return 0;
 }
 
 
@@ -1048,10 +1048,10 @@
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_device_dma_t *dma = dev->dma;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-      	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 	drm_i810_vertex_t vertex;
 
 	if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex)))
@@ -1072,10 +1072,10 @@
 				  dma->buflist[ vertex.idx ],
 				  vertex.discard, vertex.used );
 
-   	atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+	atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
 	atomic_inc(&dev->counts[_DRM_STAT_DMA]);
 	sarea_priv->last_enqueue = dev_priv->counter-1;
-   	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 
 	return 0;
 }
@@ -1089,7 +1089,7 @@
 	drm_device_t *dev = priv->dev;
 	drm_i810_clear_t clear;
 
-   	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
+	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
 		return -EFAULT;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1097,15 +1097,15 @@
 		return -EINVAL;
 	}
 
- 	/* GH: Someone's doing nasty things... */
- 	if (!dev->dev_private) {
- 		return -EINVAL;
- 	}
+	/* GH: Someone's doing nasty things... */
+	if (!dev->dev_private) {
+		return -EINVAL;
+	}
 
 	i810_dma_dispatch_clear( dev, clear.flags,
 				 clear.clear_color,
 				 clear.clear_depth );
-   	return 0;
+	return 0;
 }
 
 int i810_swap_bufs(struct inode *inode, struct file *filp,
@@ -1122,20 +1122,20 @@
 	}
 
 	i810_dma_dispatch_swap( dev );
-   	return 0;
+	return 0;
 }
 
 int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
-   	drm_file_t	  *priv	    = filp->private_data;
+	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-      	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 
-      	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 	return 0;
 }
 
@@ -1146,12 +1146,12 @@
 	drm_device_t	  *dev	    = priv->dev;
 	int		  retcode   = 0;
 	drm_i810_dma_t	  d;
-   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-   	u32 *hw_status = dev_priv->hw_status_page;
-   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
-     					dev_priv->sarea_priv;
+	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	u32 *hw_status = dev_priv->hw_status_page;
+	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+					dev_priv->sarea_priv;
 
-   	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
+	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
 		return -EFAULT;
 
 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1168,7 +1168,7 @@
 
 	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
 		return -EFAULT;
-   	sarea_priv->last_dispatch = (int) hw_status[5];
+	sarea_priv->last_dispatch = (int) hw_status[5];
 
 	return retcode;
 }
@@ -1384,5 +1384,5 @@
 		i810_do_init_pageflip( dev );
 
 	i810_dma_dispatch_flip( dev );
-   	return 0;
+	return 0;
 }
--- diff/drivers/char/drm/i830.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/i830.h	2004-02-18 09:03:58.000000000 +0000
@@ -77,6 +77,13 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam,  1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam,  1, 0 } 
 
+#define DRIVER_PCI_IDS							\
+	{0x8086, 0x3577, 0, "Intel i830M GMCH"},			\
+	{0x8086, 0x2562, 0, "Intel i845G GMCH"},			\
+	{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"},		\
+ 	{0x8086, 0x2572, 0, "Intel i865G GMCH"}, 		\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS         4
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
 #define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
@@ -115,10 +122,10 @@
 #define USE_IRQS 0
 
 #if USE_IRQS
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_SHARED_IRQ	1
 #else
-#define __HAVE_DMA_IRQ          0
+#define __HAVE_IRQ		0
 #endif
 
 
--- diff/drivers/char/drm/i830_dma.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/i830_dma.c	2004-02-18 09:03:58.000000000 +0000
@@ -231,12 +231,12 @@
 {
 	drm_device_dma_t *dma = dev->dma;
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if (dev->irq) DRM(irq_uninstall)(dev);
+	if (dev->irq_enabled) DRM(irq_uninstall)(dev);
 #endif
 
 	if (dev->dev_private) {
@@ -1539,7 +1539,7 @@
 
 	switch( param.param ) {
 	case I830_PARAM_IRQ_ACTIVE:
-		value = dev->irq ? 1 : 0;
+		value = dev->irq_enabled;
 		break;
 	default:
 		return -EINVAL;
--- diff/drivers/char/drm/i830_drv.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/i830_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -50,6 +50,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/i830_irq.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/i830_irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -35,7 +35,7 @@
 #include <linux/delay.h>
 
 
-irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS )
+irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS )
 {
 	drm_device_t	 *dev = (drm_device_t *)arg;
       	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
--- diff/drivers/char/drm/mga.h	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/mga.h	2004-02-18 09:03:58.000000000 +0000
@@ -64,6 +64,12 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)]    = { mga_dma_blit,    1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam,    1, 0 },
 
+#define DRIVER_PCI_IDS							\
+	{0x102b, 0x0521, 0, "Matrox G200 (AGP)"},			\
+	{0x102b, 0x0525, 0, "Matrox G400/G450 (AGP)"},			\
+	{0x102b, 0x2527, 0, "Matrox G550 (AGP)"},			\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS         3
 #define __HAVE_COUNTER6         _DRM_STAT_IRQ
 #define __HAVE_COUNTER7         _DRM_STAT_PRIMARY
@@ -78,7 +84,7 @@
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/mga_dma.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/mga_dma.c	2004-02-18 09:03:58.000000000 +0000
@@ -500,14 +500,6 @@
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR( "failed to find framebuffer!\n" );
-		/* Assign dev_private so we can do cleanup. */
-		dev->dev_private = (void *)dev_priv;
-		mga_do_cleanup_dma( dev );
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR( "failed to find mmio region!\n" );
@@ -639,12 +631,12 @@
 {
 	DRM_DEBUG( "\n" );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/mga_drv.c	2002-10-16 04:27:56.000000000 +0100
+++ source/drivers/char/drm/mga_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -45,6 +45,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/mga_drv.h	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/char/drm/mga_drv.h	2004-02-18 09:03:58.000000000 +0000
@@ -91,7 +91,6 @@
 	unsigned int texture_size;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *status;
 	drm_local_map_t *warp;
--- diff/drivers/char/drm/mga_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/mga_irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -36,7 +36,7 @@
 #include "mga_drm.h"
 #include "mga_drv.h"
 
-irqreturn_t mga_dma_service( DRM_IRQ_ARGS )
+irqreturn_t mga_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_mga_private_t *dev_priv = 
--- diff/drivers/char/drm/r128.h	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/char/drm/r128.h	2004-02-18 09:03:58.000000000 +0000
@@ -79,6 +79,46 @@
    [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)]   = { r128_cce_indirect, 1, 1 }, \
    [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)]   = { r128_getparam, 1, 0 },
 
+#define DRIVER_PCI_IDS							\
+	{0x1002, 0x4c45, 0, "ATI Rage 128 Mobility LE (PCI)"},		\
+	{0x1002, 0x4c46, 0, "ATI Rage 128 Mobility LF (AGP)"},		\
+	{0x1002, 0x4d46, 0, "ATI Rage 128 Mobility MF (AGP)"},		\
+	{0x1002, 0x4d4c, 0, "ATI Rage 128 Mobility ML (AGP)"},		\
+	{0x1002, 0x5041, 0, "ATI Rage 128 Pro PA (PCI)"},		\
+	{0x1002, 0x5042, 0, "ATI Rage 128 Pro PB (AGP)"},		\
+	{0x1002, 0x5043, 0, "ATI Rage 128 Pro PC (AGP)"},		\
+	{0x1002, 0x5044, 0, "ATI Rage 128 Pro PD (PCI)"},		\
+	{0x1002, 0x5045, 0, "ATI Rage 128 Pro PE (AGP)"},		\
+	{0x1002, 0x5046, 0, "ATI Rage 128 Pro PF (AGP)"},		\
+	{0x1002, 0x5047, 0, "ATI Rage 128 Pro PG (PCI)"},		\
+	{0x1002, 0x5048, 0, "ATI Rage 128 Pro PH (AGP)"},		\
+	{0x1002, 0x5049, 0, "ATI Rage 128 Pro PI (AGP)"},		\
+	{0x1002, 0x504A, 0, "ATI Rage 128 Pro PJ (PCI)"},		\
+	{0x1002, 0x504B, 0, "ATI Rage 128 Pro PK (AGP)"},		\
+	{0x1002, 0x504C, 0, "ATI Rage 128 Pro PL (AGP)"},		\
+	{0x1002, 0x504D, 0, "ATI Rage 128 Pro PM (PCI)"},		\
+	{0x1002, 0x504E, 0, "ATI Rage 128 Pro PN (AGP)"},		\
+	{0x1002, 0x504F, 0, "ATI Rage 128 Pro PO (AGP)"},		\
+	{0x1002, 0x5050, 0, "ATI Rage 128 Pro PP (PCI)"},		\
+	{0x1002, 0x5051, 0, "ATI Rage 128 Pro PQ (AGP)"},		\
+	{0x1002, 0x5052, 0, "ATI Rage 128 Pro PR (PCI)"},		\
+	{0x1002, 0x5053, 0, "ATI Rage 128 Pro PS (PCI)"},		\
+	{0x1002, 0x5054, 0, "ATI Rage 128 Pro PT (AGP)"},		\
+	{0x1002, 0x5055, 0, "ATI Rage 128 Pro PU (AGP)"},		\
+	{0x1002, 0x5056, 0, "ATI Rage 128 Pro PV (PCI)"},		\
+	{0x1002, 0x5057, 0, "ATI Rage 128 Pro PW (AGP)"},		\
+	{0x1002, 0x5058, 0, "ATI Rage 128 Pro PX (AGP)"},		\
+	{0x1002, 0x5245, 0, "ATI Rage 128 RE (PCI)"},			\
+	{0x1002, 0x5246, 0, "ATI Rage 128 RF (AGP)"},			\
+	{0x1002, 0x5247, 0, "ATI Rage 128 RG (AGP)"},			\
+	{0x1002, 0x524b, 0, "ATI Rage 128 RK (PCI)"},			\
+	{0x1002, 0x524c, 0, "ATI Rage 128 RL (AGP)"},			\
+	{0x1002, 0x534d, 0, "ATI Rage 128 SM (AGP)"},			\
+	{0x1002, 0x5446, 0, "ATI Rage 128 Pro Ultra TF (AGP)"},		\
+	{0x1002, 0x544C, 0, "ATI Rage 128 Pro Ultra TL (AGP)"},		\
+	{0x1002, 0x5452, 0, "ATI Rage 128 Pro Ultra TR (AGP)"},		\
+	{0, 0, 0, NULL}
+
 /* Driver customization:
  */
 #define DRIVER_PRERELEASE() do {					\
@@ -97,7 +137,7 @@
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/r128_cce.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/r128_cce.c	2004-02-18 09:03:58.000000000 +0000
@@ -212,7 +212,7 @@
 	int i;
 
 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-		if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) {
+		if ( GET_RING_HEAD( dev_priv ) == dev_priv->ring.tail ) {
 			int pm4stat = R128_READ( R128_PM4_STAT );
 			if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >=
 			       dev_priv->cce_fifo_size ) &&
@@ -238,7 +238,8 @@
 	r128_do_wait_for_idle( dev_priv );
 
 	R128_WRITE( R128_PM4_BUFFER_CNTL,
-		    dev_priv->cce_mode | dev_priv->ring.size_l2qw );
+		    dev_priv->cce_mode | dev_priv->ring.size_l2qw
+		    | R128_PM4_BUFFER_CNTL_NOUPDATE );
 	R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */
 	R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN );
 
@@ -253,7 +254,6 @@
 {
 	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
 	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );
-	SET_RING_HEAD( &dev_priv->ring, 0 );
 	dev_priv->ring.tail = 0;
 }
 
@@ -264,7 +264,8 @@
 static void r128_do_cce_stop( drm_r128_private_t *dev_priv )
 {
 	R128_WRITE( R128_PM4_MICRO_CNTL, 0 );
-	R128_WRITE( R128_PM4_BUFFER_CNTL, R128_PM4_NONPM4 );
+	R128_WRITE( R128_PM4_BUFFER_CNTL,
+		    R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE );
 
 	dev_priv->cce_running = 0;
 }
@@ -333,26 +334,6 @@
 	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
 	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );
 
-	/* DL_RPTR_ADDR is a physical address in AGP space. */
-	SET_RING_HEAD( &dev_priv->ring, 0 );
-
-	if ( !dev_priv->is_pci ) {
-		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-			    dev_priv->ring_rptr->offset );
-	} else {
-		drm_sg_mem_t *entry = dev->sg;
-		unsigned long tmp_ofs, page_ofs;
-
-		tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle;
-		page_ofs = tmp_ofs >> PAGE_SHIFT;
-
-		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-     			    entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n",
-			   (unsigned long) entry->busaddr[page_ofs],
-     			   entry->handle + tmp_ofs );
-	}
-
 	/* Set watermark control */
 	R128_WRITE( R128_PM4_BUFFER_WM_CNTL,
 		    ((R128_WATERMARK_L/4) << R128_WMA_SHIFT)
@@ -486,13 +467,6 @@
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR("could not find framebuffer!\n");
-		dev->dev_private = (void *)dev_priv;
-		r128_do_cleanup_cce( dev );
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR("could not find mmio region!\n");
@@ -567,9 +541,6 @@
 #endif
 		dev_priv->cce_buffers_offset = dev->sg->handle;
 
-	dev_priv->ring.head = ((__volatile__ u32 *)
-			       dev_priv->ring_rptr->handle);
-
 	dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle;
 	dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle
 			      + init->ring_size / sizeof(u32));
@@ -580,7 +551,6 @@
 		(dev_priv->ring.size / sizeof(u32)) - 1;
 
 	dev_priv->ring.high_mark = 128;
-	dev_priv->ring.ring_rptr = dev_priv->ring_rptr;
 
 	dev_priv->sarea_priv->last_frame = 0;
 	R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame );
@@ -589,8 +559,9 @@
 	R128_WRITE( R128_LAST_DISPATCH_REG,
 		    dev_priv->sarea_priv->last_dispatch );
 
-#if __REALLY_HAVE_SG
+#if __REALLY_HAVE_AGP
 	if ( dev_priv->is_pci ) {
+#endif
 		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
      					    &dev_priv->bus_pci_gart) ) {
 			DRM_ERROR( "failed to init PCI GART!\n" );
@@ -599,6 +570,7 @@
 			return DRM_ERR(ENOMEM);
 		}
 		R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart );
+#if __REALLY_HAVE_AGP
 	}
 #endif
 
@@ -615,12 +587,12 @@
 int r128_do_cleanup_cce( drm_device_t *dev )
 {
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
@@ -901,7 +873,7 @@
 	int i;
 
 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
-		r128_update_ring_snapshot( ring );
+		r128_update_ring_snapshot( dev_priv );
 		if ( ring->space >= n )
 			return 0;
 		DRM_UDELAY( 1 );
--- diff/drivers/char/drm/r128_drv.c	2002-10-16 04:27:48.000000000 +0100
+++ source/drivers/char/drm/r128_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -47,6 +47,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/r128_drv.h	2003-08-20 14:16:27.000000000 +0100
+++ source/drivers/char/drm/r128_drv.h	2004-02-18 09:03:58.000000000 +0000
@@ -34,8 +34,7 @@
 #ifndef __R128_DRV_H__
 #define __R128_DRV_H__
 
-#define GET_RING_HEAD(ring)		DRM_READ32(  (ring)->ring_rptr, 0 ) /* (ring)->head */
-#define SET_RING_HEAD(ring,val)		DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */
+#define GET_RING_HEAD(dev_priv)		R128_READ( R128_PM4_BUFFER_DL_RPTR )
 
 typedef struct drm_r128_freelist {
    	unsigned int age;
@@ -50,13 +49,11 @@
 	int size;
 	int size_l2qw;
 
-	volatile u32 *head;
 	u32 tail;
 	u32 tail_mask;
 	int space;
 
 	int high_mark;
-	drm_local_map_t *ring_rptr;
 } drm_r128_ring_buffer_t;
 
 typedef struct drm_r128_private {
@@ -100,7 +97,6 @@
 	u32 span_pitch_offset_c;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *cce_ring;
 	drm_local_map_t *ring_rptr;
@@ -132,14 +128,6 @@
 
 extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n );
 
-static __inline__ void
-r128_update_ring_snapshot( drm_r128_ring_buffer_t *ring )
-{
-	ring->space = (GET_RING_HEAD( ring ) - ring->tail) * sizeof(u32);
-	if ( ring->space <= 0 )
-		ring->space += ring->size;
-}
-
 extern int r128_do_cce_idle( drm_r128_private_t *dev_priv );
 extern int r128_do_cleanup_cce( drm_device_t *dev );
 extern int r128_do_cleanup_pageflip( drm_device_t *dev );
@@ -279,6 +267,7 @@
 #	define R128_PM4_64PIO_64VCBM_64INDBM	(7  << 28)
 #	define R128_PM4_64BM_64VCBM_64INDBM	(8  << 28)
 #	define R128_PM4_64PIO_64VCPIO_64INDPIO	(15 << 28)
+#	define R128_PM4_BUFFER_CNTL_NOUPDATE	(1  << 27)
 
 #define R128_PM4_BUFFER_WM_CNTL		0x0708
 #	define R128_WMA_SHIFT			0
@@ -403,6 +392,15 @@
 					 (pkt) | ((n) << 16))
 
 
+static __inline__ void
+r128_update_ring_snapshot( drm_r128_private_t *dev_priv )
+{
+	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
+	ring->space = (GET_RING_HEAD( dev_priv ) - ring->tail) * sizeof(u32);
+	if ( ring->space <= 0 )
+		ring->space += ring->size;
+}
+
 /* ================================================================
  * Misc helper macros
  */
@@ -412,7 +410,7 @@
 	drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i;		\
 	if ( ring->space < ring->high_mark ) {				\
 		for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {	\
-			r128_update_ring_snapshot( ring );		\
+			r128_update_ring_snapshot( dev_priv );		\
 			if ( ring->space >= ring->high_mark )		\
 				goto __ring_space_done;			\
 			DRM_UDELAY(1);				\
@@ -445,17 +443,10 @@
  * Ring control
  */
 
-#if defined(__powerpc__)
-#define r128_flush_write_combine()	(void) GET_RING_HEAD( &dev_priv->ring )
-#else
-#define r128_flush_write_combine()	DRM_WRITEMEMORYBARRIER()
-#endif
-
-
 #define R128_VERBOSE	0
 
 #define RING_LOCALS							\
-	int write; unsigned int tail_mask; volatile u32 *ring;
+	int write, _nr; unsigned int tail_mask; volatile u32 *ring;
 
 #define BEGIN_RING( n ) do {						\
 	if ( R128_VERBOSE ) {						\
@@ -463,9 +454,10 @@
 			   (n), __FUNCTION__ );				\
 	}								\
 	if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {		\
+		COMMIT_RING();						\
 		r128_wait_ring( dev_priv, (n) * sizeof(u32) );		\
 	}								\
-	dev_priv->ring.space -= (n) * sizeof(u32);			\
+	_nr = n; dev_priv->ring.space -= (n) * sizeof(u32);		\
 	ring = dev_priv->ring.start;					\
 	write = dev_priv->ring.tail;					\
 	tail_mask = dev_priv->ring.tail_mask;				\
@@ -488,9 +480,23 @@
 			dev_priv->ring.start,				\
 			write * sizeof(u32) );				\
 	}								\
-	r128_flush_write_combine();					\
-	dev_priv->ring.tail = write;					\
-	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write );			\
+	if (((dev_priv->ring.tail + _nr) & tail_mask) != write) {	\
+		DRM_ERROR( 						\
+			"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",	\
+			((dev_priv->ring.tail + _nr) & tail_mask),	\
+			write, __LINE__);				\
+	} else								\
+		dev_priv->ring.tail = write;				\
+} while (0)
+
+#define COMMIT_RING() do {						\
+	if ( R128_VERBOSE ) {						\
+		DRM_INFO( "COMMIT_RING() tail=0x%06x\n",		\
+			dev_priv->ring.tail );				\
+	}								\
+	DRM_MEMORYBARRIER();						\
+	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail );	\
+	R128_READ( R128_PM4_BUFFER_DL_WPTR );				\
 } while (0)
 
 #define OUT_RING( x ) do {						\
--- diff/drivers/char/drm/r128_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/r128_irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -36,7 +36,7 @@
 #include "r128_drm.h"
 #include "r128_drv.h"
 
-irqreturn_t r128_dma_service( DRM_IRQ_ARGS )
+irqreturn_t r128_irq_handler( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_r128_private_t *dev_priv = 
--- diff/drivers/char/drm/r128_state.c	2003-08-20 14:16:27.000000000 +0100
+++ source/drivers/char/drm/r128_state.c	2004-02-18 09:03:58.000000000 +0000
@@ -45,7 +45,7 @@
 	RING_LOCALS;
 	DRM_DEBUG( "    %s\n", __FUNCTION__ );
 
-	BEGIN_RING( 17 );
+	BEGIN_RING( (count < 3? count: 3) * 5 + 2 );
 
 	if ( count >= 1 ) {
 		OUT_RING( CCE_PACKET0( R128_AUX1_SC_LEFT, 3 ) );
@@ -1269,6 +1269,7 @@
 		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
 
 	r128_cce_dispatch_clear( dev, &clear );
+	COMMIT_RING();
 
 	/* Make sure we restore the 3D state next time.
 	 */
@@ -1304,8 +1305,10 @@
 	R128_WRITE( R128_CRTC_OFFSET,      dev_priv->crtc_offset );
 	R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl );
 
-	if (dev_priv->current_page != 0)
+	if (dev_priv->current_page != 0) {
 		r128_cce_dispatch_flip( dev );
+		COMMIT_RING();
+	}
 
 	dev_priv->page_flipping = 0;
 	return 0;
@@ -1330,6 +1333,7 @@
 
 	r128_cce_dispatch_flip( dev );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1351,6 +1355,7 @@
 	dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
 					R128_UPLOAD_MASKS);
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1410,6 +1415,7 @@
 
 	r128_cce_dispatch_vertex( dev, buf );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1481,6 +1487,7 @@
 
 	r128_cce_dispatch_indices( dev, buf, elts.start, elts.end, count );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1490,6 +1497,7 @@
 	drm_device_dma_t *dma = dev->dma;
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_blit_t blit;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev, filp );
 
@@ -1507,7 +1515,10 @@
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	return r128_cce_dispatch_blit( filp, dev, &blit );
+	ret = r128_cce_dispatch_blit( filp, dev, &blit );
+
+	COMMIT_RING();
+	return ret;
 }
 
 int r128_cce_depth( DRM_IOCTL_ARGS )
@@ -1515,6 +1526,7 @@
 	DRM_DEVICE;
 	drm_r128_private_t *dev_priv = dev->dev_private;
 	drm_r128_depth_t depth;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev, filp );
 
@@ -1523,18 +1535,20 @@
 
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
+	ret = DRM_ERR(EINVAL);
 	switch ( depth.func ) {
 	case R128_WRITE_SPAN:
-		return r128_cce_dispatch_write_span( dev, &depth );
+		ret = r128_cce_dispatch_write_span( dev, &depth );
 	case R128_WRITE_PIXELS:
-		return r128_cce_dispatch_write_pixels( dev, &depth );
+		ret = r128_cce_dispatch_write_pixels( dev, &depth );
 	case R128_READ_SPAN:
-		return r128_cce_dispatch_read_span( dev, &depth );
+		ret = r128_cce_dispatch_read_span( dev, &depth );
 	case R128_READ_PIXELS:
-		return r128_cce_dispatch_read_pixels( dev, &depth );
+		ret = r128_cce_dispatch_read_pixels( dev, &depth );
 	}
 
-	return DRM_ERR(EINVAL);
+	COMMIT_RING();
+	return ret;
 }
 
 int r128_cce_stipple( DRM_IOCTL_ARGS )
@@ -1557,6 +1571,7 @@
 
 	r128_cce_dispatch_stipple( dev, mask );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1632,6 +1647,7 @@
 	 */
 	r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end );
 
+	COMMIT_RING();
 	return 0;
 }
 
--- diff/drivers/char/drm/radeon.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon.h	2004-02-18 09:03:58.000000000 +0000
@@ -51,7 +51,7 @@
 #define DRIVER_DATE		"20020828"
 
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		9
+#define DRIVER_MINOR		10
 #define DRIVER_PATCHLEVEL	0
 
 /* Interface history:
@@ -81,6 +81,9 @@
  *       Add 'GET' queries for starting additional clients on different VT's.
  * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl.
  *       Add texture rectangle support for r100.
+ * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which
+ *       clients use to tell the DRM where they think the framebuffer is 
+ *       located in the card's address space
  */
 #define DRIVER_IOCTLS							     \
  [DRM_IOCTL_NR(DRM_IOCTL_DMA)]               = { radeon_cp_buffers,  1, 0 }, \
@@ -106,10 +109,82 @@
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)]      = { radeon_mem_alloc,   1, 0 }, \
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)]       = { radeon_mem_free,    1, 0 }, \
  [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)]  = { radeon_mem_init_heap, 1, 1 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)]   = { radeon_irq_emit, 1, 0 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)]   = { radeon_irq_wait, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)]   = { radeon_irq_emit,    1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)]   = { radeon_irq_wait,    1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)]   = { radeon_cp_setparam, 1, 0 }, \
+
+#define DRIVER_PCI_IDS							\
+	{0x1002, 0x4136, 0, "ATI Radeon RS100 IGP 320M"},		\
+	{0x1002, 0x4137, 0, "ATI Radeon RS200 IGP"},			\
+	{0x1002, 0x4237, 0, "ATI Radeon RS250 IGP"},			\
+	{0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"},		\
+	{0x1002, 0x4242, 0, "ATI Radeon BC R200"},			\
+	{0x1002, 0x4336, 0, "ATI Radeon RS100 Mobility U1"},		\
+	{0x1002, 0x4337, 0, "ATI Radeon RS200 Mobility IGP 340M"},	\
+	{0x1002, 0x4437, 0, "ATI Radeon RS250 Mobility IGP"},		\
+	{0x1002, 0x4964, 0, "ATI Radeon Id R250 9000"},			\
+	{0x1002, 0x4965, 0, "ATI Radeon Ie R250 9000"},			\
+	{0x1002, 0x4966, 0, "ATI Radeon If R250 9000"},			\
+	{0x1002, 0x4967, 0, "ATI Radeon Ig R250 9000"},			\
+	{0x1002, 0x4C57, 0, "ATI Radeon LW Mobility 7500 M7"},		\
+	{0x1002, 0x4C58, 0, "ATI Radeon LX RV200 Mobility FireGL 7800 M7"}, \
+	{0x1002, 0x4C59, 0, "ATI Radeon LY Mobility M6"},		\
+	{0x1002, 0x4C5A, 0, "ATI Radeon LZ Mobility M6"},		\
+	{0x1002, 0x4C64, 0, "ATI Radeon Ld R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C65, 0, "ATI Radeon Le R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C66, 0, "ATI Radeon Lf R250 Mobility 9000 M9"},	\
+	{0x1002, 0x4C67, 0, "ATI Radeon Lg R250 Mobility 9000 M9"},	\
+	{0x1002, 0x5144, 0, "ATI Radeon QD R100"},			\
+	{0x1002, 0x5145, 0, "ATI Radeon QE R100"},			\
+	{0x1002, 0x5146, 0, "ATI Radeon QF R100"},			\
+	{0x1002, 0x5147, 0, "ATI Radeon QG R100"},			\
+	{0x1002, 0x5148, 0, "ATI Radeon QH R200 8500"},			\
+	{0x1002, 0x5149, 0, "ATI Radeon QI R200"},			\
+	{0x1002, 0x514A, 0, "ATI Radeon QJ R200"},			\
+	{0x1002, 0x514B, 0, "ATI Radeon QK R200"},			\
+	{0x1002, 0x514C, 0, "ATI Radeon QL R200 8500 LE"},		\
+	{0x1002, 0x514D, 0, "ATI Radeon QM R200 9100"},			\
+	{0x1002, 0x514E, 0, "ATI Radeon QN R200 8500 LE"},		\
+	{0x1002, 0x514F, 0, "ATI Radeon QO R200 8500 LE"},		\
+	{0x1002, 0x5157, 0, "ATI Radeon QW RV200 7500"},		\
+	{0x1002, 0x5158, 0, "ATI Radeon QX RV200 7500"},		\
+	{0x1002, 0x5159, 0, "ATI Radeon QY RV100 7000/VE"},		\
+	{0x1002, 0x515A, 0, "ATI Radeon QZ RV100 7000/VE"},		\
+	{0x1002, 0x5168, 0, "ATI Radeon Qh R200"},			\
+	{0x1002, 0x5169, 0, "ATI Radeon Qi R200"},			\
+	{0x1002, 0x516A, 0, "ATI Radeon Qj R200"},			\
+	{0x1002, 0x516B, 0, "ATI Radeon Qk R200"},			\
+	{0x1002, 0x516C, 0, "ATI Radeon Ql R200"},			\
+	{0x1002, 0x5834, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5835, 0, "ATI Radeon RS300 Mobility IGP"},		\
+	{0x1002, 0x5836, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5837, 0, "ATI Radeon RS300 IGP"},			\
+	{0x1002, 0x5960, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5961, 0, "ATI Radeon RV280 9200 SE"},		\
+	{0x1002, 0x5962, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5963, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5964, 0, "ATI Radeon RV280 9200 SE"},		\
+	{0x1002, 0x5968, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5969, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x596A, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x596B, 0, "ATI Radeon RV280 9200"},			\
+	{0x1002, 0x5c61, 0, "ATI Radeon RV280 Mobility"},		\
+	{0x1002, 0x5c62, 0, "ATI Radeon RV280"},			\
+	{0x1002, 0x5c63, 0, "ATI Radeon RV280 Mobility"},		\
+	{0x1002, 0x5c64, 0, "ATI Radeon RV280"},			\
+	{0, 0, 0, NULL}
 
+#define DRIVER_FILE_FIELDS						\
+	int64_t radeon_fb_delta;					\
 
+#define DRIVER_OPEN_HELPER( filp_priv, dev )				\
+do {									\
+	drm_radeon_private_t *dev_priv = dev->dev_private;		\
+	if ( dev_priv )							\
+		filp_priv->radeon_fb_delta = dev_priv->fb_location;	\
+	else								\
+		filp_priv->radeon_fb_delta = 0;				\
+} while( 0 )
 
 /* When a client dies:
  *    - Check for and clean up flipped page state
@@ -125,7 +200,7 @@
 			radeon_do_cleanup_pageflip( dev );		\
 		}							\
 		radeon_mem_release( filp, dev_priv->gart_heap );	\
-                radeon_mem_release( filp, dev_priv->fb_heap );		\
+		radeon_mem_release( filp, dev_priv->fb_heap );		\
 	}								\
 } while (0)
 
@@ -142,7 +217,7 @@
 /* DMA customization:
  */
 #define __HAVE_DMA		1
-#define __HAVE_DMA_IRQ		1
+#define __HAVE_IRQ		1
 #define __HAVE_VBL_IRQ		1
 #define __HAVE_SHARED_IRQ       1
 
--- diff/drivers/char/drm/radeon_cp.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_cp.c	2004-02-18 09:03:58.000000000 +0000
@@ -855,7 +855,8 @@
 
 	/* Initialize the memory controller */
 	RADEON_WRITE( RADEON_MC_FB_LOCATION,
-		      (dev_priv->gart_vm_start - 1) & 0xffff0000 );
+		      ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 )
+		    | ( dev_priv->fb_location >> 16 ) );
 
 #if __REALLY_HAVE_AGP
 	if ( !dev_priv->is_pci ) {
@@ -1071,13 +1072,6 @@
 	dev_priv->depth_offset	= init->depth_offset;
 	dev_priv->depth_pitch	= init->depth_pitch;
 
-	dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
-					(dev_priv->front_offset >> 10));
-	dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
-				       (dev_priv->back_offset >> 10));
-	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
-					(dev_priv->depth_offset >> 10));
-
 	/* Hardware state for depth clears.  Remove this if/when we no
 	 * longer clear the depth buffer with a 3D rectangle.  Hard-code
 	 * all values to prevent unwanted 3D state from slipping through
@@ -1124,13 +1118,6 @@
 		return DRM_ERR(EINVAL);
 	}
 
-	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
-	if(!dev_priv->fb) {
-		DRM_ERROR("could not find framebuffer!\n");
-		dev->dev_private = (void *)dev_priv;
-		radeon_do_cleanup_cp(dev);
-		return DRM_ERR(EINVAL);
-	}
 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
 	if(!dev_priv->mmio) {
 		DRM_ERROR("could not find mmio region!\n");
@@ -1204,9 +1191,26 @@
 			   dev_priv->buffers->handle );
 	}
 
+	dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION )
+				& 0xffff ) << 16;
+
+	dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) |
+					( ( dev_priv->front_offset
+					  + dev_priv->fb_location ) >> 10 ) );
+
+	dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) |
+				       ( ( dev_priv->back_offset
+					 + dev_priv->fb_location ) >> 10 ) );
+
+	dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) |
+					( ( dev_priv->depth_offset
+					  + dev_priv->fb_location ) >> 10 ) );
+
 
 	dev_priv->gart_size = init->gart_size;
-	dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );
+	dev_priv->gart_vm_start = dev_priv->fb_location
+				+ RADEON_READ( RADEON_CONFIG_APER_SIZE );
+
 #if __REALLY_HAVE_AGP
 	if ( !dev_priv->is_pci )
 		dev_priv->gart_buffers_offset = (dev_priv->buffers->offset
@@ -1271,12 +1275,12 @@
 {
 	DRM_DEBUG( "\n" );
 
-#if _HAVE_DMA_IRQ
+#if __HAVE_IRQ
 	/* Make sure interrupts are disabled here because the uninstall ioctl
 	 * may not have been called from userspace and after dev_private
 	 * is freed, it's too late.
 	 */
-	if ( dev->irq ) DRM(irq_uninstall)(dev);
+	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
 #endif
 
 	if ( dev->dev_private ) {
--- diff/drivers/char/drm/radeon_drm.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_drm.h	2004-02-18 09:03:58.000000000 +0000
@@ -390,6 +390,7 @@
 #define DRM_IOCTL_RADEON_IRQ_WAIT   DRM_IOW( 0x57, drm_radeon_irq_wait_t)
 /* added by Charl P. Botha - see radeon_cp.c for details */
 #define DRM_IOCTL_RADEON_CP_RESUME  DRM_IO(0x58)
+#define DRM_IOCTL_RADEON_SETPARAM   DRM_IOW(0x59, drm_radeon_setparam_t)
 
 typedef struct drm_radeon_init {
 	enum {
@@ -502,7 +503,7 @@
 } drm_radeon_tex_image_t;
 
 typedef struct drm_radeon_texture {
-	int offset;
+	unsigned int offset;
 	int pitch;
 	int format;
 	int width;			/* Texture image coordinates */
@@ -537,6 +538,7 @@
 #define RADEON_PARAM_STATUS_HANDLE         8
 #define RADEON_PARAM_SAREA_HANDLE          9
 #define RADEON_PARAM_GART_TEX_HANDLE       10
+#define RADEON_PARAM_SCRATCH_OFFSET        11
 
 typedef struct drm_radeon_getparam {
 	int param;
@@ -578,4 +580,16 @@
 } drm_radeon_irq_wait_t;
 
 
+/* 1.10: Clients tell the DRM where they think the framebuffer is located in
+ * the card's address space, via a new generic ioctl to set parameters
+ */
+
+typedef struct drm_radeon_setparam {
+	unsigned int param;
+	int64_t      value;
+} drm_radeon_setparam_t;
+
+#define RADEON_SETPARAM_FB_LOCATION    1 /* determined framebuffer location */
+
+
 #endif
--- diff/drivers/char/drm/radeon_drv.c	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/char/drm/radeon_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -48,6 +48,7 @@
 #include "drm_fops.h"
 #include "drm_init.h"
 #include "drm_ioctl.h"
+#include "drm_irq.h"
 #include "drm_lock.h"
 #include "drm_memory.h"
 #include "drm_proc.h"
--- diff/drivers/char/drm/radeon_drv.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/radeon_drv.h	2004-02-18 09:03:58.000000000 +0000
@@ -73,6 +73,8 @@
 	drm_radeon_ring_buffer_t ring;
 	drm_radeon_sarea_t *sarea_priv;
 
+	u32 fb_location;
+
 	int gart_size;
 	u32 gart_vm_start;
 	unsigned long gart_buffers_offset;
@@ -133,7 +135,6 @@
 	unsigned long gart_textures_offset;
 
 	drm_local_map_t *sarea;
-	drm_local_map_t *fb;
 	drm_local_map_t *mmio;
 	drm_local_map_t *cp_ring;
 	drm_local_map_t *ring_rptr;
@@ -184,6 +185,7 @@
 extern int radeon_cp_vertex2( DRM_IOCTL_ARGS );
 extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS );
 extern int radeon_cp_getparam( DRM_IOCTL_ARGS );
+extern int radeon_cp_setparam( DRM_IOCTL_ARGS );
 extern int radeon_cp_flip( DRM_IOCTL_ARGS );
 
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
@@ -239,6 +241,7 @@
 #define RADEON_CRTC2_OFFSET		0x0324
 #define RADEON_CRTC2_OFFSET_CNTL	0x0328
 
+#define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
 #define RADEON_DP_GUI_MASTER_CNTL	0x146c
@@ -332,6 +335,7 @@
 #define RADEON_PP_MISC			0x1c14
 #define RADEON_PP_ROT_MATRIX_0		0x1d58
 #define RADEON_PP_TXFILTER_0		0x1c54
+#define RADEON_PP_TXOFFSET_0		0x1c5c
 #define RADEON_PP_TXFILTER_1		0x1c6c
 #define RADEON_PP_TXFILTER_2		0x1c84
 
--- diff/drivers/char/drm/radeon_irq.c	2003-05-21 11:50:14.000000000 +0100
+++ source/drivers/char/drm/radeon_irq.c	2004-02-18 09:03:58.000000000 +0000
@@ -54,7 +54,7 @@
  * tied to dma at all, this is just a hangover from dri prehistory.
  */
 
-irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS )
+irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS )
 {
 	drm_device_t *dev = (drm_device_t *) arg;
 	drm_radeon_private_t *dev_priv = 
--- diff/drivers/char/drm/radeon_state.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/drm/radeon_state.c	2004-02-18 09:03:58.000000000 +0000
@@ -36,6 +36,151 @@
 
 
 /* ================================================================
+ * Helper functions for client state checking and fixup
+ */
+
+static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv,
+						     drm_file_t *filp_priv,
+						     u32 *offset ) {
+	u32 off = *offset;
+
+	if ( off >= dev_priv->fb_location &&
+	     off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+		return 0;
+
+	off += filp_priv->radeon_fb_delta;
+
+	DRM_DEBUG( "offset fixed up to 0x%x\n", off );
+
+	if ( off < dev_priv->fb_location ||
+	     off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+		return DRM_ERR( EINVAL );
+
+	*offset = off;
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv,
+							  drm_file_t *filp_priv,
+							  u32 *offset ) {
+	u32 off;
+
+	DRM_GET_USER_UNCHECKED( off, offset );
+
+	if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) )
+		return DRM_ERR( EINVAL );
+
+	DRM_PUT_USER_UNCHECKED( offset, off );
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv,
+						      drm_file_t *filp_priv,
+						      int id,
+						      u32 *data ) {
+	if ( id == RADEON_EMIT_PP_MISC &&
+	     radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+						 &data[( RADEON_RB3D_DEPTHOFFSET
+							 - RADEON_PP_MISC ) / 4] ) ) {
+		DRM_ERROR( "Invalid depth buffer offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id == RADEON_EMIT_PP_CNTL &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[( RADEON_RB3D_COLOROFFSET
+								- RADEON_PP_CNTL ) / 4] ) ) {
+		DRM_ERROR( "Invalid colour buffer offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id >= R200_EMIT_PP_TXOFFSET_0 &&
+		    id <= R200_EMIT_PP_TXOFFSET_5 &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[0] ) ) {
+		DRM_ERROR( "Invalid R200 texture offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 ||
+		      id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 ||
+		      id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) &&
+		    radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+							&data[( RADEON_PP_TXOFFSET_0
+								- RADEON_PP_TXFILTER_0 ) / 4] ) ) {
+		DRM_ERROR( "Invalid R100 texture offset\n" );
+		return DRM_ERR( EINVAL );
+	} else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 ||
+		    id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 ||
+		    id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) {
+		int i;
+		for ( i = 0; i < 6; i++ ) {
+			if ( radeon_check_and_fixup_offset_user( dev_priv,
+								 filp_priv,
+								 &data[i] ) ) {
+				DRM_ERROR( "Invalid R200 cubic texture offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+		}
+	}
+
+	return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv,
+						      drm_file_t *filp_priv,
+						      drm_radeon_cmd_buffer_t *cmdbuf,
+						      unsigned int *cmdsz ) {
+	u32 tmp[4], *cmd = ( u32* )cmdbuf->buf;
+
+	if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) {
+		DRM_ERROR( "Failed to copy data from user space\n" );
+		return DRM_ERR( EFAULT );
+	}
+
+	*cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
+
+	if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
+		DRM_ERROR( "Not a type 3 packet\n" );
+		return DRM_ERR( EINVAL );
+	}
+
+	if ( 4 * *cmdsz > cmdbuf->bufsz ) {
+		DRM_ERROR( "Packet size larger than size of data provided\n" );
+		return DRM_ERR( EINVAL );
+	}
+
+	/* Check client state and fix it up if necessary */
+	if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
+		u32 offset;
+
+		if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+			offset = tmp[2] << 10;
+			if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+				DRM_ERROR( "Invalid first packet offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+			tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10;
+		}
+
+		if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
+		     ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+			offset = tmp[3] << 10;
+			if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+				DRM_ERROR( "Invalid second packet offset\n" );
+				return DRM_ERR( EINVAL );
+			}
+			tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10;
+		}
+
+		if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) {
+			DRM_ERROR( "Failed to copy data to user space\n" );
+			return DRM_ERR( EFAULT );
+		}
+	}
+
+	return 0;
+}
+
+
+/* ================================================================
  * CP hardware state programming functions
  */
 
@@ -57,15 +202,28 @@
 
 /* Emit 1.1 state
  */
-static void radeon_emit_state( drm_radeon_private_t *dev_priv,
-			       drm_radeon_context_regs_t *ctx,
-			       drm_radeon_texture_regs_t *tex,
-			       unsigned int dirty )
+static int radeon_emit_state( drm_radeon_private_t *dev_priv,
+			      drm_file_t *filp_priv,
+			      drm_radeon_context_regs_t *ctx,
+			      drm_radeon_texture_regs_t *tex,
+			      unsigned int dirty )
 {
 	RING_LOCALS;
 	DRM_DEBUG( "dirty=0x%08x\n", dirty );
 
 	if ( dirty & RADEON_UPLOAD_CONTEXT ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &ctx->rb3d_depthoffset ) ) {
+			DRM_ERROR( "Invalid depth buffer offset\n" );
+			return DRM_ERR( EINVAL );
+		}
+
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &ctx->rb3d_coloroffset ) ) {
+			DRM_ERROR( "Invalid depth buffer offset\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 14 );
 		OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
 		OUT_RING( ctx->pp_misc );
@@ -149,6 +307,12 @@
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX0 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[0].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 0\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
 		OUT_RING( tex[0].pp_txfilter );
@@ -163,6 +327,12 @@
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX1 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[1].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 1\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
 		OUT_RING( tex[1].pp_txfilter );
@@ -177,6 +347,12 @@
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX2 ) {
+		if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+						    &tex[2].pp_txoffset ) ) {
+			DRM_ERROR( "Invalid texture offset for unit 2\n" );
+			return DRM_ERR( EINVAL );
+		}
+
 		BEGIN_RING( 9 );
 		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
 		OUT_RING( tex[2].pp_txfilter );
@@ -189,12 +365,15 @@
 		OUT_RING( tex[2].pp_border_color );
 		ADVANCE_RING();
 	}
+
+	return 0;
 }
 
 /* Emit 1.2 state
  */
-static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
-				drm_radeon_state_t *state )
+static int radeon_emit_state2( drm_radeon_private_t *dev_priv,
+			       drm_file_t *filp_priv,
+			       drm_radeon_state_t *state )
 {
 	RING_LOCALS;
 
@@ -206,7 +385,7 @@
 		ADVANCE_RING();
 	}
 
-	radeon_emit_state( dev_priv, &state->context, 
+	return radeon_emit_state( dev_priv, filp_priv, &state->context,
 			   state->tex, state->dirty );
 }
 
@@ -1065,6 +1244,7 @@
 				       drm_radeon_tex_image_t *image )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_buf_t *buf;
 	u32 format;
 	u32 *buffer;
@@ -1074,6 +1254,13 @@
 	int i;
 	RING_LOCALS;
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+	if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) {
+		DRM_ERROR( "Invalid destination offset\n" );
+		return DRM_ERR( EINVAL );
+	}
+
 	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
 
 	/* Flush the pixel cache.  This ensures no pixel data gets mixed
@@ -1377,6 +1564,7 @@
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1390,6 +1578,8 @@
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data,
 			     sizeof(vertex) );
 
@@ -1429,11 +1619,14 @@
 		buf->used = vertex.count; /* not used? */
 
 		if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-			radeon_emit_state( dev_priv,
-					   &sarea_priv->context_state,
-					   sarea_priv->tex_state,
-					   sarea_priv->dirty );
-			
+			if ( radeon_emit_state( dev_priv, filp_priv,
+						&sarea_priv->context_state,
+						sarea_priv->tex_state,
+						sarea_priv->dirty ) ) {
+				DRM_ERROR( "radeon_emit_state failed\n" );
+				return DRM_ERR( EINVAL );
+			}
+
 			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
 					       RADEON_UPLOAD_TEX1IMAGES |
 					       RADEON_UPLOAD_TEX2IMAGES |
@@ -1461,6 +1654,7 @@
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1475,6 +1669,8 @@
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data,
 			     sizeof(elts) );
 
@@ -1523,10 +1719,13 @@
 	buf->used = elts.end;
 
 	if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-		radeon_emit_state( dev_priv,
-				   &sarea_priv->context_state,
-				   sarea_priv->tex_state,
-				   sarea_priv->dirty );
+		if ( radeon_emit_state( dev_priv, filp_priv,
+					&sarea_priv->context_state,
+					sarea_priv->tex_state,
+					sarea_priv->dirty ) ) {
+			DRM_ERROR( "radeon_emit_state failed\n" );
+			return DRM_ERR( EINVAL );
+		}
 
 		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
 				       RADEON_UPLOAD_TEX1IMAGES |
@@ -1686,6 +1885,7 @@
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
@@ -1700,6 +1900,8 @@
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data,
 			     sizeof(vertex) );
 
@@ -1747,7 +1949,10 @@
 					     sizeof(state) ) )
 				return DRM_ERR(EFAULT);
 
-			radeon_emit_state2( dev_priv, &state );
+			if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) {
+				DRM_ERROR( "radeon_emit_state2 failed\n" );
+				return DRM_ERR( EINVAL );
+			}
 
 			laststate = prim.stateidx;
 		}
@@ -1784,6 +1989,7 @@
 
 static int radeon_emit_packets( 
 	drm_radeon_private_t *dev_priv,
+	drm_file_t *filp_priv,
 	drm_radeon_cmd_header_t header,
 	drm_radeon_cmd_buffer_t *cmdbuf )
 {
@@ -1798,8 +2004,15 @@
 	sz = packet[id].len;
 	reg = packet[id].start;
 
-	if (sz * sizeof(int) > cmdbuf->bufsz) 
+	if (sz * sizeof(int) > cmdbuf->bufsz) {
+		DRM_ERROR( "Packet size provided larger than data provided\n" );
 		return DRM_ERR(EINVAL);
+	}
+
+	if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return DRM_ERR( EINVAL );
+	}
 
 	BEGIN_RING(sz+1);
 	OUT_RING( CP_PACKET0( reg, (sz-1) ) );
@@ -1882,24 +2095,21 @@
 
 
 static int radeon_emit_packet3( drm_device_t *dev,
+				drm_file_t *filp_priv,
 				drm_radeon_cmd_buffer_t *cmdbuf )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	int cmdsz, tmp;
-	int *cmd = (int *)cmdbuf->buf;
+	unsigned int cmdsz;
+	int *cmd = (int *)cmdbuf->buf, ret;
 	RING_LOCALS;
 
-
 	DRM_DEBUG("\n");
 
-	if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
-		return DRM_ERR(EFAULT);
-
-	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
-	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
-	    cmdsz * 4 > cmdbuf->bufsz)
-		return DRM_ERR(EINVAL);
+	if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+						     cmdbuf, &cmdsz ) ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return ret;
+	}
 
 	BEGIN_RING( cmdsz );
 	OUT_RING_USER_TABLE( cmd, cmdsz );
@@ -1912,27 +2122,25 @@
 
 
 static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+					 drm_file_t *filp_priv,
 					 drm_radeon_cmd_buffer_t *cmdbuf,
 					 int orig_nbox )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_clip_rect_t box;
-	int cmdsz, tmp;
-	int *cmd = (int *)cmdbuf->buf;
+	unsigned int cmdsz;
+	int *cmd = (int *)cmdbuf->buf, ret;
 	drm_clip_rect_t *boxes = cmdbuf->boxes;
 	int i = 0;
 	RING_LOCALS;
 
 	DRM_DEBUG("\n");
 
-	if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
-		return DRM_ERR(EFAULT);
-
-	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
-	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
-	    cmdsz * 4 > cmdbuf->bufsz)
-		return DRM_ERR(EINVAL);
+	if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+						     cmdbuf, &cmdsz ) ) ) {
+		DRM_ERROR( "Packet verification failed\n" );
+		return ret;
+	}
 
 	if (!orig_nbox)
 		goto out;
@@ -2009,6 +2217,7 @@
 {
 	DRM_DEVICE;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf = 0;
 	int idx;
@@ -2023,6 +2232,8 @@
 		return DRM_ERR(EINVAL);
 	}
 
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
 	DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
 			     sizeof(cmdbuf) );
 
@@ -2053,7 +2264,7 @@
 		switch (header.header.cmd_type) {
 		case RADEON_CMD_PACKET: 
 			DRM_DEBUG("RADEON_CMD_PACKET\n");
-			if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+			if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) {
 				DRM_ERROR("radeon_emit_packets failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2096,7 +2307,7 @@
 
 		case RADEON_CMD_PACKET3:
 			DRM_DEBUG("RADEON_CMD_PACKET3\n");
-			if (radeon_emit_packet3( dev, &cmdbuf )) {
+			if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) {
 				DRM_ERROR("radeon_emit_packet3 failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2104,7 +2315,7 @@
 
 		case RADEON_CMD_PACKET3_CLIP:
 			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
-			if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) {
+			if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) {
 				DRM_ERROR("radeon_emit_packet3_clip failed\n");
 				return DRM_ERR(EINVAL);
 			}
@@ -2214,3 +2425,31 @@
 	
 	return 0;
 }
+
+int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
+	DRM_DEVICE;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_file_t *filp_priv;
+	drm_radeon_setparam_t sp;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return DRM_ERR( EINVAL );
+	}
+
+	DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+	DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data,
+				  sizeof( sp ) );
+
+	switch( sp.param ) {
+	case RADEON_SETPARAM_FB_LOCATION:
+		filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+		break;
+	default:
+		DRM_DEBUG( "Invalid parameter %d\n", sp.param );
+		return DRM_ERR( EINVAL );
+	}
+
+	return 0;
+}
--- diff/drivers/char/drm/sis.h	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/sis.h	2004-02-18 09:03:58.000000000 +0000
@@ -62,6 +62,13 @@
 	[DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)]	= { sis_ioctl_agp_free,	1, 0 }, \
 	[DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)]	= { sis_fb_init,	1, 1 }
 
+#define DRIVER_PCI_IDS							\
+	{0x1039, 0x0300, 0, "SiS 300/305"},				\
+	{0x1039, 0x5300, 0, "SiS 540"},					\
+	{0x1039, 0x6300, 0, "SiS 630"},					\
+	{0x1039, 0x7300, 0, "SiS 730"},					\
+	{0, 0, 0, NULL}
+
 #define __HAVE_COUNTERS		5
 
 /* Buffer customization:
--- diff/drivers/char/drm/sis_mm.c	2003-09-30 15:46:12.000000000 +0100
+++ source/drivers/char/drm/sis_mm.c	2004-02-18 09:03:58.000000000 +0000
@@ -34,7 +34,11 @@
 #include "sis_drv.h"
 #include "sis_ds.h"
 #if defined(__linux__) && defined(CONFIG_FB_SIS)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <video/sisfb.h>
+#else
+#include <linux/sisfb.h>
+#endif
 #endif
 
 #define MAX_CONTEXT 100
@@ -132,7 +136,7 @@
 		retval = DRM_ERR(EINVAL);
 	sis_free(fb.free);
 
-	DRM_DEBUG("free fb, offset = %lu\n", fb.free);
+	DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
 
 	return retval;
 }
--- diff/drivers/char/drm/tdfx.h	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/char/drm/tdfx.h	2004-02-18 09:03:58.000000000 +0000
@@ -39,4 +39,22 @@
 #define __HAVE_MTRR		1
 #define __HAVE_CTX_BITMAP	1
 
+#define DRIVER_AUTHOR		"VA Linux Systems Inc."
+
+#define DRIVER_NAME		"tdfx"
+#define DRIVER_DESC		"3dfx Banshee/Voodoo3+"
+#define DRIVER_DATE		"20010216"
+
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		0
+#define DRIVER_PATCHLEVEL	0
+
+#define DRIVER_PCI_IDS							\
+	{0x121a, 0x0003, 0, "3dfx Voodoo Banshee"},			\
+	{0x121a, 0x0004, 0, "3dfx Voodoo3 2000"},			\
+	{0x121a, 0x0005, 0, "3dfx Voodoo3 3000"},			\
+	{0x121a, 0x0007, 0, "3dfx Voodoo4"},				\
+	{0x121a, 0x0009, 0, "3dfx Voodoo5"},				\
+	{0, 0, 0, NULL}
+
 #endif
--- diff/drivers/char/drm/tdfx_drv.c	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/char/drm/tdfx_drv.c	2004-02-18 09:03:58.000000000 +0000
@@ -34,47 +34,6 @@
 #include "tdfx.h"
 #include "drmP.h"
 
-#define DRIVER_AUTHOR		"VA Linux Systems Inc."
-
-#define DRIVER_NAME		"tdfx"
-#define DRIVER_DESC		"3dfx Banshee/Voodoo3+"
-#define DRIVER_DATE		"20010216"
-
-#define DRIVER_MAJOR		1
-#define DRIVER_MINOR		0
-#define DRIVER_PATCHLEVEL	0
-
-#ifndef PCI_VENDOR_ID_3DFX
-#define PCI_VENDOR_ID_3DFX 0x121A
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO5
-#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO4
-#define PCI_DEVICE_ID_3DFX_VOODOO4 0x0007
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_3000 /* Voodoo3 3000 */
-#define PCI_DEVICE_ID_3DFX_VOODOO3_3000 0x0005
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_2000 /* Voodoo3 3000 */
-#define PCI_DEVICE_ID_3DFX_VOODOO3_2000 0x0004
-#endif
-#ifndef PCI_DEVICE_ID_3DFX_BANSHEE
-#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
-#endif
-
-static drm_pci_list_t DRM(idlist)[] = {
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_2000 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_3000 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO4 },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5 },
-	{ 0, 0 }
-};
-
-#define DRIVER_CARD_LIST DRM(idlist)
-
-
 #include "drm_auth.h"
 #include "drm_bufs.h"
 #include "drm_context.h"
--- diff/drivers/char/epca.c	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/char/epca.c	2004-02-18 09:03:58.000000000 +0000
@@ -2931,6 +2931,96 @@
 }
 /* --------------------- Begin pc_ioctl  ----------------------- */
 
+static int pc_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct channel *ch = (struct channel *) tty->driver_data;
+	volatile struct board_chan *bc;
+	unsigned int mstat, mflag = 0;
+	unsigned long flags;
+
+	if (ch)
+		bc = ch->brdchan;
+	else
+	{
+		printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n");
+		return(-EINVAL);
+	}
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+	mstat = bc->mstat;
+	memoff(ch);
+	restore_flags(flags);
+
+	if (mstat & ch->m_dtr)
+		mflag |= TIOCM_DTR;
+
+	if (mstat & ch->m_rts)
+		mflag |= TIOCM_RTS;
+
+	if (mstat & ch->m_cts)
+		mflag |= TIOCM_CTS;
+
+	if (mstat & ch->dsr)
+		mflag |= TIOCM_DSR;
+
+	if (mstat & ch->m_ri)
+		mflag |= TIOCM_RI;
+
+	if (mstat & ch->dcd)
+		mflag |= TIOCM_CD;
+
+	return mflag;
+}
+
+static int pc_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
+{
+	struct channel *ch = (struct channel *) tty->driver_data;
+	unsigned long flags;
+
+	if (!ch) {
+		printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n");
+		return(-EINVAL);
+	}
+
+	save_flags(flags);
+	cli();
+	/*
+	 * I think this modemfake stuff is broken.  It doesn't
+	 * correctly reflect the behaviour desired by the TIOCM*
+	 * ioctls.  Therefore this is probably broken.
+	 */
+	if (set & TIOCM_RTS) {
+		ch->modemfake |= ch->m_rts;
+		ch->modem |= ch->m_rts;
+	}
+	if (set & TIOCM_DTR) {
+		ch->modemfake |= ch->m_dtr;
+		ch->modem |= ch->m_dtr;
+	}
+	if (clear & TIOCM_RTS) {
+		ch->modemfake |= ch->m_rts;
+		ch->modem &= ~ch->m_rts;
+	}
+	if (clear & TIOCM_DTR) {
+		ch->modemfake |= ch->m_dtr;
+		ch->modem &= ~ch->m_dtr;
+	}
+
+	globalwinon(ch);
+
+	/*  --------------------------------------------------------------
+		The below routine generally sets up parity, baud, flow control
+		issues, etc.... It effect both control flags and input flags.
+	------------------------------------------------------------------ */
+
+	epcaparam(tty,ch);
+	memoff(ch);
+	restore_flags(flags);
+}
+
 static int pc_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 { /* Begin pc_ioctl */
@@ -3021,90 +3111,15 @@
 		}
 
 		case TIOCMODG:
-		case TIOCMGET:
-
-			mflag = 0;
-
-			cli();
-			globalwinon(ch);
-			mstat = bc->mstat;
-			memoff(ch);
-			restore_flags(flags);
-
-			if (mstat & ch->m_dtr)
-				mflag |= TIOCM_DTR;
-
-			if (mstat & ch->m_rts)
-				mflag |= TIOCM_RTS;
-
-			if (mstat & ch->m_cts)
-				mflag |= TIOCM_CTS;
-
-			if (mstat & ch->dsr)
-				mflag |= TIOCM_DSR;
-
-			if (mstat & ch->m_ri)
-				mflag |= TIOCM_RI;
-
-			if (mstat & ch->dcd)
-				mflag |= TIOCM_CD;
-
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
-
-			if (error)
-				return error;
-
-			putUser(mflag, (unsigned int *) arg);
-
+			mflag = pc_tiocmget(tty, file);
+			if (putUser(mflag, (unsigned int *) arg))
+				return -EFAULT;
 			break;
 
-		case TIOCMBIS:
-		case TIOCMBIC:
 		case TIOCMODS:
-		case TIOCMSET:
-
-			getUser(mstat, (unsigned int *)arg);
-
-			mflag = 0;
-			if (mstat & TIOCM_DTR)
-				mflag |= ch->m_dtr;
-
-			if (mstat & TIOCM_RTS)
-				mflag |= ch->m_rts;
-
-			switch (cmd) 
-			{ /* Begin switch cmd */
-
-				case TIOCMODS:
-				case TIOCMSET:
-					ch->modemfake = ch->m_dtr|ch->m_rts;
-					ch->modem = mflag;
-					break;
-
-				case TIOCMBIS:
-					ch->modemfake |= mflag;
-					ch->modem |= mflag;
-					break;
-
-				case TIOCMBIC:
-					ch->modemfake |= mflag;
-					ch->modem &= ~mflag;
-					break;
-
-			} /* End switch cmd */
-
-			cli();
-			globalwinon(ch);
-
-			/*  --------------------------------------------------------------
-				The below routine generally sets up parity, baud, flow control 
-				issues, etc.... It effect both control flags and input flags.
-			------------------------------------------------------------------ */
-
-			epcaparam(tty,ch);
-			memoff(ch);
-			restore_flags(flags);
-			break;
+			if (getUser(mstat, (unsigned int *)arg))
+				return -EFAULT;
+			return pc_tiocmset(tty, file, mstat, ~mstat);
 
 		case TIOCSDTR:
 			ch->omodem |= ch->m_dtr;
--- diff/drivers/char/esp.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/esp.c	2004-02-18 09:03:58.000000000 +0000
@@ -1753,55 +1753,52 @@
 }
 
 
-static int get_modem_info(struct esp_struct * info, unsigned int *value)
+static int esp_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct esp_struct * info = (struct esp_struct *)tty->driver_data;
 	unsigned char control, status;
-	unsigned int result;
+
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
 	control = info->MCR;
 	cli();
 	serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
 	status = serial_in(info, UART_ESI_STAT2);
 	sti();
-	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+	return    ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
 		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
 		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
 		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result,value);
 }
 
-static int set_modem_info(struct esp_struct * info, unsigned int cmd,
-			  unsigned int *value)
+static int esp_tiocmset(struct tty_struct *tty, struct file *file,
+			unsigned int set, unsigned int clear)
 {
+	struct esp_struct * info = (struct esp_struct *)tty->driver_data;
 	unsigned int arg;
 
-	if (get_user(arg, value))
-		return -EFAULT;
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS)
-			info->MCR |= UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR |= UART_MCR_DTR;
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			info->MCR &= ~UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR &= ~UART_MCR_DTR;
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
-			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		break;
-	default:
-		return -EINVAL;
-	}
 	cli();
+
+	if (set & TIOCM_RTS)
+		info->MCR |= UART_MCR_RTS;
+	if (set & TIOCM_DTR)
+		info->MCR |= UART_MCR_DTR;
+
+	if (clear & TIOCM_RTS)
+		info->MCR &= ~UART_MCR_RTS;
+	if (clear & TIOCM_DTR)
+		info->MCR &= ~UART_MCR_DTR;
+
 	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 	serial_out(info, UART_ESI_CMD2, UART_MCR);
 	serial_out(info, UART_ESI_CMD2, info->MCR);
@@ -1853,12 +1850,6 @@
 	}
 	
 	switch (cmd) {
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
 			return get_serial_info(info,
 					       (struct serial_struct *) arg);
@@ -2444,6 +2435,8 @@
 	.hangup = esp_hangup,
 	.break_ctl = esp_break,
 	.wait_until_sent = rs_wait_until_sent,
+	.tiocmget = esp_tiocmget,
+	.tiocmset = esp_tiocmset,
 };
 
 /*
--- diff/drivers/char/genrtc.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/genrtc.c	2004-02-18 09:03:58.000000000 +0000
@@ -523,4 +523,4 @@
 
 MODULE_AUTHOR("Richard Zidlicky");
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS_MISCDEV(RTC_MINOR);
--- diff/drivers/char/hw_random.c	2003-09-30 15:46:13.000000000 +0100
+++ source/drivers/char/hw_random.c	2004-02-18 09:03:58.000000000 +0000
@@ -454,11 +454,7 @@
 
 static void via_cleanup(void)
 {
-	u32 lo, hi;
-
-	rdmsr(MSR_VIA_RNG, lo, hi);
-	lo &= ~VIA_RNG_ENABLE;
-	wrmsr(MSR_VIA_RNG, lo, hi);
+	/* do nothing */
 }
 
 
--- diff/drivers/char/ip2/ip2.h	2003-05-21 11:49:54.000000000 +0100
+++ source/drivers/char/ip2/ip2.h	2004-02-18 09:03:58.000000000 +0000
@@ -59,7 +59,7 @@
  * console warning.
  
  * When the driver is loaded as a module these setting can be overridden on the 
- * modprobe command line or on an option line in /etc/modules.conf.
+ * modprobe command line or on an option line in /etc/modprobe.conf.
  * If the driver is built-in the configuration must be 
  * set here for ISA cards and address set to 1 and 2 for PCI and EISA.
  *
@@ -80,7 +80,7 @@
 
  /* this structure is zeroed out because the suggested method is to configure
   * the driver as a module, set up the parameters with an options line in
-  * /etc/modules.conf and load with modprobe, kerneld or kmod, the kernel
+  * /etc/modprobe.conf and load with modprobe or kmod, the kernel
   * module loader
   */
 
--- diff/drivers/char/ip2main.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/ip2main.c	2004-02-18 09:03:58.000000000 +0000
@@ -186,6 +186,9 @@
 static void ip2_stop(PTTY);
 static void ip2_start(PTTY);
 static void ip2_hangup(PTTY);
+static int  ip2_tiocmget(struct tty_struct *tty, struct file *file);
+static int  ip2_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear);
 
 static void set_irq(int, int);
 static void ip2_interrupt_bh(i2eBordStrPtr pB);
@@ -466,6 +469,8 @@
 	.start           = ip2_start,
 	.hangup          = ip2_hangup,
 	.read_proc       = ip2_read_proc,
+	.tiocmget	 = ip2_tiocmget,
+	.tiocmset	 = ip2_tiocmset,
 };
 
 /******************************************************************************/
@@ -1951,6 +1956,80 @@
 /* Device Ioctl Section                                                       */
 /******************************************************************************/
 
+static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	i2ChanStrPtr pCh = DevTable[tty->index];
+	wait_queue_t wait;
+
+	if (pCh == NULL)
+		return -ENODEV;
+
+/*
+	FIXME - the following code is causing a NULL pointer dereference in
+	2.3.51 in an interrupt handler.  It's suppose to prompt the board
+	to return the DSS signal status immediately.  Why doesn't it do
+	the same thing in 2.2.14?
+*/
+
+/*	This thing is still busted in the 1.2.12 driver on 2.4.x
+	and even hoses the serial console so the oops can be trapped.
+		/\/\|=mhw=|\/\/			*/
+
+#ifdef	ENABLE_DSSNOW
+	i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
+
+	init_waitqueue_entry(&wait, current);
+	add_wait_queue(&pCh->dss_now_wait, &wait);
+	set_current_state( TASK_INTERRUPTIBLE );
+
+	serviceOutgoingFifo( pCh->pMyBord );
+
+	schedule();
+
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue(&pCh->dss_now_wait, &wait);
+
+	if (signal_pending(current)) {
+		return -EINTR;
+	}
+#endif
+	return  ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
+	      | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
+	      | ((pCh->dataSetIn  & I2_DCD) ? TIOCM_CAR : 0)
+	      | ((pCh->dataSetIn  & I2_RI)  ? TIOCM_RNG : 0)
+	      | ((pCh->dataSetIn  & I2_DSR) ? TIOCM_DSR : 0)
+	      | ((pCh->dataSetIn  & I2_CTS) ? TIOCM_CTS : 0);
+}
+
+static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
+			unsigned int set, unsigned int clear)
+{
+	i2ChanStrPtr pCh = DevTable[tty->index];
+
+	if (pCh == NULL)
+		return -ENODEV;
+
+	if (set & TIOCM_RTS) {
+		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
+		pCh->dataSetOut |= I2_RTS;
+	}
+	if (set & TIOCM_DTR) {
+		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
+		pCh->dataSetOut |= I2_DTR;
+	}
+
+	if (clear & TIOCM_RTS) {
+		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
+		pCh->dataSetOut &= ~I2_RTS;
+	}
+	if (clear & TIOCM_DTR) {
+		i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
+		pCh->dataSetOut &= ~I2_DTR;
+	}
+	serviceOutgoingFifo( pCh->pMyBord );
+	return 0;
+}
+
 /******************************************************************************/
 /* Function:   ip2_ioctl()                                                    */
 /* Parameters: Pointer to tty structure                                       */
@@ -2078,57 +2157,6 @@
 		
 		break;
 
-	case TIOCMGET:
-
-		ip2trace (CHANN, ITRC_IOCTL, 8, 1, rc );
-
-/*
-	FIXME - the following code is causing a NULL pointer dereference in
-	2.3.51 in an interrupt handler.  It's suppose to prompt the board
-	to return the DSS signal status immediately.  Why doesn't it do
-	the same thing in 2.2.14?
-*/
-
-/*	This thing is still busted in the 1.2.12 driver on 2.4.x
-	and even hoses the serial console so the oops can be trapped.
-		/\/\|=mhw=|\/\/			*/
-
-#ifdef	ENABLE_DSSNOW
-		i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
-
-		init_waitqueue_entry(&wait, current);
-		add_wait_queue(&pCh->dss_now_wait, &wait);
-		set_current_state( TASK_INTERRUPTIBLE );
-
-		serviceOutgoingFifo( pCh->pMyBord );
-
-		schedule();
-
-		set_current_state( TASK_RUNNING );
-		remove_wait_queue(&pCh->dss_now_wait, &wait);
-
-		if (signal_pending(current)) {
-			return -EINTR;
-		}
-#endif
-		rc = put_user(
-				    ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
-				  | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
-				  | ((pCh->dataSetIn  & I2_DCD) ? TIOCM_CAR : 0)
-				  | ((pCh->dataSetIn  & I2_RI)  ? TIOCM_RNG : 0)
-				  | ((pCh->dataSetIn  & I2_DSR) ? TIOCM_DSR : 0)
-				  | ((pCh->dataSetIn  & I2_CTS) ? TIOCM_CTS : 0),
-				(unsigned int *) arg);
-		break;
-
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		ip2trace (CHANN, ITRC_IOCTL, 9, 0 );
-
-		rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
-		break;
-
 	/*
 	 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
 	 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
@@ -2239,70 +2267,6 @@
 }
 
 /******************************************************************************/
-/* Function:   set_modem_info()                                               */
-/* Parameters: Pointer to channel structure                                   */
-/*             Specific ioctl command                                         */
-/*             Pointer to source for new settings                             */
-/* Returns:    Nothing                                                        */
-/*                                                                            */
-/* Description:                                                               */
-/* This returns the current settings of the dataset signal inputs to the user */
-/* program.                                                                   */
-/******************************************************************************/
-static int
-set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value)
-{
-	int rc;
-	unsigned int arg;
-
-	rc = get_user(arg,value);
-	if (rc)
-		return rc;
-	switch(cmd) {
-	case TIOCMBIS:
-		if (arg & TIOCM_RTS) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
-			pCh->dataSetOut |= I2_RTS;
-		}
-		if (arg & TIOCM_DTR) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
-			pCh->dataSetOut |= I2_DTR;
-		}
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
-			pCh->dataSetOut &= ~I2_RTS;
-		}
-		if (arg & TIOCM_DTR) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
-			pCh->dataSetOut &= ~I2_DTR;
-		}
-		break;
-	case TIOCMSET:
-		if ( (arg & TIOCM_RTS) && !(pCh->dataSetOut & I2_RTS) ) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
-			pCh->dataSetOut |= I2_RTS;
-		} else if ( !(arg & TIOCM_RTS) && (pCh->dataSetOut & I2_RTS) ) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
-			pCh->dataSetOut &= ~I2_RTS;
-		}
-		if ( (arg & TIOCM_DTR) && !(pCh->dataSetOut & I2_DTR) ) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
-			pCh->dataSetOut |= I2_DTR;
-		} else if ( !(arg & TIOCM_DTR) && (pCh->dataSetOut & I2_DTR) ) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
-			pCh->dataSetOut &= ~I2_DTR;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-	serviceOutgoingFifo( pCh->pMyBord );
-	return 0;
-}
-
-/******************************************************************************/
 /* Function:   GetSerialInfo()                                                */
 /* Parameters: Pointer to channel structure                                   */
 /*             Pointer to old termios structure                               */
@@ -2964,7 +2928,7 @@
 			rc = put_user(ip2_throttle, pIndex++ );
 			rc = put_user(ip2_unthrottle, pIndex++ );
 			rc = put_user(ip2_ioctl, pIndex++ );
-			rc = put_user(set_modem_info, pIndex++ );
+			rc = put_user(0, pIndex++ );
 			rc = put_user(get_serial_info, pIndex++ );
 			rc = put_user(set_serial_info, pIndex++ );
 			rc = put_user(ip2_set_termios, pIndex++ );
--- diff/drivers/char/isicom.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/isicom.c	2004-02-18 09:03:58.000000000 +0000
@@ -29,7 +29,7 @@
  *	You can find the original tools for this direct from Multitech
  *		ftp://ftp.multitech.com/ISI-Cards/
  *
- *	Having installed the cards the module options (/etc/modules.conf)
+ *	Having installed the cards the module options (/etc/modprobe.conf)
  *
  *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
  *
@@ -1291,63 +1291,44 @@
 out:	restore_flags(flags);
 }
 
-static int isicom_get_modem_info(struct isi_port * port, unsigned int * value)
+static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct isi_port * port = (struct isi_port *) tty->driver_data;
 	/* just send the port status */
-	unsigned int info;
 	unsigned short status = port->status;
+
+	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
+		return -ENODEV;
 	
-	info =  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
+	return  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
 		((status & ISI_DTR) ? TIOCM_DTR : 0) |
 		((status & ISI_DCD) ? TIOCM_CAR : 0) |
 		((status & ISI_DSR) ? TIOCM_DSR : 0) |
 		((status & ISI_CTS) ? TIOCM_CTS : 0) |
 		((status & ISI_RI ) ? TIOCM_RI  : 0);
-	return put_user(info, (unsigned int *) value);
 }
 
-static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd,
-					unsigned int * value)
+static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
+			   unsigned int set, unsigned int clear)
 {
+	struct isi_port * port = (struct isi_port *) tty->driver_data;
 	unsigned int arg;
 	unsigned long flags;
 	
-	if(get_user(arg, value))
-		return -EFAULT;
+	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
+		return -ENODEV;
 	
 	save_flags(flags); cli();
-	
-	switch(cmd) {
-		case TIOCMBIS:
-			if (arg & TIOCM_RTS) 
-				raise_rts(port);
-			if (arg & TIOCM_DTR) 
-				raise_dtr(port);
-			break;
-		
-		case TIOCMBIC:
-			if (arg & TIOCM_RTS)
-				drop_rts(port);
-			if (arg & TIOCM_DTR)
-				drop_dtr(port);	
-			break;
-			
-		case TIOCMSET:
-			if (arg & TIOCM_RTS)
-				raise_rts(port);
-			else
-				drop_rts(port);
-			
-			if (arg & TIOCM_DTR)
-				raise_dtr(port);
-			else
-				drop_dtr(port);
-			break;
-		
-		default:
-			restore_flags(flags);
-			return -EINVAL;		 	
-	}
+	if (set & TIOCM_RTS)
+		raise_rts(port);
+	if (set & TIOCM_DTR)
+		raise_dtr(port);
+
+	if (clear & TIOCM_RTS)
+		drop_rts(port);
+	if (clear & TIOCM_DTR)
+		drop_dtr(port);
+
 	restore_flags(flags);
 	return 0;
 }			
@@ -1445,15 +1426,6 @@
 				(arg ? CLOCAL : 0));
 			return 0;	
 			
-		case TIOCMGET:
-			return isicom_get_modem_info(port, (unsigned int*) arg);
-			
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET: 	
-			return isicom_set_modem_info(port, cmd, 
-					(unsigned int *) arg);
-		
 		case TIOCGSERIAL:
 			return isicom_get_serial_info(port, 
 					(struct serial_struct *) arg);
@@ -1640,6 +1612,8 @@
 	.start	= isicom_start,
 	.hangup	= isicom_hangup,
 	.flush_buffer	= isicom_flush_buffer,
+	.tiocmget	= isicom_tiocmget,
+	.tiocmset	= isicom_tiocmset,
 };
 
 static int register_drivers(void)
--- diff/drivers/char/istallion.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/istallion.c	2004-02-18 09:03:58.000000000 +0000
@@ -1991,6 +1991,61 @@
 
 /*****************************************************************************/
 
+static int stli_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	stliport_t *portp = tty->driver_data;
+	stlibrd_t *brdp;
+	int rc;
+
+	if (portp == (stliport_t *) NULL)
+		return(-ENODEV);
+	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+		return(0);
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return(-EIO);
+
+	if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
+			       &portp->asig, sizeof(asysigs_t), 1)) < 0)
+		return(rc);
+
+	return stli_mktiocm(portp->asig.sigvalue);
+}
+
+static int stli_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear)
+{
+	stliport_t *portp = tty->driver_data;
+	stlibrd_t *brdp;
+	int rts = -1, dtr = -1;
+
+	if (portp == (stliport_t *) NULL)
+		return(-ENODEV);
+	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+		return(0);
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return(-EIO);
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	stli_mkasysigs(&portp->asig, dtr, rts);
+
+	return stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
+			    sizeof(asysigs_t), 0);
+}
+
 static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	stliport_t	*portp;
@@ -2034,43 +2089,6 @@
 				(tty->termios->c_cflag & ~CLOCAL) |
 				(ival ? CLOCAL : 0);
 		break;
-	case TIOCMGET:
-		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
-		    sizeof(unsigned int))) == 0) {
-			if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
-			    &portp->asig, sizeof(asysigs_t), 1)) < 0)
-				return(rc);
-			lval = stli_mktiocm(portp->asig.sigvalue);
-			put_user(lval, (unsigned int *) arg);
-		}
-		break;
-	case TIOCMBIS:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			stli_mkasysigs(&portp->asig,
-				((ival & TIOCM_DTR) ? 1 : -1),
-				((ival & TIOCM_RTS) ? 1 : -1));
-			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
-				&portp->asig, sizeof(asysigs_t), 0);
-		}
-		break;
-	case TIOCMBIC:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			stli_mkasysigs(&portp->asig,
-				((ival & TIOCM_DTR) ? 0 : -1),
-				((ival & TIOCM_RTS) ? 0 : -1));
-			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
-				&portp->asig, sizeof(asysigs_t), 0);
-		}
-		break;
-	case TIOCMSET:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			stli_mkasysigs(&portp->asig,
-				((ival & TIOCM_DTR) ? 1 : 0),
-				((ival & TIOCM_RTS) ? 1 : 0));
-			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
-				&portp->asig, sizeof(asysigs_t), 0);
-		}
-		break;
 	case TIOCGSERIAL:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
 		    sizeof(struct serial_struct))) == 0)
@@ -5255,6 +5273,8 @@
 	.wait_until_sent = stli_waituntilsent,
 	.send_xchar = stli_sendxchar,
 	.read_proc = stli_readproc,
+	.tiocmget = stli_tiocmget,
+	.tiocmset = stli_tiocmset,
 };
 
 /*****************************************************************************/
--- diff/drivers/char/keyboard.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/keyboard.c	2004-02-18 09:03:58.000000000 +0000
@@ -1066,6 +1066,9 @@
 	}
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+#ifdef CONFIG_KGDB_SYSRQ
+                sysrq_down = 0;        /* in case we miss the "up" event */
+#endif
 		return;
 	}
 #endif
--- diff/drivers/char/mem.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/mem.c	2004-02-18 09:03:58.000000000 +0000
@@ -11,8 +11,6 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
-#include <linux/tpqic02.h>
-#include <linux/ftape.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mman.h>
@@ -41,6 +39,7 @@
 extern void tapechar_init(void);
 #endif
 
+#ifdef pgprot_noncached
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -66,19 +65,21 @@
 	  && addr >= __pa(high_memory);
 #elif defined(CONFIG_IA64)
 	/*
-	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
+	 * On ia64, we ignore O_SYNC because we cannot tolerate memory
+	 * attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
 #else
 	/*
-	 * Accessing memory above the top the kernel knows about or through a file pointer
-	 * that was marked O_SYNC will be done non-cached.
+	 * Accessing memory above the top the kernel knows about or through a
+	 * file pointer that was marked O_SYNC will be done non-cached.
 	 */
 	if (file->f_flags & O_SYNC)
 		return 1;
 	return addr >= __pa(high_memory);
 #endif
 }
+#endif		/* pgprot_noncached */
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
@@ -168,28 +169,24 @@
 	return do_write_mem(file, __va(p), p, buf, count, ppos);
 }
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int uncached;
 
-	uncached = uncached_access(file, offset);
 #ifdef pgprot_noncached
-	if (uncached)
+	if (uncached_access(file, offset))
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #endif
 
-	/* Don't try to swap out physical pages.. */
-	vma->vm_flags |= VM_RESERVED;
-
 	/*
-	 * Don't dump addresses that are not real memory to a core file.
+	 * Don't try to swap out physical pages..
+	 * And treat /dev/mem mappings as "IO" regions: they may not
+	 * describe valid pageframes.
 	 */
-	if (uncached)
-		vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED|VM_IO;
 
-	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
-			     vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, offset,
+			vma->vm_end-vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
--- diff/drivers/char/moxa.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/moxa.c	2004-02-18 09:03:58.000000000 +0000
@@ -232,6 +232,9 @@
 static void moxa_stop(struct tty_struct *);
 static void moxa_start(struct tty_struct *);
 static void moxa_hangup(struct tty_struct *);
+static int moxa_tiocmget(struct tty_struct *tty, struct file *file);
+static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear);
 static void moxa_poll(unsigned long);
 static void set_tty_param(struct tty_struct *);
 static int block_till_ready(struct tty_struct *, struct file *,
@@ -289,6 +292,8 @@
 	.stop = moxa_stop,
 	.start = moxa_start,
 	.hangup = moxa_hangup,
+	.tiocmget = moxa_tiocmget,
+	.tiocmset = moxa_tiocmset,
 };
 
 static int __init moxa_init(void)
@@ -742,6 +747,55 @@
 	ch->statusflags |= LOWWAIT;
 }
 
+static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+	int port;
+	int flag = 0, dtr, rts;
+
+	port = PORTNO(tty);
+	if ((port != MAX_PORTS) && (!ch))
+		return (-EINVAL);
+
+	MoxaPortGetLineOut(ch->port, &dtr, &rts);
+	if (dtr)
+		flag |= TIOCM_DTR;
+	if (rts)
+		flag |= TIOCM_RTS;
+	dtr = MoxaPortLineStatus(ch->port);
+	if (dtr & 1)
+		flag |= TIOCM_CTS;
+	if (dtr & 2)
+		flag |= TIOCM_DSR;
+	if (dtr & 4)
+		flag |= TIOCM_CD;
+	return flag;
+}
+
+static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear)
+{
+	struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+	int port;
+	int flag = 0, dtr, rts;
+
+	port = PORTNO(tty);
+	if ((port != MAX_PORTS) && (!ch))
+		return (-EINVAL);
+
+	MoxaPortGetLineOut(ch->port, &dtr, &rts);
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+	MoxaPortLineCtrl(ch->port, dtr, rts);
+	return 0;
+}
+
 static int moxa_ioctl(struct tty_struct *tty, struct file *file,
 		      unsigned int cmd, unsigned long arg)
 {
@@ -785,51 +839,6 @@
 		else
 			ch->asyncflags |= ASYNC_CHECK_CD;
 		return (0);
-	case TIOCMGET:
-		flag = 0;
-		MoxaPortGetLineOut(ch->port, &dtr, &rts);
-		if (dtr)
-			flag |= TIOCM_DTR;
-		if (rts)
-			flag |= TIOCM_RTS;
-		dtr = MoxaPortLineStatus(ch->port);
-		if (dtr & 1)
-			flag |= TIOCM_CTS;
-		if (dtr & 2)
-			flag |= TIOCM_DSR;
-		if (dtr & 4)
-			flag |= TIOCM_CD;
-		return put_user(flag, (unsigned int *) arg);
-	case TIOCMBIS:
-		if(get_user(retval, (unsigned int *) arg))
-			return -EFAULT;
-		MoxaPortGetLineOut(ch->port, &dtr, &rts);
-		if (retval & TIOCM_RTS)
-			rts = 1;
-		if (retval & TIOCM_DTR)
-			dtr = 1;
-		MoxaPortLineCtrl(ch->port, dtr, rts);
-		return (0);
-	case TIOCMBIC:
-		if(get_user(retval, (unsigned int *) arg))
-			return -EFAULT;
-		MoxaPortGetLineOut(ch->port, &dtr, &rts);
-		if (retval & TIOCM_RTS)
-			rts = 0;
-		if (retval & TIOCM_DTR)
-			dtr = 0;
-		MoxaPortLineCtrl(ch->port, dtr, rts);
-		return (0);
-	case TIOCMSET:
-		if(get_user(retval, (unsigned long *) arg))
-			return -EFAULT;
-		dtr = rts = 0;
-		if (retval & TIOCM_RTS)
-			rts = 1;
-		if (retval & TIOCM_DTR)
-			dtr = 1;
-		MoxaPortLineCtrl(ch->port, dtr, rts);
-		return (0);
 	case TIOCGSERIAL:
 		return (moxa_get_serial_info(ch, (struct serial_struct *) arg));
 
--- diff/drivers/char/mxser.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/mxser.c	2004-02-18 09:03:58.000000000 +0000
@@ -350,8 +350,8 @@
 static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
 static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
 static void mxser_send_break(struct mxser_struct *, int);
-static int mxser_get_modem_info(struct mxser_struct *, unsigned int *);
-static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);
+static int mxser_tiocmget(struct tty_struct *, struct file *);
+static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
 
 /*
  * The MOXA C168/C104 serial driver boot-time initialization code!
@@ -492,6 +492,8 @@
 	.stop = mxser_stop,
 	.start = mxser_start,
 	.hangup = mxser_hangup,
+	.tiocmget = mxser_tiocmget,
+	.tiocmset = mxser_tiocmset,
 };
 
 static int __init mxser_module_init(void)
@@ -1009,12 +1011,6 @@
 		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
 					 (arg ? CLOCAL : 0));
 		return (0);
-	case TIOCMGET:
-		return (mxser_get_modem_info(info, (unsigned int *) arg));
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return (mxser_set_modem_info(info, cmd, (unsigned int *) arg));
 	case TIOCGSERIAL:
 		return (mxser_get_serial_info(info, (struct serial_struct *) arg));
 	case TIOCSSERIAL:
@@ -2150,13 +2146,18 @@
 	restore_flags(flags);
 }
 
-static int mxser_get_modem_info(struct mxser_struct *info,
-				unsigned int *value)
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
 	unsigned char control, status;
 	unsigned int result;
 	unsigned long flags;
 
+	if (PORTNO(tty) == MXSER_PORTS)
+		return (-ENOIOCTLCMD);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return (-EIO);
+
 	control = info->MCR;
 	save_flags(flags);
 	cli();
@@ -2164,46 +2165,38 @@
 	if (status & UART_MSR_ANY_DELTA)
 		mxser_check_modem_status(info, status);
 	restore_flags(flags);
-	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
 	    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
 	    ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
 	    ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
 	    ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
 	    ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result, value);
 }
 
-static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd,
-				unsigned int *value)
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
+			  unsigned int set, unsigned int clear)
 {
+	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
 	unsigned int arg;
 	unsigned long flags;
 
-	if(get_user(arg, value))
-		return -EFAULT;
-	switch (cmd) {
-	case TIOCMBIS:
-		if (arg & TIOCM_RTS)
-			info->MCR |= UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR |= UART_MCR_DTR;
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			info->MCR &= ~UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR &= ~UART_MCR_DTR;
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) |
-			     ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) |
-			     ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		break;
-	default:
-		return (-EINVAL);
-	}
+	if (PORTNO(tty) == MXSER_PORTS)
+		return (-ENOIOCTLCMD);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return (-EIO);
+
 	save_flags(flags);
 	cli();
+	if (set & TIOCM_RTS)
+		info->MCR |= UART_MCR_RTS;
+	if (set & TIOCM_DTR)
+		info->MCR |= UART_MCR_DTR;
+
+	if (clear & TIOCM_RTS)
+		info->MCR &= ~UART_MCR_RTS;
+	if (clear & TIOCM_DTR)
+		info->MCR &= ~UART_MCR_DTR;
+
 	outb(info->MCR, info->base + UART_MCR);
 	restore_flags(flags);
 	return (0);
--- diff/drivers/char/pcxx.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/pcxx.c	2004-02-18 09:03:58.000000000 +0000
@@ -173,6 +173,9 @@
 static inline void memoff(struct channel *ch);
 static inline void assertgwinon(struct channel *ch);
 static inline void assertmemoff(struct channel *ch);
+static int pcxe_tiocmget(struct tty_struct *tty, struct file *file);
+static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear);
 
 #define TZ_BUFSZ 4096
 
@@ -1029,6 +1032,8 @@
 	.stop = pcxe_stop,
 	.start = pcxe_start,
 	.hangup = pcxe_hangup,
+	.tiocmget = pcxe_tiocmget,
+	.tiocmset = pcxe_tiocmset,
 };
 
 /*
@@ -1983,6 +1988,89 @@
 }
 
 
+static int pcxe_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct channel *ch = (struct channel *) tty->driver_data;
+	volatile struct board_chan *bc;
+	unsigned long flags;
+	int mflag = 0;
+
+	if(ch)
+		bc = ch->brdchan;
+	else {
+		printk("ch is NULL in %s!\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+
+	save_flags(flags);
+	cli();
+	globalwinon(ch);
+	mstat = bc->mstat;
+	memoff(ch);
+	restore_flags(flags);
+
+	if(mstat & DTR)
+		mflag |= TIOCM_DTR;
+	if(mstat & RTS)
+		mflag |= TIOCM_RTS;
+	if(mstat & CTS)
+		mflag |= TIOCM_CTS;
+	if(mstat & ch->dsr)
+		mflag |= TIOCM_DSR;
+	if(mstat & RI)
+		mflag |= TIOCM_RI;
+	if(mstat & ch->dcd)
+		mflag |= TIOCM_CD;
+
+	return mflag;
+}
+
+
+static int pcxe_tiocmset(struct tty_struct *tty, struct file *file,
+			 unsigned int set, unsigned int clear)
+{
+	struct channel *ch = (struct channel *) tty->driver_data;
+	volatile struct board_chan *bc;
+	unsigned long flags;
+
+	if(ch)
+		bc = ch->brdchan;
+	else {
+		printk("ch is NULL in %s!\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+
+	save_flags(flags);
+	cli();
+	/*
+	 * I think this modemfake stuff is broken.  It doesn't
+	 * correctly reflect the behaviour desired by the TIOCM*
+	 * ioctls.  Therefore this is probably broken.
+	 */
+	if (set & TIOCM_DTR) {
+		ch->modemfake |= DTR;
+		ch->modem |= DTR;
+	}
+	if (set & TIOCM_RTS) {
+		ch->modemfake |= RTS;
+		ch->modem |= RTS;
+	}
+
+	if (clear & TIOCM_DTR) {
+		ch->modemfake |= DTR;
+		ch->modem &= ~DTR;
+	}
+	if (clear & TIOCM_RTS) {
+		ch->modemfake |= RTS;
+		ch->modem &= ~RTS;
+	}
+	globalwinon(ch);
+	pcxxparam(tty,ch);
+	memoff(ch);
+	restore_flags(flags);
+}
+
+
 static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -2036,69 +2124,15 @@
 			return 0;
 
 		case TIOCMODG:
-		case TIOCMGET:
-			mflag = 0;
-
-			cli();
-			globalwinon(ch);
-			mstat = bc->mstat;
-			memoff(ch);
-			restore_flags(flags);
-
-			if(mstat & DTR)
-				mflag |= TIOCM_DTR;
-			if(mstat & RTS)
-				mflag |= TIOCM_RTS;
-			if(mstat & CTS)
-				mflag |= TIOCM_CTS;
-			if(mstat & ch->dsr)
-				mflag |= TIOCM_DSR;
-			if(mstat & RI)
-				mflag |= TIOCM_RI;
-			if(mstat & ch->dcd)
-				mflag |= TIOCM_CD;
-
+			mflag = pcxe_tiocmget(tty, file);
 			if (put_user(mflag, (unsigned int *) arg))
 				return -EFAULT;
 			break;
 
-		case TIOCMBIS:
-		case TIOCMBIC:
 		case TIOCMODS:
-		case TIOCMSET:
 			if (get_user(mstat, (unsigned int *) arg))
 				return -EFAULT;
-
-			mflag = 0;
-			if(mstat & TIOCM_DTR)
-				mflag |= DTR;
-			if(mstat & TIOCM_RTS)
-				mflag |= RTS;
-
-			switch(cmd) {
-				case TIOCMODS:
-				case TIOCMSET:
-					ch->modemfake = DTR|RTS;
-					ch->modem = mflag;
-					break;
-
-				case TIOCMBIS:
-					ch->modemfake |= mflag;
-					ch->modem |= mflag;
-					break;
-
-				case TIOCMBIC:
-					ch->modemfake &= ~mflag;
-					ch->modem &= ~mflag;
-					break;
-			}
-
-			cli();
-			globalwinon(ch);
-			pcxxparam(tty,ch);
-			memoff(ch);
-			restore_flags(flags);
-			break;
+			return pcxe_tiocmset(tty, file, mstat, ~mstat);
 
 		case TIOCSDTR:
 			cli();
--- diff/drivers/char/pty.c	2003-09-30 15:46:13.000000000 +0100
+++ source/drivers/char/pty.c	2004-02-18 09:03:58.000000000 +0000
@@ -25,16 +25,21 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <linux/devpts_fs.h>
 
+#if defined(CONFIG_LEGACY_PTYS) || defined(CONFIG_UNIX98_PTYS)
+
+#ifdef CONFIG_LEGACY_PTYS
 static struct tty_driver *pty_driver, *pty_slave_driver;
+#endif
 
-#ifdef CONFIG_UNIX98_PTYS
 /* These are global because they are accessed in tty_io.c */
+#ifdef CONFIG_UNIX98_PTYS
 struct tty_driver *ptm_driver;
 struct tty_driver *pts_driver;
 #endif
@@ -226,8 +231,9 @@
 	return 0;
 }
 
+#ifdef CONFIG_LEGACY_PTYS
 static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
-			unsigned int cmd, unsigned long arg)
+			 unsigned int cmd, unsigned long arg)
 {
 	if (!tty) {
 		printk("pty_ioctl called with NULL tty!\n");
@@ -239,6 +245,7 @@
 	}
 	return -ENOIOCTLCMD;
 }
+#endif
 
 #ifdef CONFIG_UNIX98_PTYS
 static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
@@ -249,11 +256,13 @@
 		return -EIO;
 	}
 	switch(cmd) {
+	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+		return pty_set_lock(tty, (int *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return pty_get_device_number(tty, (unsigned int *)arg);
 	}
 
-	return pty_bsd_ioctl(tty,file,cmd,arg);
+	return -ENOIOCTLCMD;
 }
 #endif
 
@@ -313,8 +322,41 @@
 	.set_termios = pty_set_termios,
 };
 
+/* sysctl support for setting limits on the number of Unix98 ptys allocated.
+   Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */
+#ifdef CONFIG_UNIX98_PTYS
+int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_limit_min = 0;
+static int pty_limit_max = NR_UNIX98_PTY_MAX;
+
+ctl_table pty_table[] = {
+	{
+		.ctl_name	= PTY_MAX,
+		.procname	= "max",
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.data		= &pty_limit,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &pty_limit_min,
+		.extra2		= &pty_limit_max,
+	}, {
+		.ctl_name	= PTY_NR,
+		.procname	= "nr",
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.proc_handler	= &proc_dointvec,
+	}, {
+		.ctl_name	= 0
+	}
+};
+#endif
+
+/* Initialization */
+
 static int __init pty_init(void)
 {
+#ifdef CONFIG_LEGACY_PTYS
 	/* Traditional BSD devices */
 
 	pty_driver = alloc_tty_driver(NR_PTYS);
@@ -363,15 +405,15 @@
 	if (tty_register_driver(pty_slave_driver))
 		panic("Couldn't register pty slave driver");
 
+#endif /* CONFIG_LEGACY_PTYS */
 
-	/* Unix98 devices */
 #ifdef CONFIG_UNIX98_PTYS
+	/* Unix98 devices */
 	devfs_mk_dir("pts");
-	printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
-	ptm_driver = alloc_tty_driver(UNIX98_NR_MAJORS * NR_PTYS);
+	ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
 	if (!ptm_driver)
 		panic("Couldn't allocate Unix98 ptm driver");
-	pts_driver = alloc_tty_driver(UNIX98_NR_MAJORS * NR_PTYS);
+	pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
 	if (!pts_driver)
 		panic("Couldn't allocate Unix98 pts driver");
 
@@ -388,7 +430,7 @@
 	ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
 	ptm_driver->init_termios.c_lflag = 0;
 	ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-				TTY_DRIVER_NO_DEVFS;
+		TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
 	ptm_driver->other = pts_driver;
 	tty_set_operations(ptm_driver, &pty_ops);
 	ptm_driver->ioctl = pty_unix98_ioctl;
@@ -402,8 +444,8 @@
 	pts_driver->subtype = PTY_TYPE_SLAVE;
 	pts_driver->init_termios = tty_std_termios;
 	pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-	pts_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
 	pts_driver->other = ptm_driver;
 	tty_set_operations(pts_driver, &pty_ops);
 	
@@ -411,7 +453,12 @@
 		panic("Couldn't register Unix98 ptm driver");
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
-#endif
+
+	pty_table[1].data = &ptm_driver->refcount;
+#endif /* CONFIG_UNIX98_PTYS */
+
 	return 0;
 }
 module_init(pty_init);
+
+#endif /* CONFIG_LEGACY_PTYS || CONFIG_UNIX98_PTYS */
--- diff/drivers/char/rio/rio_linux.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/rio/rio_linux.c	2004-02-18 09:03:58.000000000 +0000
@@ -728,6 +728,11 @@
       rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg);
     break;
 #if 0
+  /*
+   * note: these IOCTLs no longer reach here.  Use
+   * tiocmset/tiocmget driver methods instead.  The
+   * #if 0 disablement predates this comment.
+   */
   case TIOCMGET:
     if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
                           sizeof(unsigned int))) == 0) {
--- diff/drivers/char/riscom8.c	2003-09-17 12:28:05.000000000 +0100
+++ source/drivers/char/riscom8.c	2004-02-18 09:03:58.000000000 +0000
@@ -1306,13 +1306,17 @@
 		(tty->ldisc.write_wakeup)(tty);
 }
 
-static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
+static int rc_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
 	struct riscom_board * bp;
 	unsigned char status;
 	unsigned int result;
 	unsigned long flags;
 
+	if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
 	bp = port_Board(port);
 	save_flags(flags); cli();
 	rc_out(bp, CD180_CAR, port_No(port));
@@ -1324,41 +1328,32 @@
 		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)
 		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
 		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result, value);
+	return result;
 }
 
-static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
-			     unsigned int *value)
+static int rc_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
 {
-	unsigned int arg;
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
 	unsigned long flags;
-	struct riscom_board *bp = port_Board(port);
+	struct riscom_board *bp;
+
+	if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	bp = port_Board(port);
 
-	if (get_user(arg, value))
-		return -EFAULT;
-	switch (cmd) {
-	 case TIOCMBIS: 
-		if (arg & TIOCM_RTS) 
-			port->MSVR |= MSVR_RTS;
-		if (arg & TIOCM_DTR)
-			bp->DTR &= ~(1u << port_No(port));
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			port->MSVR &= ~MSVR_RTS;
-		if (arg & TIOCM_DTR)
-			bp->DTR |= (1u << port_No(port));
-		break;
-	case TIOCMSET:
-		port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : 
-					         (port->MSVR & ~MSVR_RTS);
-		bp->DTR = arg & TIOCM_DTR ? (bp->DTR &= ~(1u << port_No(port))) :
-					    (bp->DTR |=  (1u << port_No(port)));
-		break;
-	 default:
-		return -EINVAL;
-	}
 	save_flags(flags); cli();
+	if (set & TIOCM_RTS)
+		port->MSVR |= MSVR_RTS;
+	if (set & TIOCM_DTR)
+		bp->DTR &= ~(1u << port_No(port));
+
+	if (clear & TIOCM_RTS)
+		port->MSVR &= ~MSVR_RTS;
+	if (clear & TIOCM_DTR)
+		bp->DTR |= (1u << port_No(port));
+
 	rc_out(bp, CD180_CAR, port_No(port));
 	rc_out(bp, CD180_MSVR, port->MSVR);
 	rc_out(bp, RC_DTR, bp->DTR);
@@ -1485,12 +1480,6 @@
 			((tty->termios->c_cflag & ~CLOCAL) |
 			(arg ? CLOCAL : 0));
 		break;
-	 case TIOCMGET:
-		return rc_get_modem_info(port, (unsigned int *) arg);
-	 case TIOCMBIS:
-	 case TIOCMBIC:
-	 case TIOCMSET:
-		return rc_set_modem_info(port, cmd, (unsigned int *) arg);
 	 case TIOCGSERIAL:	
 		return rc_get_serial_info(port, (struct serial_struct *) arg);
 	 case TIOCSSERIAL:	
@@ -1677,6 +1666,8 @@
 	.stop = rc_stop,
 	.start = rc_start,
 	.hangup = rc_hangup,
+	.tiocmget = rc_tiocmget,
+	.tiocmset = rc_tiocmset,
 };
 
 static inline int rc_init_drivers(void)
--- diff/drivers/char/rocket.c	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/char/rocket.c	2004-02-18 09:03:58.000000000 +0000
@@ -1216,59 +1216,6 @@
 /********************************************************************************************/
 /*  Here are the routines used by rp_ioctl.  These are all called from exception handlers.  */
 
-static int get_modem_info(struct r_port *info, unsigned int *value)
-{
-	unsigned int control, result, ChanStatus;
-
-	ChanStatus = sGetChanStatusLo(&info->channel);
-
-	control = info->channel.TxControl[3];
-	result = ((control & SET_RTS) ? TIOCM_RTS : 0) | 
-		((control & SET_DTR) ?  TIOCM_DTR : 0) |
-		((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
-		(sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
-		((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
-		((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
-
-	if (copy_to_user(value, &result, sizeof (int)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_modem_info(struct r_port *info, unsigned int cmd,
-			  unsigned int *value)
-{
-	unsigned int arg;
-
-	if (copy_from_user(&arg, value, sizeof (int)))
-		return -EFAULT;
-
-	switch (cmd) {
-	case TIOCMBIS:
-		if (arg & TIOCM_RTS)
-			info->channel.TxControl[3] |= SET_RTS;
-		if (arg & TIOCM_DTR)
-			info->channel.TxControl[3] |= SET_DTR;
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			info->channel.TxControl[3] &= ~SET_RTS;
-		if (arg & TIOCM_DTR)
-			info->channel.TxControl[3] &= ~SET_DTR;
-		break;
-	case TIOCMSET:
-		info->channel.TxControl[3] = ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) | 
-					      ((arg & TIOCM_RTS) ? SET_RTS : 0) | 
-					      ((arg & TIOCM_DTR) ? SET_DTR : 0));
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0]));
-	return 0;
-}
-
 /*
  *  Returns the state of the serial modem control lines.  These next 2 functions 
  *  are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
@@ -1432,12 +1379,6 @@
 		return -ENXIO;
 
 	switch (cmd) {
-	case TIOCMGET:
-		return get_modem_info(info, (unsigned int *) arg);
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return set_modem_info(info, cmd, (unsigned int *) arg);
 	case RCKP_GET_STRUCT:
 		if (copy_to_user((void *) arg, info, sizeof (struct r_port)))
 			return -EFAULT;
--- diff/drivers/char/serial167.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/serial167.c	2004-02-18 09:03:58.000000000 +0000
@@ -1492,8 +1492,9 @@
 } /* set_serial_info */
 
 static int
-get_modem_info(struct cyclades_port * info, unsigned int *value)
+cy_tiocmget(struct tty_struct *tty, struct file *file)
 {
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   int channel;
   volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
   unsigned long flags;
@@ -1507,36 +1508,32 @@
         status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
     local_irq_restore(flags);
 
-    result =  ((status  & CyRTS) ? TIOCM_RTS : 0)
+    return    ((status  & CyRTS) ? TIOCM_RTS : 0)
             | ((status  & CyDTR) ? TIOCM_DTR : 0)
             | ((status  & CyDCD) ? TIOCM_CAR : 0)
             | ((status  & CyDSR) ? TIOCM_DSR : 0)
             | ((status  & CyCTS) ? TIOCM_CTS : 0);
-    return put_user(result,(unsigned int *) value);
-} /* get_modem_info */
+} /* cy_tiocmget */
 
 static int
-set_modem_info(struct cyclades_port * info, unsigned int cmd,
-                          unsigned int *value)
+cy_tiocmset(struct tty_struct *tty, struct file *file,
+	    unsigned int set, unsigned int clear)
 {
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   int channel;
   volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
   unsigned long flags;
   unsigned int arg;
 	  
-    if (get_user(arg, (unsigned long *) value))
-	return -EFAULT;
     channel = info->line;
 
-    switch (cmd) {
-    case TIOCMBIS:
-	if (arg & TIOCM_RTS){
+	if (set & TIOCM_RTS){
 	    local_irq_save(flags);
 		base_addr[CyCAR] = (u_char)channel;
 		base_addr[CyMSVR1] = CyRTS;
 	    local_irq_restore(flags);
 	}
-	if (arg & TIOCM_DTR){
+	if (set & TIOCM_DTR){
 	    local_irq_save(flags);
 	    base_addr[CyCAR] = (u_char)channel;
 /* CP('S');CP('2'); */
@@ -1547,15 +1544,14 @@
 #endif
 	    local_irq_restore(flags);
 	}
-	break;
-    case TIOCMBIC:
-	if (arg & TIOCM_RTS){
+
+	if (clear & TIOCM_RTS){
 	    local_irq_save(flags);
 		base_addr[CyCAR] = (u_char)channel;
 		base_addr[CyMSVR1] = 0;
 	    local_irq_restore(flags);
 	}
-	if (arg & TIOCM_DTR){
+	if (clear & TIOCM_DTR){
 	    local_irq_save(flags);
 	    base_addr[CyCAR] = (u_char)channel;
 /* CP('C');CP('2'); */
@@ -1566,44 +1562,7 @@
 #endif
 	    local_irq_restore(flags);
 	}
-	break;
-    case TIOCMSET:
-	if (arg & TIOCM_RTS){
-	    local_irq_save(flags);
-		base_addr[CyCAR] = (u_char)channel;
-		base_addr[CyMSVR1] = CyRTS;
-	    local_irq_restore(flags);
-	}else{
-	    local_irq_save(flags);
-		base_addr[CyCAR] = (u_char)channel;
-		base_addr[CyMSVR1] = 0;
-	    local_irq_restore(flags);
-	}
-	if (arg & TIOCM_DTR){
-	    local_irq_save(flags);
-	    base_addr[CyCAR] = (u_char)channel;
-/* CP('S');CP('3'); */
-	    base_addr[CyMSVR2] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
-#endif
-	    local_irq_restore(flags);
-	}else{
-	    local_irq_save(flags);
-	    base_addr[CyCAR] = (u_char)channel;
-/* CP('C');CP('3'); */
-	    base_addr[CyMSVR2] = 0;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
-#endif
-	    local_irq_restore(flags);
-	}
-	break;
-    default:
-		return -EINVAL;
-        }
+
     return 0;
 } /* set_modem_info */
 
@@ -1777,11 +1736,6 @@
             tty_wait_until_sent(tty,0);
             send_break(info, arg ? arg*(HZ/10) : HZ/4);
             break;
-        case TIOCMBIS:
-        case TIOCMBIC:
-        case TIOCMSET:
-            ret_val = set_modem_info(info, cmd, (unsigned int *) arg);
-            break;
 
 /* The following commands are incompletely implemented!!! */
         case TIOCGSOFTCAR:
@@ -1794,9 +1748,6 @@
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
             break;
-        case TIOCMGET:
-            ret_val = get_modem_info(info, (unsigned int *) arg);
-            break;
         case TIOCGSERIAL:
             ret_val = get_serial_info(info, (struct serial_struct *) arg);
             break;
@@ -2299,6 +2250,8 @@
 	.stop = cy_stop,
 	.start = cy_start,
 	.hangup = cy_hangup,
+	.tiocmget = cy_tiocmget,
+	.tiocmset = cy_tiocmset,
 };
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
--- diff/drivers/char/sh-sci.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/sh-sci.c	2004-02-18 09:03:58.000000000 +0000
@@ -1109,6 +1109,31 @@
         return;
 }
 
+static int sci_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct sci_port *port = tty->driver_data;
+	return sci_getsignals(port);
+}
+
+static int sci_tiocmset(struct tty_struct *tty, struct file *file,
+			unsigned int set, unsigned int clear)
+{
+	struct sci_port *port = tty->driver_data;
+	int rts = -1, dtr = -1;
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	sci_setsignals(port, dtr, rts);
+	return 0;
+}
+
 static int sci_ioctl(struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1139,26 +1164,6 @@
 			rc = gs_setserial(&port->gs,
 					  (struct serial_struct *) arg);
 		break;
-	case TIOCMGET:
-		ival = sci_getsignals(port);
-		rc = put_user(ival, (unsigned int __user *) arg);
-		break;
-	case TIOCMBIS:
-		if ((rc = get_user(ival, (unsigned int __user *) arg)) == 0)
-			sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
-			                     ((ival & TIOCM_RTS) ? 1 : -1));
-		break;
-	case TIOCMBIC:
-		if ((rc = get_user(ival, (unsigned int __user *) arg)) == 0)
-			sci_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
-			                     ((ival & TIOCM_RTS) ? 0 : -1));
-		break;
-	case TIOCMSET:
-		if ((rc = get_user(ival, (unsigned int __user *)arg)) == 0)
-			sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
-			                     ((ival & TIOCM_RTS) ? 1 : 0));
-		break;
-
 	default:
 		rc = -ENOIOCTLCMD;
 		break;
@@ -1272,6 +1277,8 @@
 #ifdef CONFIG_PROC_FS
 	.read_proc = sci_read_proc,
 #endif
+	.tiocmget = sci_tiocmget,
+	.tiocmset = sci_tiocmset,
 };
 
 /* ********************************************************************** *
--- diff/drivers/char/sn_serial.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/sn_serial.c	2004-02-18 09:03:58.000000000 +0000
@@ -259,7 +259,7 @@
 	va_list args;
 
 	va_start(args, fmt);
-	printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 	early_printk_sn_sal(printk_buf, printed_len);
 	va_end(args);
 	return printed_len;
--- diff/drivers/char/specialix.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/specialix.c	2004-02-18 09:03:58.000000000 +0000
@@ -1653,13 +1653,17 @@
 }
 
 
-static int sx_get_modem_info(struct specialix_port * port, unsigned int *value)
+static int sx_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	struct specialix_board * bp;
 	unsigned char status;
 	unsigned int result;
 	unsigned long flags;
 
+	if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
 	bp = port_Board(port);
 	save_flags(flags); cli();
 	sx_out(bp, CD186x_CAR, port_No(port));
@@ -1683,71 +1687,51 @@
 		          |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
 		          |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);
 	}
-	put_user(result,(unsigned int *) value);
-	return 0;
+
+	return result;
 }
 
 
-static int sx_set_modem_info(struct specialix_port * port, unsigned int cmd,
-                             unsigned int *value)
+static int sx_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
 {
+	struct specialix_port *port = (struct specialix_port *)tty->driver_data;
 	int error;
 	unsigned int arg;
 	unsigned long flags;
-	struct specialix_board *bp = port_Board(port);
+	struct specialix_board *bp;
 
-	error = verify_area(VERIFY_READ, value, sizeof(int));
-	if (error) 
-		return error;
+	if (sx_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	bp = port_Board(port);
 
-	get_user(arg, (unsigned long *) value);
-	switch (cmd) {
-	case TIOCMBIS: 
-	   /*	if (arg & TIOCM_RTS) 
-			port->MSVR |= MSVR_RTS; */
-	   /*   if (arg & TIOCM_DTR)
-			port->MSVR |= MSVR_DTR; */
-
-		if (SX_CRTSCTS(port->tty)) {
-			if (arg & TIOCM_RTS)
-				port->MSVR |= MSVR_DTR; 
-		} else {
-			if (arg & TIOCM_DTR)
-				port->MSVR |= MSVR_DTR; 
-		}	     
-		break;
-	case TIOCMBIC:
-	  /*	if (arg & TIOCM_RTS)
-			port->MSVR &= ~MSVR_RTS; */
-	  /*    if (arg & TIOCM_DTR)
-			port->MSVR &= ~MSVR_DTR; */
-		if (SX_CRTSCTS(port->tty)) {
-			if (arg & TIOCM_RTS)
-				port->MSVR &= ~MSVR_DTR;
-		} else {
-			if (arg & TIOCM_DTR)
-				port->MSVR &= ~MSVR_DTR;
-		}
-		break;
-	case TIOCMSET:
-	  /* port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : 
-						 (port->MSVR & ~MSVR_RTS); */
-	  /* port->MSVR = (arg & TIOCM_DTR) ? (port->MSVR | MSVR_DTR) : 
-						 (port->MSVR & ~MSVR_DTR); */
-		if (SX_CRTSCTS(port->tty)) {
-	  		port->MSVR = (arg & TIOCM_RTS) ? 
-			                         (port->MSVR |  MSVR_DTR) : 
-			                         (port->MSVR & ~MSVR_DTR);
-		} else {
-			port->MSVR = (arg & TIOCM_DTR) ?
-			                         (port->MSVR |  MSVR_DTR):
-			                         (port->MSVR & ~MSVR_DTR);
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
 	save_flags(flags); cli();
+   /*	if (set & TIOCM_RTS)
+		port->MSVR |= MSVR_RTS; */
+   /*   if (set & TIOCM_DTR)
+		port->MSVR |= MSVR_DTR; */
+
+	if (SX_CRTSCTS(port->tty)) {
+		if (set & TIOCM_RTS)
+			port->MSVR |= MSVR_DTR;
+	} else {
+		if (set & TIOCM_DTR)
+			port->MSVR |= MSVR_DTR;
+	}
+
+  /*	if (clear & TIOCM_RTS)
+		port->MSVR &= ~MSVR_RTS; */
+  /*    if (clear & TIOCM_DTR)
+		port->MSVR &= ~MSVR_DTR; */
+	if (SX_CRTSCTS(port->tty)) {
+		if (clear & TIOCM_RTS)
+			port->MSVR &= ~MSVR_DTR;
+	} else {
+		if (clear & TIOCM_DTR)
+			port->MSVR &= ~MSVR_DTR;
+	}
+
 	sx_out(bp, CD186x_CAR, port_No(port));
 	sx_out(bp, CD186x_MSVR, port->MSVR);
 	restore_flags(flags);
@@ -1897,16 +1881,6 @@
 			((tty->termios->c_cflag & ~CLOCAL) |
 			(arg ? CLOCAL : 0));
 		return 0;
-	 case TIOCMGET:
-		error = verify_area(VERIFY_WRITE, (void *) arg,
-		                    sizeof(unsigned int));
-		if (error)
-			return error;
-		return sx_get_modem_info(port, (unsigned int *) arg);
-	 case TIOCMBIS:
-	 case TIOCMBIC:
-	 case TIOCMSET:
-		return sx_set_modem_info(port, cmd, (unsigned int *) arg);
 	 case TIOCGSERIAL:	
 		return sx_get_serial_info(port, (struct serial_struct *) arg);
 	 case TIOCSSERIAL:	
@@ -2116,6 +2090,8 @@
 	.stop = sx_stop,
 	.start = sx_start,
 	.hangup = sx_hangup,
+	.tiocmget = sx_tiocmget,
+	.tiocmset = sx_tiocmset,
 };
 
 static int sx_init_drivers(void)
--- diff/drivers/char/stallion.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/char/stallion.c	2004-02-18 09:03:59.000000000 +0000
@@ -1514,6 +1514,48 @@
 
 /*****************************************************************************/
 
+static int stl_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	stlport_t	*portp;
+
+	if (tty == (struct tty_struct *) NULL)
+		return(-ENODEV);
+	portp = tty->driver_data;
+	if (portp == (stlport_t *) NULL)
+		return(-ENODEV);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return(-EIO);
+
+	return stl_getsignals(portp);
+}
+
+static int stl_tiocmset(struct tty_struct *tty, struct file *file,
+			unsigned int set, unsigned int clear)
+{
+	stlport_t	*portp;
+	int rts = -1, dtr = -1;
+
+	if (tty == (struct tty_struct *) NULL)
+		return(-ENODEV);
+	portp = tty->driver_data;
+	if (portp == (stlport_t *) NULL)
+		return(-ENODEV);
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return(-EIO);
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	stl_setsignals(portp, dtr, rts);
+	return 0;
+}
+
 static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	stlport_t	*portp;
@@ -1553,37 +1595,6 @@
 				(ival ? CLOCAL : 0);
 		}
 		break;
-	case TIOCMGET:
-		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
-		    sizeof(unsigned int))) == 0) {
-			ival = stl_getsignals(portp);
-			put_user(ival, (unsigned int *) arg);
-		}
-		break;
-	case TIOCMBIS:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg,
-		    sizeof(unsigned int))) == 0) {
-			get_user(ival, (unsigned int *) arg);
-			stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1),
-				((ival & TIOCM_RTS) ? 1 : -1));
-		}
-		break;
-	case TIOCMBIC:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg,
-		    sizeof(unsigned int))) == 0) {
-			get_user(ival, (unsigned int *) arg);
-			stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1),
-				((ival & TIOCM_RTS) ? 0 : -1));
-		}
-		break;
-	case TIOCMSET:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg,
-		    sizeof(unsigned int))) == 0) {
-			get_user(ival, (unsigned int *) arg);
-			stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0),
-				((ival & TIOCM_RTS) ? 1 : 0));
-		}
-		break;
 	case TIOCGSERIAL:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
 		    sizeof(struct serial_struct))) == 0)
@@ -3137,6 +3148,8 @@
 	.wait_until_sent = stl_waituntilsent,
 	.send_xchar = stl_sendxchar,
 	.read_proc = stl_readproc,
+	.tiocmget = stl_tiocmget,
+	.tiocmset = stl_tiocmset,
 };
 
 /*****************************************************************************/
--- diff/drivers/char/sx.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/char/sx.c	2004-02-18 09:03:59.000000000 +0000
@@ -1743,6 +1743,32 @@
 }
 
 
+static int sx_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct sx_port *port = tty->driver_data;
+	return sx_getsignals(port);
+}
+
+static int sx_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
+{
+	struct sx_port *port = tty->driver_data;
+	int rts = -1, dtr = -1;
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	sx_setsignals(port, dtr, rts);
+	sx_reconfigure_port(port);
+	return 0;
+}
+
 static int sx_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1775,34 +1801,6 @@
 		                      sizeof(struct serial_struct))) == 0)
 			rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
 		break;
-	case TIOCMGET:
-		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
-		                      sizeof(unsigned int))) == 0) {
-			ival = sx_getsignals(port);
-			put_user(ival, (unsigned int *) arg);
-		}
-		break;
-	case TIOCMBIS:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
-			                     ((ival & TIOCM_RTS) ? 1 : -1));
-			sx_reconfigure_port(port);
-		}
-		break;
-	case TIOCMBIC:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			sx_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
-			                     ((ival & TIOCM_RTS) ? 0 : -1));
-			sx_reconfigure_port(port);
-		}
-		break;
-	case TIOCMSET:
-		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
-			sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
-			                     ((ival & TIOCM_RTS) ? 1 : 0));
-			sx_reconfigure_port(port);
-		}
-		break;
 	default:
 		rc = -ENOIOCTLCMD;
 		break;
@@ -2217,6 +2215,8 @@
 	.stop = gs_stop,
 	.start = gs_start,
 	.hangup = gs_hangup,
+	.tiocmget = sx_tiocmget,
+	.tiocmset = sx_tiocmset,
 };
 
 static int sx_init_drivers(void)
--- diff/drivers/char/sysrq.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/sysrq.c	2004-02-18 09:03:59.000000000 +0000
@@ -35,6 +35,25 @@
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
+#ifdef CONFIG_KGDB_SYSRQ
+
+#define  GDB_OP &kgdb_op
+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
+	printk("kgdb sysrq\n");
+	breakpoint();
+}
+
+static struct sysrq_key_op kgdb_op = {
+	.handler	= kgdb_sysrq,
+	.help_msg	= "kGdb|Fgdb",
+	.action_msg	= "Debug breakpoint\n",
+};
+
+#else
+#define  GDB_OP NULL
+#endif
+
 
 extern void reset_vc(unsigned int);
 
@@ -238,8 +257,8 @@
 /* c */ NULL,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
-/* f */	NULL,
-/* g */	NULL,
+/* f */	GDB_OP,
+/* g */	GDB_OP,
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
 /* j */	NULL,
--- diff/drivers/char/tty_io.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/tty_io.c	2004-02-18 09:03:59.000000000 +0000
@@ -124,7 +124,7 @@
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
-extern struct tty_driver *pts_driver;	/* Unix98 pty slaves;  for /dev/ptmx */
+extern int pty_limit;		/* Config limit on Unix98 ptys */
 #endif
 
 extern void disable_early_printk(void);
@@ -799,7 +799,13 @@
 	down_tty_sem(idx);
 
 	/* check whether we're reopening an existing tty */
-	tty = driver->ttys[idx];
+	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
+		tty = devpts_get_tty(idx);
+		if (tty && driver->subtype == PTY_TYPE_MASTER)
+			tty = tty->link;
+	} else {
+		tty = driver->ttys[idx];
+	}
 	if (tty) goto fast_track;
 
 	/*
@@ -827,7 +833,14 @@
 	tty->index = idx;
 	tty_line_name(driver, idx, tty->name);
 
-	tp_loc = &driver->termios[idx];
+	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
+		tp_loc = &tty->termios;
+		ltp_loc = &tty->termios_locked;
+	} else {
+		tp_loc = &driver->termios[idx];
+		ltp_loc = &driver->termios_locked[idx];
+	}
+
 	if (!*tp_loc) {
 		tp = (struct termios *) kmalloc(sizeof(struct termios),
 						GFP_KERNEL);
@@ -836,7 +849,6 @@
 		*tp = driver->init_termios;
 	}
 
-	ltp_loc = &driver->termios_locked[idx];
 	if (!*ltp_loc) {
 		ltp = (struct termios *) kmalloc(sizeof(struct termios),
 						 GFP_KERNEL);
@@ -854,7 +866,14 @@
 		o_tty->index = idx;
 		tty_line_name(driver->other, idx, o_tty->name);
 
-		o_tp_loc  = &driver->other->termios[idx];
+		if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
+			o_tp_loc = &o_tty->termios;
+			o_ltp_loc = &o_tty->termios_locked;
+		} else {
+			o_tp_loc = &driver->other->termios[idx];
+			o_ltp_loc = &driver->other->termios_locked[idx];
+		}
+
 		if (!*o_tp_loc) {
 			o_tp = (struct termios *)
 				kmalloc(sizeof(struct termios), GFP_KERNEL);
@@ -863,7 +882,6 @@
 			*o_tp = driver->other->init_termios;
 		}
 
-		o_ltp_loc = &driver->other->termios_locked[idx];
 		if (!*o_ltp_loc) {
 			o_ltp = (struct termios *)
 				kmalloc(sizeof(struct termios), GFP_KERNEL);
@@ -875,7 +893,9 @@
 		/*
 		 * Everything allocated ... set up the o_tty structure.
 		 */
-		driver->other->ttys[idx] = o_tty;
+		if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) {
+			driver->other->ttys[idx] = o_tty;
+		}
 		if (!*o_tp_loc)
 			*o_tp_loc = o_tp;
 		if (!*o_ltp_loc)
@@ -896,7 +916,9 @@
 	 * Failures after this point use release_mem to clean up, so 
 	 * there's no need to null out the local pointers.
 	 */
-	driver->ttys[idx] = tty;
+	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+		driver->ttys[idx] = tty;
+	}
 	
 	if (!*tp_loc)
 		*tp_loc = tp;
@@ -994,12 +1016,20 @@
 {
 	struct tty_struct *o_tty;
 	struct termios *tp;
+	int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
 
 	if ((o_tty = tty->link) != NULL) {
-		o_tty->driver->ttys[idx] = NULL;
+		if (!devpts)
+			o_tty->driver->ttys[idx] = NULL;
 		if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-			tp = o_tty->driver->termios[idx];
-			o_tty->driver->termios[idx] = NULL;
+			tp = o_tty->termios;
+			if (!devpts)
+				o_tty->driver->termios[idx] = NULL;
+			kfree(tp);
+
+			tp = o_tty->termios_locked;
+			if (!devpts)
+				o_tty->driver->termios_locked[idx] = NULL;
 			kfree(tp);
 		}
 		o_tty->magic = 0;
@@ -1010,12 +1040,20 @@
 		free_tty_struct(o_tty);
 	}
 
-	tty->driver->ttys[idx] = NULL;
+	if (!devpts)
+		tty->driver->ttys[idx] = NULL;
 	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-		tp = tty->driver->termios[idx];
-		tty->driver->termios[idx] = NULL;
+		tp = tty->termios;
+		if (!devpts)
+			tty->driver->termios[idx] = NULL;
+		kfree(tp);
+
+		tp = tty->termios_locked;
+		if (!devpts)
+			tty->driver->termios_locked[idx] = NULL;
 		kfree(tp);
 	}
+
 	tty->magic = 0;
 	tty->driver->refcount--;
 	file_list_lock();
@@ -1059,22 +1097,24 @@
 				  "free (%s)\n", tty->name);
 		return;
 	}
-	if (tty != tty->driver->ttys[idx]) {
-		printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
-				  "for (%s)\n", idx, tty->name);
-		return;
-	}
-	if (tty->termios != tty->driver->termios[idx]) {
-		printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
-		       "for (%s)\n",
-		       idx, tty->name);
-		return;
-	}
-	if (tty->termios_locked != tty->driver->termios_locked[idx]) {
-		printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
-		       "termios_locked for (%s)\n",
-		       idx, tty->name);
-		return;
+	if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+		if (tty != tty->driver->ttys[idx]) {
+			printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+			       "for (%s)\n", idx, tty->name);
+			return;
+		}
+		if (tty->termios != tty->driver->termios[idx]) {
+			printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+			       "for (%s)\n",
+			       idx, tty->name);
+			return;
+		}
+		if (tty->termios_locked != tty->driver->termios_locked[idx]) {
+			printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
+			       "termios_locked for (%s)\n",
+			       idx, tty->name);
+			return;
+		}
 	}
 #endif
 
@@ -1084,7 +1124,8 @@
 #endif
 
 #ifdef TTY_PARANOIA_CHECK
-	if (tty->driver->other) {
+	if (tty->driver->other &&
+	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
 		if (o_tty != tty->driver->other->ttys[idx]) {
 			printk(KERN_DEBUG "release_dev: other->table[%d] "
 					  "not o_tty for (%s)\n",
@@ -1328,23 +1369,29 @@
 		return -ENODEV;
 	}
 
-	if (device == MKDEV(TTYAUX_MAJOR,2)) {
 #ifdef CONFIG_UNIX98_PTYS
+	if (device == MKDEV(TTYAUX_MAJOR,2)) {
 		/* find a device that is not in use. */
+		static int next_ptmx_dev = 0;
 		retval = -1;
 		driver = ptm_driver;
-		for (index = 0; index < driver->num ; index++)
+		while (driver->refcount < pty_limit) {
+			index = next_ptmx_dev;
+			next_ptmx_dev = (next_ptmx_dev+1) % driver->num;
 			if (!init_dev(driver, index, &tty))
 				goto ptmx_found; /* ok! */
+		}
 		return -EIO; /* no free ptys */
 	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-		devpts_pty_new(index, MKDEV(pts_driver->major, pts_driver->minor_start) + index);
+		if (devpts_pty_new(tty->link)) {
+			/* BADNESS - need to destroy both ptm and pts! */
+			return -ENOMEM;
+		}
 		noctty = 1;
-#else
-		return -ENODEV;
-#endif  /* CONFIG_UNIX_98_PTYS */
-	} else {
+	} else
+#endif
+	{
 		driver = get_tty_driver(device, &index);
 		if (!driver)
 			return -ENODEV;
@@ -2190,15 +2237,17 @@
         int i;
 	dev_t dev;
 	char *s;
-	void **p;
+	void **p = NULL;
 
 	if (driver->flags & TTY_DRIVER_INSTALLED)
 		return 0;
 
-	p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
-	if (!p)
-		return -ENOMEM;
-	memset(p, 0, driver->num * 3 * sizeof(void *));
+	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+		p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+		if (!p)
+			return -ENOMEM;
+		memset(p, 0, driver->num * 3 * sizeof(void *));
+	}
 
 	if (!driver->major) {
 		error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
@@ -2217,9 +2266,15 @@
 		return error;
 	}
 
-	driver->ttys = (struct tty_struct **)p;
-	driver->termios = (struct termios **)(p + driver->num);
-	driver->termios_locked = (struct termios **)(p + driver->num * 2);
+	if (p) {
+		driver->ttys = (struct tty_struct **)p;
+		driver->termios = (struct termios **)(p + driver->num);
+		driver->termios_locked = (struct termios **)(p + driver->num * 2);
+	} else {
+		driver->ttys = NULL;
+		driver->termios = NULL;
+		driver->termios_locked = NULL;
+	}
 
 	driver->cdev.kobj.parent = &tty_kobj;
 	strcpy(driver->cdev.kobj.name, driver->name);
@@ -2388,7 +2443,7 @@
 	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
 	class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 #endif
-	
+
 #ifdef CONFIG_VT
 	strcpy(vc0_cdev.kobj.name, "dev.vc0");
 	cdev_init(&vc0_cdev, &console_fops);
--- diff/drivers/char/viocons.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/char/viocons.c	2004-02-18 09:03:59.000000000 +0000
@@ -149,7 +149,7 @@
 
 	spin_lock_irqsave(&consoleloglock, flags);
 	va_start(args, fmt);
-	i = vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+	i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
 	va_end(args);
 	buf[i++] = '\r';
 	HvCall_writeLogBuffer(buf, i);
--- diff/drivers/char/vt.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/vt.c	2004-02-18 09:03:59.000000000 +0000
@@ -1883,14 +1883,24 @@
 	int c, tc, ok, n = 0, draw_x = -1;
 	unsigned int currcons;
 	unsigned long draw_from = 0, draw_to = 0;
-	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+	struct vt_struct *vt;
 	u16 himask, charmask;
 	const unsigned char *orig_buf = NULL;
 	int orig_count;
 
 	if (in_interrupt())
 		return count;
-		
+
+	might_sleep();
+
+	acquire_console_sem();
+	vt = (struct vt_struct *)tty->driver_data;
+	if (vt == NULL) {
+		printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
+		release_console_sem();
+		return 0;
+	}
+
 	currcons = vt->vc_num;
 	if (!vc_cons_allocated(currcons)) {
 	    /* could this happen? */
@@ -1899,13 +1909,16 @@
 		error = 1;
 		printk("con_write: tty %d not allocated\n", currcons+1);
 	    }
+	    release_console_sem();
 	    return 0;
 	}
+	release_console_sem();
 
 	orig_buf = buf;
 	orig_count = count;
 
 	if (from_user) {
+
 		down(&con_buf_sem);
 
 again:
@@ -1929,6 +1942,13 @@
 
 	acquire_console_sem();
 
+	vt = (struct vt_struct *)tty->driver_data;
+	if (vt == NULL) {
+		printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
+		release_console_sem();
+		goto out;
+	}
+
 	himask = hi_font_mask;
 	charmask = himask ? 0x1ff : 0xff;
 
@@ -2442,14 +2462,16 @@
 
 	acquire_console_sem();
 	i = vc_allocate(currcons);
-	release_console_sem();
-	if (i)
+	if (i) {
+		release_console_sem();
 		return i;
-
+	}
 	vt_cons[currcons]->vc_num = currcons;
 	tty->driver_data = vt_cons[currcons];
 	vc_cons[currcons].d->vc_tty = tty;
 
+	release_console_sem();
+
 	if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 		tty->winsize.ws_row = video_num_lines;
 		tty->winsize.ws_col = video_num_columns;
@@ -2467,10 +2489,12 @@
 		return;
 
 	vcs_remove_devfs(tty);
+	acquire_console_sem();
 	vt = (struct vt_struct*)tty->driver_data;
 	if (vt)
 		vc_cons[vt->vc_num].d->vc_tty = NULL;
 	tty->driver_data = 0;
+	release_console_sem();
 }
 
 static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
--- diff/drivers/char/vt_ioctl.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/char/vt_ioctl.c	2004-02-18 09:03:59.000000000 +0000
@@ -60,7 +60,7 @@
 unsigned char keyboard_type = KB_101;
 
 #ifdef CONFIG_X86
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+#include <linux/syscalls.h>
 #endif
 
 /*
--- diff/drivers/cpufreq/cpufreq.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/cpufreq/cpufreq.c	2004-02-18 09:03:59.000000000 +0000
@@ -198,7 +198,7 @@
 	else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
 		return sprintf(buf, "performance\n");
 	else if (policy->governor)
-		return snprintf(buf, CPUFREQ_NAME_LEN, "%s\n", policy->governor->name);
+		return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", policy->governor->name);
 	return -EINVAL;
 }
 
@@ -234,7 +234,7 @@
  */
 static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
 {
-	return snprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
+	return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
 }
 
 /**
@@ -254,7 +254,7 @@
 	list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
 		if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2)))
 			goto out;
-		i += snprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name);
+		i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name);
 	}
  out:
 	i += sprintf(&buf[i], "\n");
--- diff/drivers/cpufreq/proc_intf.c	2003-09-17 12:28:05.000000000 +0100
+++ source/drivers/cpufreq/proc_intf.c	2004-02-18 09:03:59.000000000 +0000
@@ -139,7 +139,7 @@
 				break;
 			} 
 		} else
-			p += snprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
+			p += scnprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
 	}
 end:
 	len = (p - page);
--- diff/drivers/i2c/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -15,9 +15,6 @@
 
 	  Both I2C and SMBus are supported here. You will need this for
 	  hardware sensors support, and also for Video For Linux support.
-	  Specifically, if you want to use a BT848 based frame grabber/overlay
-	  boards under Linux, say Y here and also to "I2C bit-banging
-	  interfaces", below.
 
 	  If you want I2C support, you should say Y here and also to the
 	  specific driver for your bus adapter(s) below.
--- diff/drivers/i2c/busses/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/busses/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -144,6 +144,17 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-ite.
 
+config I2C_IXP42X
+	tristate "IXP42x GPIO-Based I2C Interface"
+	depends on I2C && ARCH_IXP425
+	select I2C_ALGOBIT
+	help
+	  Say Y here if you have an Intel IXP42x(420,421,422,425) based 
+	  system and are using GPIO lines for an I2C bus.
+
+	  This support is also available as a module. If so, the module
+	  will be called i2c-ixp42x.
+
 config I2C_KEYWEST
 	tristate "Powermac Keywest I2C interface"
 	depends on I2C && PPC_PMAC
--- diff/drivers/i2c/busses/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/busses/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -15,6 +15,7 @@
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_ISA)		+= i2c-isa.o
 obj-$(CONFIG_I2C_ITE)		+= i2c-ite.o
+obj-$(CONFIG_I2C_IXP42X)	+= i2c-ixp42x.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
 obj-$(CONFIG_I2C_PHILIPSPAR)	+= i2c-philips-par.o
--- diff/drivers/i2c/busses/i2c-voodoo3.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/i2c/busses/i2c-voodoo3.c	2004-02-18 09:03:59.000000000 +0000
@@ -171,6 +171,7 @@
 
 static struct i2c_adapter voodoo3_i2c_adapter = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_ADAP_CLASS_TV_ANALOG, 
 	.name		= "I2C Voodoo3/Banshee adapter",
 	.algo_data	= &voo_i2c_bit_data,
 };
@@ -187,6 +188,7 @@
 
 static struct i2c_adapter voodoo3_ddc_adapter = {
 	.owner		= THIS_MODULE,
+	.class		= I2C_ADAP_CLASS_DDC, 
 	.name		= "DDC Voodoo3/Banshee adapter",
 	.algo_data	= &voo_ddc_bit_data,
 };
--- diff/drivers/i2c/chips/Kconfig	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -102,6 +102,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm78.
 
+config SENSORS_LM80
+	tristate "National Semiconductor LM80"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for National Semiconductor
+	  LM80 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm80.
+
 config SENSORS_LM83
 	tristate "National Semiconductor LM83"
 	depends on I2C && EXPERIMENTAL
--- diff/drivers/i2c/chips/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -13,6 +13,7 @@
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_LM75)	+= lm75.o
 obj-$(CONFIG_SENSORS_LM78)	+= lm78.o
+obj-$(CONFIG_SENSORS_LM80)	+= lm80.o
 obj-$(CONFIG_SENSORS_LM83)	+= lm83.o
 obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
--- diff/drivers/i2c/chips/fscher.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/fscher.c	2004-02-18 09:03:59.000000000 +0000
@@ -26,6 +26,11 @@
  *  and Philip Edelbrock <phil@netroedge.com>
  */
 
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_CHIP
+#define DEBUG	1
+#endif
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
--- diff/drivers/i2c/chips/w83l785ts.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/i2c/chips/w83l785ts.c	2004-02-18 09:03:59.000000000 +0000
@@ -12,6 +12,9 @@
  * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
  * <khali@linux-fr.org>.
  *
+ * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
+ * error handling mechanism.
+ *
  * 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
--- diff/drivers/ide/ide-tape.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ide/ide-tape.c	2004-02-18 09:03:59.000000000 +0000
@@ -451,18 +451,6 @@
 #include <asm/bitops.h>
 
 /*
- *	OnStream support
- */
-#define ONSTREAM_DEBUG		(0)
-#define OS_CONFIG_PARTITION	(0xff)
-#define OS_DATA_PARTITION	(0)
-#define OS_PARTITION_VERSION	(1)
-#define OS_EW			300
-#define OS_ADR_MINREV		2
-
-#define OS_DATA_STARTFRAME1	20
-#define OS_DATA_ENDFRAME1	2980
-/*
  * partition
  */
 typedef struct os_partition_s {
@@ -498,87 +486,6 @@
 	os_dat_entry_t	dat_list[16];
 } os_dat_t;
 
-/*
- * Frame types
- */
-#define OS_FRAME_TYPE_FILL	(0)
-#define OS_FRAME_TYPE_EOD	(1 << 0)
-#define OS_FRAME_TYPE_MARKER	(1 << 1)
-#define OS_FRAME_TYPE_HEADER	(1 << 3)
-#define OS_FRAME_TYPE_DATA	(1 << 7)
-
-/*
- * AUX
- */
-typedef struct os_aux_s {
-	__u32		format_id;		/* hardware compatibility AUX is based on */
-	char		application_sig[4];	/* driver used to write this media */
-	__u32		hdwr;			/* reserved */
-	__u32		update_frame_cntr;	/* for configuration frame */
-	__u8		frame_type;
-	__u8		frame_type_reserved;
-	__u8		reserved_18_19[2];
-	os_partition_t	partition;
-	__u8		reserved_36_43[8];
-	__u32		frame_seq_num;
-	__u32		logical_blk_num_high;
-	__u32		logical_blk_num;
-	os_dat_t	dat;
-	__u8		reserved188_191[4];
-	__u32		filemark_cnt;
-	__u32		phys_fm;
-	__u32		last_mark_addr;
-	__u8		reserved204_223[20];
-
-	/*
-	 * __u8		app_specific[32];
-	 *
-	 * Linux specific fields:
-	 */
-	 __u32		next_mark_addr;		/* when known, points to next marker */
-	 __u8		linux_specific[28];
-
-	__u8		reserved_256_511[256];
-} os_aux_t;
-
-typedef struct os_header_s {
-	char		ident_str[8];
-	__u8		major_rev;
-	__u8		minor_rev;
-	__u8		reserved10_15[6];
-	__u8		par_num;
-	__u8		reserved1_3[3];
-	os_partition_t	partition;
-} os_header_t;
-
-/*
- *	OnStream Tape Parameters Page
- */
-typedef struct {
-	unsigned	page_code	:6;	/* Page code - Should be 0x2b */
-	unsigned	reserved1_6	:1;
-	unsigned	ps		:1;
-	__u8		reserved2;
-	__u8		density;		/* kbpi */
-	__u8		reserved3,reserved4;
-	__u16		segtrk;                 /* segment of per track */
-	__u16		trks;                   /* tracks per tape */
-	__u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
-} onstream_tape_paramtr_page_t;
-
-/*
- * OnStream ADRL frame
- */
-#define OS_FRAME_SIZE	(32 * 1024 + 512)
-#define OS_DATA_SIZE	(32 * 1024)
-#define OS_AUX_SIZE	(512)
-
-/*
- * internal error codes for onstream
- */
-#define OS_PART_ERROR    2
-#define OS_WRITE_ERROR   1
-
 #include <linux/mtio.h>
 
 /**************************** Tunable parameters *****************************/
@@ -842,7 +749,6 @@
 	struct request rq;			/* The corresponding request */
 	struct idetape_bh *bh;			/* The data buffers */
 	struct idetape_stage_s *next;		/* Pointer to the next stage */
-	os_aux_t *aux;				/* OnStream aux ptr */
 } idetape_stage_t;
 
 /*
@@ -1037,52 +943,6 @@
 	char write_prot;
 
 	/*
-	 * OnStream flags
-	 */
-	/* the tape is an OnStream tape */
-	int onstream;
-	/* OnStream raw access (32.5KB block size) */
-	int raw;
-	/* current number of frames in internal buffer */
-	int cur_frames;
-	/* max number of frames in internal buffer */
-	int max_frames;
-	/* logical block number */
-	int logical_blk_num;
-	/* write pass counter */
-	__u16 wrt_pass_cntr;
-	/* update frame counter */
-	__u32 update_frame_cntr;
-	struct completion *waiting;
-	/* write error recovery active */
-	int onstream_write_error;
-	/* header frame verified ok */
-	int header_ok;
-	/* reading linux-specific media */
-	int linux_media;
-	int linux_media_version;
-	/* application signature */
-	char application_sig[5];
-	int filemark_cnt;
-	int first_mark_addr;
-	int last_mark_addr;
-	int eod_frame_addr;
-	unsigned long cmd_start_time;
-	unsigned long max_cmd_time;
-	unsigned capacity;
-
-	/*
-	 * Optimize the number of "buffer filling"
-	 * mode sense commands.
-	 */
-	/* last time in which we issued fill cmd */
-	unsigned long last_buffer_fill;
-	/* buffer fill command requested */
-	int req_buffer_fill;
-	int writes_since_buffer_fill;
-	int reads_since_buffer_fill;
-
-	/*
 	 * Limit the number of times a request can
 	 * be postponed, to avoid an infinite postpone
 	 * deadlock.
@@ -1468,7 +1328,6 @@
  *      Function declarations
  *
  */
-static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug);
 static int idetape_chrdev_release (struct inode *inode, struct file *filp);
 static void idetape_write_release (ide_drive_t *drive, unsigned int minor);
 
@@ -1659,13 +1518,6 @@
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 &&
-	    result->asc == 0x53 && result->ascq == 2) {
-		clear_bit(PC_DMA_ERROR, &pc->flags);
-		ide_stall_queue(drive, HZ / 2);
-		return;
-	}
-
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
@@ -1706,7 +1558,7 @@
 			set_bit(PC_ABORT, &pc->flags);
 		}
 		if (!test_bit(PC_ABORT, &pc->flags) &&
-		    (tape->onstream || pc->actually_transferred))
+		    pc->actually_transferred)
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
@@ -1868,11 +1720,6 @@
 	int error;
 	int remove_stage = 0;
 	idetape_stage_t *active_stage;
-#if ONSTREAM_DEBUG
-	idetape_stage_t *stage;
-	os_aux_t *aux;
-	unsigned char *p;
-#endif
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
@@ -1897,50 +1744,11 @@
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
 		if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 2) {
-				if (tape->onstream) {
-					stage = tape->first_stage;
-					aux = stage->aux;
-					p = stage->bh->b_data;
-					if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
-						printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
-				}
-			}
-#endif
-			if (tape->onstream && !tape->raw) {
-				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
-#if ONSTREAM_DEBUG
-					if (tape->debug_level >= 2)
-						printk("ide-tape: %s: skipping over config partition.\n", tape->name);
-#endif
-					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting) {
-						rq->waiting = NULL;
-						complete(tape->waiting);
-					}
-				}
-			}
 			remove_stage = 1;
 			if (error) {
 				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
 					idetape_abort_pipeline(drive, active_stage);
-				if (tape->onstream && !tape->raw &&
-				    error == IDETAPE_ERROR_GENERAL &&
-				    tape->sense.sense_key == 3) {
-					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
-					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
-					tape->onstream_write_error = OS_WRITE_ERROR;
-					remove_stage = 0;
-					tape->nr_pending_stages++;
-					tape->next_stage = tape->first_stage;
-					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting) {
-						rq->waiting = NULL;
-						complete(tape->waiting);
-					}
-				}
 			}
 		} else if (rq->cmd[0] & REQ_IDETAPE_READ) {
 			if (error == IDETAPE_ERROR_EOD) {
@@ -1948,7 +1756,7 @@
 				idetape_abort_pipeline(drive, active_stage);
 			}
 		}
-		if (tape->next_stage != NULL && !tape->onstream_write_error) {
+		if (tape->next_stage != NULL) {
 			idetape_active_next_stage(drive);
 
 			/*
@@ -1956,7 +1764,6 @@
 			 */
 			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
-			if (!tape->onstream)
 				idetape_increase_max_pipeline_stages(drive);
 		}
 	}
@@ -2089,7 +1896,6 @@
 	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
-	unsigned long cmd_time;
 #if SIMULATE_ERRORS
 	static int error_sim_count = 0;
 #endif
@@ -2139,8 +1945,6 @@
 
 	/* No more interrupts */
 	if (!status.b.drq) {
-		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
-		tape->max_cmd_time = max(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
@@ -2178,8 +1982,7 @@
 			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
-		if (!tape->onstream &&
-		    test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+		if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
 		    !status.b.dsc) {
 			/* Media access command */
 			tape->dsc_polling_start = jiffies;
@@ -2333,7 +2136,6 @@
 				"a packet command\n");
 		return ide_do_reset(drive);
 	}
-	tape->cmd_start_time = jiffies;
 	/* Set the interrupt routine */
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -2383,12 +2185,6 @@
 						tape->name, pc->c[0],
 						tape->sense_key, tape->asc,
 						tape->ascq);
-				if (tape->onstream &&
-				    pc->c[0] == IDETAPE_READ_CMD &&
-				    tape->sense_key == 3 &&
-				    tape->asc == 0x11)
-					/* AJN-1: 11 should be 0x11 */
-					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
 			/* Giving up */
 			pc->error = IDETAPE_ERROR_GENERAL;
@@ -2482,48 +2278,6 @@
 	pc->callback = &idetape_pc_callback;
 }
 
-static ide_startstop_t idetape_onstream_buffer_fill_callback (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	tape->max_frames = tape->pc->buffer[4 + 2];
-	tape->cur_frames = tape->pc->buffer[4 + 3];
-	if (tape->chrdev_direction == idetape_direction_write)
-		tape->tape_head = tape->buffer_head - tape->cur_frames;
-	else
-		tape->tape_head = tape->buffer_head + tape->cur_frames;
-	if (tape->tape_head != tape->last_tape_head) {
-		tape->last_tape_head = tape->tape_head;
-		tape->tape_still_time_begin = jiffies;
-		if (tape->tape_still_time > 200)
-			tape->measure_insert_time = 1;
-	}
-	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
-#if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
-			tape->tape_head, tape->minor);
-#endif
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
-			tape->cur_frames, tape->max_frames);
-#endif
-	idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
-	return ide_stopped;
-}
-
-static void idetape_queue_onstream_buffer_fill (ide_drive_t *drive)
-{
-	idetape_pc_t *pc;
-	struct request *rq;
-
-	pc = idetape_next_pc_storage(drive);
-	rq = idetape_next_rq_storage(drive);
-	idetape_create_mode_sense_cmd(pc, IDETAPE_BUFFER_FILLING_PAGE);
-	pc->callback = idetape_onstream_buffer_fill_callback;
-	idetape_queue_pc_head(drive, pc, rq);
-}
-
 static void calculate_speeds(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -2579,8 +2333,6 @@
 	idetape_pc_t *pc = tape->pc;
 	atapi_status_t status;
 
-	if (tape->onstream)
-		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
 	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 	if (status.b.dsc) {
 		if (status.b.check) {
@@ -2641,7 +2393,6 @@
 
 static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
 {
-	struct idetape_bh *p = bh;
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_CMD;
 	put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
@@ -2650,23 +2401,9 @@
 	pc->bh = bh;
 	atomic_set(&bh->b_count, 0);
 	pc->buffer = NULL;
-	if (tape->onstream) {
-		while (p) {
-			atomic_set(&p->b_count, 0);
-			p = p->b_reqnext;
-		}
-	}
-	if (!tape->onstream) {
-		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
-		if (pc->request_transfer == tape->stage_size)
-			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-	} else  {
-		if (length) {
-			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-		} else
-			pc->request_transfer = 0;
-	}
+	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+	if (pc->request_transfer == tape->stage_size)
+		set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
@@ -2692,35 +2429,19 @@
 
 static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
 {
-	struct idetape_bh *p = bh;
-
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
 	put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	set_bit(PC_WRITING, &pc->flags);
-	if (tape->onstream) {
-		while (p) {
-			atomic_set(&p->b_count, p->b_size);
-			p = p->b_reqnext;
-		}
-	}
 	pc->bh = bh;
 	pc->b_data = bh->b_data;
 	pc->b_count = atomic_read(&bh->b_count);
 	pc->buffer = NULL;
-	if (!tape->onstream) {
-		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
-		if (pc->request_transfer == tape->stage_size)
-			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-	} else  {
-		if (length) {
-			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-		} else
-			pc->request_transfer = 0;
-	}
+	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+	if (pc->request_transfer == tape->stage_size)
+		set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
@@ -2782,65 +2503,14 @@
 	 */
 	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	/*
-	 * The OnStream tape drive doesn't support DSC. Assume
-	 * that DSC is always set.
-	 */
-	if (tape->onstream)
-		status.b.dsc = 1;
 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
-	/*
-	 * For the OnStream tape, check the current status of the tape
-	 * internal buffer using data gathered from the buffer fill
-	 * mode page, and postpone our request, effectively "disconnecting"
-	 * from the IDE bus, in case the buffer is full (writing) or
-	 * empty (reading), and there is a danger that our request will
-	 * hold the IDE bus during actual media access.
-	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill &&
-	    (rq->cmd[0] & (REQ_IDETAPE_WRITE | REQ_IDETAPE_READ))) {
-		tape->req_buffer_fill = 0;
-		tape->writes_since_buffer_fill = 0;
-		tape->reads_since_buffer_fill = 0;
-		tape->last_buffer_fill = jiffies;
-		idetape_queue_onstream_buffer_fill(drive);
-		if (time_after(jiffies, tape->insert_time))
-			tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-		return ide_stopped;
-	}
 	if (time_after(jiffies, tape->insert_time))
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
-	if (tape->onstream && tape->max_frames &&
-	    (((rq->cmd[0] & REQ_IDETAPE_WRITE) &&
-              ( tape->cur_frames == tape->max_frames ||
-                ( tape->speed_control && tape->cur_frames > 5 &&
-                       (tape->insert_speed > tape->max_insert_speed ||
-                        (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
-	     ((rq->cmd[0] & REQ_IDETAPE_READ) &&
-	      ( tape->cur_frames == 0 ||
-		( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
-			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
-#if IDETAPE_DEBUG_LOG
-		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, "
-					"cmd %ld, cur %d, max %d\n",
-				rq->cmd[0], tape->cur_frames, tape->max_frames);
-#endif
-		if (tape->postpone_cnt++ < 500) {
-			status.b.dsc = 0;
-			tape->req_buffer_fill = 1;
-		}
-#if ONSTREAM_DEBUG
-		else if (tape->debug_level >= 4) 
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
-				tape->name, tape->postpone_cnt);
-#endif
-	}
 	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
 	    !status.b.dsc) {
 		if (postponed_rq == NULL) {
@@ -2867,13 +2537,6 @@
 		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
 #endif
 		tape->postpone_cnt = 0;
-		tape->reads_since_buffer_fill++;
-		if (tape->onstream) {
-			if (tape->cur_frames - tape->reads_since_buffer_fill <= 0)
-				tape->req_buffer_fill = 1;
-			if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
-				tape->req_buffer_fill = 1;
-		}
 		pc = idetape_next_pc_storage(drive);
 		idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
 		goto out;
@@ -2884,14 +2547,6 @@
 		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
 #endif
 		tape->postpone_cnt = 0;
-		tape->writes_since_buffer_fill++;
-		if (tape->onstream) {
-			if (tape->cur_frames + tape->writes_since_buffer_fill >= tape->max_frames)
-				tape->req_buffer_fill = 1;
-			if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
-				tape->req_buffer_fill = 1;
-			calculate_speeds(drive);
-		}
 		pc = idetape_next_pc_storage(drive);
 		idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
 		goto out;
@@ -2995,8 +2650,6 @@
 	bh->b_size -= tape->excess_bh_size;
 	if (full)
 		atomic_sub(tape->excess_bh_size, &bh->b_count);
-	if (tape->onstream)
-		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
 	return stage;
 abort:
 	__idetape_kfree_stage(stage);
@@ -3093,14 +2746,10 @@
 static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
 {
 	struct idetape_bh *tmp;
-	os_aux_t *tmp_aux;
 
 	tmp = stage->bh;
-	tmp_aux = stage->aux;
 	stage->bh = tape->merge_stage->bh;
-	stage->aux = tape->merge_stage->aux;
 	tape->merge_stage->bh = tmp;
-	tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage(tape);
 }
 
@@ -3131,68 +2780,6 @@
 }
 
 /*
- * Initialize the OnStream AUX
- */
-static void idetape_init_stage (ide_drive_t *drive, idetape_stage_t *stage, int frame_type, int logical_blk_num)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	os_aux_t *aux = stage->aux;
-	os_partition_t *par = &aux->partition;
-	os_dat_t *dat = &aux->dat;
-
-	if (!tape->onstream || tape->raw)
-		return;
-	memset(aux, 0, sizeof(*aux));
-	aux->format_id = htonl(0);
-	memcpy(aux->application_sig, "LIN3", 4);
-	aux->hdwr = htonl(0);
-	aux->frame_type = frame_type;
-
-	if (frame_type == OS_FRAME_TYPE_HEADER) {
-		aux->update_frame_cntr = htonl(tape->update_frame_cntr);
-		par->partition_num = OS_CONFIG_PARTITION;
-		par->par_desc_ver = OS_PARTITION_VERSION;
-		par->wrt_pass_cntr = htons(0xffff);
-		par->first_frame_addr = htonl(0);
-		par->last_frame_addr = htonl(0xbb7); /* 2999 */
-		aux->frame_seq_num = htonl(0);
-		aux->logical_blk_num_high = htonl(0);
-		aux->logical_blk_num = htonl(0);
-		aux->next_mark_addr = htonl(tape->first_mark_addr);
-	} else {
-		aux->update_frame_cntr = htonl(0);
-		par->partition_num = OS_DATA_PARTITION;
-		par->par_desc_ver = OS_PARTITION_VERSION;
-		par->wrt_pass_cntr = htons(tape->wrt_pass_cntr);
-		par->first_frame_addr = htonl(OS_DATA_STARTFRAME1);
-		par->last_frame_addr = htonl(tape->capacity);
-		aux->frame_seq_num = htonl(logical_blk_num);
-		aux->logical_blk_num_high = htonl(0);
-		aux->logical_blk_num = htonl(logical_blk_num);
-		dat->dat_sz = 8;
-		dat->reserved1 = 0;
-		dat->entry_cnt = 1;
-		dat->reserved3 = 0;
-		if (frame_type == OS_FRAME_TYPE_DATA)
-			dat->dat_list[0].blk_sz = htonl(32 * 1024);
-		else
-			dat->dat_list[0].blk_sz = 0;
-		dat->dat_list[0].blk_cnt = htons(1);
-		if (frame_type == OS_FRAME_TYPE_MARKER)
-			dat->dat_list[0].flags = OS_DAT_FLAGS_MARK;
-		else
-			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
-		dat->dat_list[0].reserved = 0;
-	}
-	/* shouldn't this be htonl ?? */
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);
-	/* shouldn't this be htonl ?? */
-	aux->phys_fm = ntohl(0xffffffff);
-	/* shouldn't this be htonl ?? */
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);
-}
-
-/*
  *	idetape_wait_for_request installs a completion in a pending request
  *	and sleeps until it is serviced.
  *
@@ -3211,11 +2798,9 @@
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	rq->waiting = &wait;
-	tape->waiting = &wait;
 	spin_unlock_irq(&tape->spinlock);
 	wait_for_completion(&wait);
 	/* The stage and its struct request have been deallocated */
-	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
 
@@ -3269,13 +2854,9 @@
  */
 static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
 {
-	idetape_tape_t *tape = drive->driver_data;
-
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
-	if (tape->onstream)
-		pc->c[1] = 1; /* Immed bit */
-	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
+	pc->c[4] = write_filemark;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
@@ -3318,16 +2899,9 @@
 
 static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
-	idetape_tape_t *tape = drive->driver_data;
-
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
-	if (tape->onstream) {
-		pc->c[1] = 1;
-		if (cmd == !IDETAPE_LU_LOAD_MASK)
-			pc->c[4] = 4;
-	}
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
@@ -3366,20 +2940,7 @@
 
 static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
 {
-	idetape_tape_t *tape = drive->driver_data;
-	int rc;
-
-	rc = __idetape_queue_pc_tail(drive, pc);
-	if (rc)
-		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
-		/* AJN-4: Changed from 5 to 10 minutes;
-		 * because retension takes approx.
-		 * 8:20 with Onstream 30GB tape
-		 */
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
-	}
-	return rc;
+	return __idetape_queue_pc_tail(drive, pc);
 }
 
 static int idetape_flush_tape_buffers (ide_drive_t *drive)
@@ -3422,23 +2983,11 @@
 
 static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
 {
-	idetape_tape_t *tape = drive->driver_data;
-
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
-	if (tape->onstream)
-		pc->c[1] = 1; /* Immediate bit */
-	else
-		pc->c[1] = 2;
+	pc->c[1] = 2;
 	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
-	if (tape->onstream)
-                /*
-                 * Set SKIP bit.
-                 * In case of write error this will write buffered
-                 * data in the drive to this new position!
-                 */
-		pc->c[9] = skip << 7;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
@@ -3539,10 +3088,6 @@
 	cnt = __idetape_discard_read_pipeline(drive);
 	if (restore_position) {
 		position = idetape_read_position(drive);
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
-#endif
 		seek = position > cnt ? position - cnt : 0;
 		if (idetape_position_tape(drive, seek, 0, 0)) {
 			printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
@@ -3551,15 +3096,6 @@
 	}
 }
 
-static void idetape_update_stats (ide_drive_t *drive)
-{
-	idetape_pc_t pc;
-
-	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
-	pc.callback = idetape_onstream_buffer_fill_callback;
-	(void) idetape_queue_pc_tail(drive, &pc);
-}
-
 /*
  * idetape_queue_rw_tail generates a read/write request for the block
  * device interface and wait for it to be serviced.
@@ -3584,8 +3120,6 @@
 	rq.special = (void *)bh;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (tape->onstream)
-		tape->postpone_cnt = 600;
 	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
@@ -3599,108 +3133,6 @@
 }
 
 /*
- * Read back the drive's internal buffer contents, as a part
- * of the write error recovery mechanism for old OnStream
- * firmware revisions.
- */
-static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	int frames, i, logical_blk_num;
-	idetape_stage_t *stage, *first = NULL, *last = NULL;
-	os_aux_t *aux;
-	struct request *rq;
-	unsigned char *p;
-	unsigned long flags;
-
-	idetape_update_stats(drive);
-	frames = tape->cur_frames;
-	logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num) - frames;
-	printk(KERN_INFO "ide-tape: %s: reading back %d frames from the drive's internal buffer\n", tape->name, frames);
-	for (i = 0; i < frames; i++) {
-		stage = __idetape_kmalloc_stage(tape, 0, 0);
-		if (!first)
-			first = stage;
-		aux = stage->aux;
-		p = stage->bh->b_data;
-		idetape_queue_rw_tail(drive, REQ_IDETAPE_READ_BUFFER, tape->capabilities.ctl, stage->bh);
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
-#endif
-		rq = &stage->rq;
-		idetape_init_rq(rq, REQ_IDETAPE_WRITE);
-		rq->sector = tape->first_frame_position;
-		rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
-		idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
-		stage->next = NULL;
-		if (last)
-			last->next = stage;
-		last = stage;
-	}
-	if (frames) {
-		spin_lock_irqsave(&tape->spinlock, flags);
-		last->next = tape->first_stage;
-		tape->next_stage = tape->first_stage = first;
-		tape->nr_stages += frames;
-		tape->nr_pending_stages += frames;
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	idetape_update_stats(drive);
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
-#endif
-}
-
-/*
- * Error recovery algorithm for the OnStream tape.
- */
-static void idetape_onstream_write_error_recovery (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	unsigned int block;
-
-	if (tape->onstream_write_error == OS_WRITE_ERROR) {
-		printk(KERN_ERR "ide-tape: %s: onstream_write_error_recovery: detected physical bad block at %u, logical %u first frame %u last_frame %u bufblocks %u stages %u skipping %u frames\n",
-			tape->name, ntohl(tape->sense.information), tape->logical_blk_num,
-			tape->first_frame_position, tape->last_frame_position,
-			tape->blocks_in_buffer, tape->nr_stages,
- 			(ntohl(tape->sense.command_specific) >> 16) & 0xff );
-		block = ntohl(tape->sense.information) + ((ntohl(tape->sense.command_specific) >> 16) & 0xff);
-		idetape_update_stats(drive);
-		printk(KERN_ERR "ide-tape: %s: relocating %d buffered logical blocks to physical block %u\n", tape->name, tape->cur_frames, block);
-#if 0  /* isn't once enough ??? MM */
-		idetape_update_stats(drive);
-#endif
-		if (tape->firmware_revision_num >= 106)
-			idetape_position_tape(drive, block, 0, 1);
-		else {
-			idetape_onstream_read_back_buffer(drive);
-			idetape_position_tape(drive, block, 0, 0);
-		}
-#if 0     /* already done in idetape_position_tape MM */
-		idetape_read_position(drive);
-#endif
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 1)
-			printk(KERN_ERR "ide-tape: %s: positioning complete, cur_frames %d, pos %d, tape pos %d\n", tape->name, tape->cur_frames, tape->first_frame_position, tape->last_frame_position);
-#endif
-	} else if (tape->onstream_write_error == OS_PART_ERROR) {
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 1)
-			printk(KERN_INFO "ide-tape: %s: skipping over config partition\n", tape->name);
-#endif
-		idetape_flush_tape_buffers(drive);
-		block = idetape_read_position(drive);
-		if (block != OS_DATA_ENDFRAME1)  
-			printk(KERN_ERR "ide-tape: warning, current position %d, expected %d\n", block, OS_DATA_ENDFRAME1);
-		idetape_position_tape(drive, 0xbb8, 0, 0); /* 3000 */
-	}
-	tape->onstream_write_error = 0;
-}
-
-/*
  *	idetape_insert_pipeline_into_queue is used to start servicing the
  *	pipeline stages, starting from tape->next_stage.
  */
@@ -3711,8 +3143,6 @@
 	if (tape->next_stage == NULL)
 		return;
 	if (!idetape_pipeline_active(tape)) {
-		if (tape->onstream_write_error)
-			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 		idetape_active_next_stage(drive);
 		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
@@ -3729,16 +3159,13 @@
 
 static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
 {
-	idetape_tape_t *tape = drive->driver_data;
-
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
-	if (tape->onstream)
-		pc->c[1] = 1;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
+#if 0
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
 	idetape_init_pc(pc);
@@ -3749,6 +3176,7 @@
 	pc->request_transfer = 255;
 	pc->callback = &idetape_pc_callback;
 }
+#endif
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
@@ -3769,82 +3197,6 @@
 	pc->callback = &idetape_pc_callback;
 }
 
-/*
- * Verify that we have the correct tape frame
- */
-static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int logical_blk_num, int quiet)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	os_aux_t *aux = stage->aux;
-	os_partition_t *par = &aux->partition;
-	struct request *rq = &stage->rq;
-	struct idetape_bh *bh;
-
-	if (!tape->onstream)
-		return 1;
-	if (tape->raw) {
-		if (rq->errors) {
-			bh = stage->bh;
-			while (bh) {
-				memset(bh->b_data, 0, bh->b_size);
-				bh = bh->b_reqnext;
-			}
-			strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
-		}
-		return 1;
-	}
-	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
-		return 0;
-	}
-	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
-		return 0;
-	}
-	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
-		return 0;
-	}
-	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
-		return 0;
-	}
-	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
-	    aux->frame_type != OS_FRAME_TYPE_EOD &&
-	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
-		return 0;
-	}
-	if (par->partition_num != OS_DATA_PARTITION) {
-		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
-			return 0;
-		}
-	}
-	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
-		return 0;
-	}
-	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
-		return 0;
-	}
-	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
-		return 0;
-	}
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
-		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
-		return 0;
-	}
-	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
-		rq->errors = IDETAPE_ERROR_FILEMARK;
-		rq->current_nr_sectors = rq->nr_sectors;
-	}
-	return 1;
-}
-
 static void idetape_wait_first_stage (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -3909,8 +3261,6 @@
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
 	idetape_switch_buffers(tape, new_stage);
-	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
-	tape->logical_blk_num++;
 	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
@@ -3924,15 +3274,6 @@
 	 *	writing anymore, wait for the pipeline to be full enough
 	 *	(90%) before starting to service requests, so that we will
 	 *	be able to keep up with the higher speeds of the tape.
-	 *
-	 *	For the OnStream drive, we can query the number of pending
-	 *	frames in the drive's internal buffer. As long as the tape
-	 *	is still writing, it is better to write frames immediately
-	 *	rather than gather them in the pipeline. This will give the
-	 *	tape's firmware the ability to sense the current incoming
-	 *	data rate more accurately, and since the OnStream tape
-	 *	supports variable speeds, it can try to adjust itself to the
-	 *	incoming data rate.
 	 */
 	if (!idetape_pipeline_active(tape)) {
 		if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
@@ -3942,10 +3283,6 @@
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
 			idetape_insert_pipeline_into_queue(drive);
-		} else if (tape->onstream) {
-			idetape_update_stats(drive);
-			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
@@ -4052,7 +3389,6 @@
 
 	tape->restart_speed_control_req = 0;
 	tape->pipeline_head = 0;
-	tape->buffer_head = tape->tape_head = tape->cur_frames;
 	tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
 	tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
 	tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000;
@@ -4084,7 +3420,6 @@
 		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_read;
-		tape->logical_blk_num = 0;
 
 		/*
 		 *	Issue a read 0 command to ensure that DSC handshake
@@ -4126,89 +3461,11 @@
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
 			idetape_insert_pipeline_into_queue(drive);
-		} else if (tape->onstream) {
-			idetape_update_stats(drive);
-			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
 }
 
-static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int max_stages, int quiet)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	unsigned long flags;
-	int cnt = 0, x, position;
-
-	/*
-	 * Search and wait for the next logical tape block
-	 */
-	while (1) {
-		if (cnt++ > 1000) {   /* AJN: was 100 */
-			printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
-			return 0;
-		}
-		idetape_initiate_read(drive, max_stages);
-		if (tape->first_stage == NULL) {
-			if (tape->onstream) {
-#if ONSTREAM_DEBUG
-				if (tape->debug_level >= 1)
-					printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ld\n", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
-#endif
-				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
-				position = idetape_read_position(drive);
-				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
-				if (position >= 3000 && position < 3080)
-					/* Why is this check and number ??? MM */
-					position += 32;
-				if (position >= OS_DATA_ENDFRAME1 &&
-				    position < 3000)
-					position = 3000;
-				else
-					/*
-					 * compensate for write errors that
-					 * generally skip 80 frames, expect
-					 * around 20 read errors in a row...
-					 */
-					position += 60;
-				if (position >= OS_DATA_ENDFRAME1 &&
-				    position < 3000)
-					position = 3000;
-				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
-
-				/* seems to be needed to correctly position
-				 * at block 3000 MM
-				 */
-				if (position == 3000)
-					idetape_position_tape(drive, 0, 0, 0);
-				idetape_position_tape(drive, position, 0, 0);
-				cnt += 40;
-				continue;
-			} else
-				return 0;
-		}
-		idetape_wait_first_stage(drive);
-		if (idetape_verify_stage(drive, tape->first_stage, logical_blk_num, quiet))
-			break;
-		if (tape->first_stage->rq.errors == IDETAPE_ERROR_EOD)
-			cnt--;
-		if (idetape_verify_stage(drive, tape->first_stage, -1, quiet)) {
-			x = ntohl(tape->first_stage->aux->logical_blk_num);
-			if (x > logical_blk_num) {
-				printk(KERN_ERR "ide-tape: %s: couldn't find logical block %d, aborting (block %d found)\n", tape->name, logical_blk_num, x);
-				return 0;
-			}
-		}
-		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head(drive);
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	if (tape->onstream)
-		tape->logical_blk_num = ntohl(tape->first_stage->aux->logical_blk_num);
-	return 1;
-}
-
 /*
  *	idetape_add_chrdev_read_request is called from idetape_chrdev_read
  *	to service a character device read request and add read-ahead
@@ -4233,48 +3490,30 @@
 		return 0;
 
 	/*
-	 * Wait for the next logical block to be available at the head
+	 * Wait for the next block to be available at the head
 	 * of the pipeline
 	 */
-	if (!idetape_get_logical_blk(drive, tape->logical_blk_num, tape->max_stages, 0)) {
-		if (tape->onstream) {
-			set_bit(IDETAPE_READ_ERROR, &tape->flags);
-			return 0;
-		}
+	idetape_initiate_read(drive, tape->max_stages);
+	if (tape->first_stage == NULL) {
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
-		 	return 0;
+			return 0;
 		return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh);
 	}
+	idetape_wait_first_stage(drive);
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw &&
-	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
-				tape->name);
-#endif
-		return 0;
-	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
 	else {
 		idetape_switch_buffers(tape, tape->first_stage);
-		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
-#endif
-		}
 		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
 			set_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
-		tape->logical_blk_num++;
 		tape->pipeline_head++;
 #if USE_IOTRACE
 		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -4342,8 +3581,8 @@
 {
 	int retval;
 	idetape_pc_t pc;
-	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
+	idetape_tape_t *tape = drive->driver_data;
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
 #endif /* IDETAPE_DEBUG_LOG */	
@@ -4357,7 +3596,6 @@
 	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
-	tape->logical_blk_num = 0;
 	return 0;
 }
 
@@ -4406,206 +3644,26 @@
 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
-static int idetape_onstream_space_over_filemarks_backward (ide_drive_t *drive,short mt_op,int mt_count)
+/*
+ *	idetape_space_over_filemarks is now a bit more complicated than just
+ *	passing the command to the tape since we may have crossed some
+ *	filemarks during our pipelined read-ahead mode.
+ *
+ *	As a minor side effect, the pipeline enables us to support MTFSFM when
+ *	the filemark is in our internal pipeline even if the tape doesn't
+ *	support spacing over filemarks in the reverse direction.
+ */
+static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	int cnt = 0;
-	int last_mark_addr;
+	idetape_pc_t pc;
 	unsigned long flags;
+	int retval,count=0;
 
-	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name);
-		return -EIO;
-	}
-	while (cnt != mt_count) {
-		last_mark_addr = ntohl(tape->first_stage->aux->last_mark_addr);
-		if (last_mark_addr == -1)
-			return -EIO;
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
-#endif
-		idetape_position_tape(drive, last_mark_addr, 0, 0);
-		cnt++;
-		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
-			return -EIO;
-		}
-		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr);
-			return -EIO;
-		}
-	}
-	if (mt_op == MTBSFM) {
-		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head(drive);
-		tape->logical_blk_num++;
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	return 0;
-}
-
-/*
- * ADRL 1.1 compatible "slow" space filemarks fwd version
- *
- * Just scans for the filemark sequentially.
- */
-static int idetape_onstream_space_over_filemarks_forward_slow (ide_drive_t *drive,short mt_op,int mt_count)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	int cnt = 0;
-	unsigned long flags;
-
-	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
-		return -EIO;
-	}
-	while (1) {
-		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
-			return -EIO;
-		}
-		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
-			cnt++;
-		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
-#endif
-			return -EIO;
-		}
-		if (cnt == mt_count)
-			break;
-		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head(drive);
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	if (mt_op == MTFSF) {
-		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head(drive);
-		tape->logical_blk_num++;
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	return 0;
-}
-
-
-/*
- * Fast linux specific version of OnStream FSF
- */
-static int idetape_onstream_space_over_filemarks_forward_fast (ide_drive_t *drive,short mt_op,int mt_count)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	int cnt = 0, next_mark_addr;
-	unsigned long flags;
-
-	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
-		return -EIO;
-	}
-
-	/*
-	 * Find nearest (usually previous) marker
-	 */
-	while (1) {
-		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
-			break;
-		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
-#endif
-			return -EIO;
-		}
-		if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
-			if (tape->first_mark_addr == -1) {
-				printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
-				return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
-			}
-			idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
-			if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-				printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name);
-				return -EIO;
-			}
-			if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr);
-				return -EIO;
-			}
-		} else {
-			if (idetape_onstream_space_over_filemarks_backward(drive, MTBSF, 1) < 0)
-				return -EIO;
-			mt_count++;
-		}
-	}
-	cnt++;
-	while (cnt != mt_count) {
-		next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
-		if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
-			printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
-			return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
-#if ONSTREAM_DEBUG
-		} else if (tape->debug_level >= 2) {
-		     printk(KERN_INFO "ide-tape: positioning to next mark at %d\n", next_mark_addr);
-#endif
-		}
-		idetape_position_tape(drive, next_mark_addr, 0, 0);
-		cnt++;
-		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
-			return -EIO;
-		}
-		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr);
-			return -EIO;
-		}
-	}
-	if (mt_op == MTFSF) {
-		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head(drive);
-		tape->logical_blk_num++;
-		spin_unlock_irqrestore(&tape->spinlock, flags);
-	}
-	return 0;
-}
-
-/*
- *	idetape_space_over_filemarks is now a bit more complicated than just
- *	passing the command to the tape since we may have crossed some
- *	filemarks during our pipelined read-ahead mode.
- *
- *	As a minor side effect, the pipeline enables us to support MTFSFM when
- *	the filemark is in our internal pipeline even if the tape doesn't
- *	support spacing over filemarks in the reverse direction.
- */
-static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_pc_t pc;
-	unsigned long flags;
-	int retval,count=0;
-	int speed_control;
-
-	if (tape->onstream) {
-		if (tape->raw)
-			return -EIO;
-		speed_control = tape->speed_control;
-		tape->speed_control = 0;
-		if (mt_op == MTFSF || mt_op == MTFSFM) {
-			if (tape->linux_media)
-				retval = idetape_onstream_space_over_filemarks_forward_fast(drive, mt_op, mt_count);
-			else
-				retval = idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
-		} else
-			retval = idetape_onstream_space_over_filemarks_backward(drive, mt_op, mt_count);
-		tape->speed_control = speed_control;
-		tape->restart_speed_control_req = 1;
-		return retval;
-	}
- 
-	if (mt_count == 0)
-		return 0;
-	if (MTBSF == mt_op || MTBSFM == mt_op) {
-		if (!tape->capabilities.sprev)
+	if (mt_count == 0)
+		return 0;
+	if (MTBSF == mt_op || MTBSFM == mt_op) {
+		if (!tape->capabilities.sprev)
 			return -EIO;
 		mt_count = - mt_count;
 	}
@@ -4700,10 +3758,6 @@
 		/* "A request was outside the capabilities of the device." */
 		return -ENXIO;
 	}
-	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
-		return -EINVAL;
-	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
 		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
@@ -4753,179 +3807,15 @@
 		idetape_space_over_filemarks(drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read &&
-	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
-			"logical block number %d, skipping\n",
-			tape->name, tape->logical_blk_num);
-		tape->logical_blk_num++;
-		return -EIO;
-	}
 	return actually_read;
 }
 
-static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr, int next_mark_addr)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage;
-	os_aux_t *aux;
-	int position;
-
-	if (!tape->onstream || tape->raw)
-		return;
-	if (last_mark_addr == -1)
-		return;
-	stage = __idetape_kmalloc_stage(tape, 0, 0);
-	if (stage == NULL)
-		return;
-	idetape_flush_tape_buffers(drive);
-	position = idetape_read_position(drive);
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, "
-			"lblk %d\n", position, tape->logical_blk_num);
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) "
-			"tape block %d\n", tape->last_frame_position);
-#endif
-	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n",
-			tape->name);
-		__idetape_kfree_stage(stage);
-		idetape_position_tape(drive, position, 0, 0);
-		return;
-	}
-	aux = stage->aux;
-	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker "
-			"at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage(stage);
-		idetape_position_tape(drive, position, 0, 0);
-		return;
-	}
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: writing back marker\n");
-#endif
-	aux->next_mark_addr = htonl(next_mark_addr);
-	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker "
-			"frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage(stage);
-		idetape_position_tape(drive, position, 0, 0);
-		return;
-	}
-	__idetape_kfree_stage(stage);
-	idetape_flush_tape_buffers(drive);
-	idetape_position_tape(drive, position, 0, 0);
-	return;
-}
-
-static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage;
-	int rc;
-
-	if (!tape->onstream || tape->raw)
-		return;
-	stage = __idetape_kmalloc_stage(tape, 1, 1);
-	if (stage == NULL)
-		return;
-	idetape_init_stage(drive, stage, OS_FRAME_TYPE_FILL, 0);
-	idetape_wait_ready(drive, 60 * 5 * HZ);
-	rc = idetape_position_tape(drive, block, 0, 0);
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
-#endif
-	if (rc != 0)
-		/* don't write fillers if we cannot position the tape. */
-		return;
-
-	strcpy(stage->bh->b_data, "Filler");
-	while (cnt--) {
-		if (!idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: "
-				"couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage(stage);
-			return;
-		}
-	}
-	__idetape_kfree_stage(stage);
-}
-
-static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage;
-	os_header_t header;
-
-	stage = __idetape_kmalloc_stage(tape, 1, 1);
-	if (stage == NULL)
-		return;
-	idetape_init_stage(drive, stage, OS_FRAME_TYPE_HEADER, tape->logical_blk_num);
-	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_position_tape(drive, block, 0, 0);
-	memset(&header, 0, sizeof(header));
-	strcpy(header.ident_str, "ADR_SEQ");
-	header.major_rev = 1;
-	header.minor_rev = OS_ADR_MINREV;
-	header.par_num = 1;
-	header.partition.partition_num = OS_DATA_PARTITION;
-	header.partition.par_desc_ver = OS_PARTITION_VERSION;
-	header.partition.first_frame_addr = htonl(OS_DATA_STARTFRAME1);
-	header.partition.last_frame_addr = htonl(tape->capacity);
-	header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
-	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
-	memcpy(stage->bh->b_data, &header, sizeof(header));
-	while (cnt--) {
-		if (!idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't write "
-				"header frame\n", tape->name);
-			__idetape_kfree_stage(stage);
-			return;
-		}
-	}
-	__idetape_kfree_stage(stage);
-	idetape_flush_tape_buffers(drive);
-}
-
-static void idetape_write_header (ide_drive_t *drive, int locate_eod)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: writing tape header\n",
-			tape->name);
-#endif
-	if (!tape->onstream || tape->raw)
-		return;
-	tape->update_frame_cntr++;
-	__idetape_write_header(drive, 5, 5);
-	__idetape_write_header(drive, 0xbae, 5); /* 2990 */
-	if (locate_eod) {
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod "
-				"frame addr %d\n", tape->name,
-				tape->eod_frame_addr);
-#endif
-		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
-	}
-}
-
 static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
 				     size_t count, loff_t *ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
 	ide_drive_t *drive = file->private_data;
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor = iminor(inode);
 	ssize_t retval, actually_written = 0;
-	int position;
 
 	if (ppos != &file->f_pos) {
 		/* "A request was outside the capabilities of the device." */
@@ -4942,28 +3832,6 @@
 			"count %Zd\n", count);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream) {
-		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d "
-				"bytes as block size (%Zd used)\n",
-				tape->name, tape->tape_block_size, count);
-			return -EINVAL;
-		}
-		/*
-		 * Check if we reach the end of the tape. Just assume the whole
-		 * pipeline is filled with write requests!
-		 */
-		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
-#if ONSTREAM_DEBUG
-			printk(KERN_INFO, "chrdev_write: Write truncated at "
-				"EOM early warning");
-#endif
-			if (tape->chrdev_direction == idetape_direction_write)
-				idetape_write_release(drive, minor);
-			return -ENOSPC;
-		}
-	}
-
 	/* Initialize write operation */
 	if (tape->chrdev_direction != idetape_direction_write) {
 		if (tape->chrdev_direction == idetape_direction_read)
@@ -4980,39 +3848,6 @@
 		tape->chrdev_direction = idetape_direction_write;
 		idetape_init_merge_stage(tape);
 
-		if (tape->onstream) {
-			position = idetape_read_position(drive);
-			if (position <= OS_DATA_STARTFRAME1) {
-				tape->logical_blk_num = 0;
-				tape->wrt_pass_cntr++;
-#if ONSTREAM_DEBUG
-				if (tape->debug_level >= 2)
-					printk(KERN_INFO "ide-tape: %s: logical block num 0, setting eod to %d\n", tape->name, OS_DATA_STARTFRAME1);
-				if (tape->debug_level >= 2)
-					printk(KERN_INFO "ide-tape: %s: allocating new write pass counter %d\n", tape->name, tape->wrt_pass_cntr);
-#endif
-				tape->filemark_cnt = 0;
-				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
-				tape->first_mark_addr = tape->last_mark_addr = -1;
-				idetape_write_header(drive, 1);
-			}
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: positioning "
-					"tape to eod at %d\n",
-					tape->name, tape->eod_frame_addr);
-#endif
-			position = idetape_read_position(drive);
-			if (position != tape->eod_frame_addr)
-				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
-#if ONSTREAM_DEBUG
-			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: "
-					"first_frame_position %d\n",
-					tape->name, tape->first_frame_position);
-#endif
-		}
-
 		/*
 		 *	Issue a write 0 command to ensure that DSC handshake
 		 *	is switched from completion mode to buffer available
@@ -5029,11 +3864,6 @@
 				return retval;
 			}
 		}
-#if ONSTREAM_DEBUG
-		if (tape->debug_level >= 2)
-			printk("ide-tape: first_frame_position %d\n",
-				tape->first_frame_position);
-#endif
 	}
 	if (count == 0)
 		return (0);
@@ -5078,88 +3908,14 @@
 
 static int idetape_write_filemark (ide_drive_t *drive)
 {
-	idetape_tape_t *tape = drive->driver_data;
-	int last_mark_addr;
 	idetape_pc_t pc;
 
-	if (!tape->onstream) {
-		/* Write a filemark */
-		idetape_create_write_filemark_cmd(drive, &pc, 1);
-		if (idetape_queue_pc_tail(drive, &pc)) {
-			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
-			return -EIO;
-		}
-	} else if (!tape->raw) {
-		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
-		if (tape->merge_stage != NULL) {
-			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros(drive, tape->stage_size);
-			tape->logical_blk_num++;
-			__idetape_kfree_stage(tape->merge_stage);
-			tape->merge_stage = NULL;
-		}
-		if (tape->filemark_cnt)
-			idetape_update_last_marker(drive, tape->last_mark_addr, last_mark_addr);
-		tape->last_mark_addr = last_mark_addr;
-		if (tape->filemark_cnt++ == 0)
-			tape->first_mark_addr = last_mark_addr;
-	}
-	return 0;
-}
-
-static void idetape_write_eod (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	if (!tape->onstream || tape->raw)
-		return;
-	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
-	if (tape->merge_stage != NULL) {
-		tape->eod_frame_addr = idetape_read_position(drive);
-		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros(drive, tape->stage_size);
-		__idetape_kfree_stage(tape->merge_stage);
-		tape->merge_stage = NULL;
-	}
-	return;
-}
-
-int idetape_seek_logical_blk (ide_drive_t *drive, int logical_blk_num)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	int estimated_address = logical_blk_num + 20;
-	int retries = 0;
-	int speed_control;
-
-	speed_control = tape->speed_control;
-	tape->speed_control = 0;
-	if (logical_blk_num < 0)
-		logical_blk_num = 0;
-	if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1))
-		goto ok;
-	while (++retries < 10) {
-		idetape_discard_read_pipeline(drive, 0);
-		idetape_position_tape(drive, estimated_address, 0, 0);
-		if (idetape_get_logical_blk(drive, logical_blk_num, 10, 1))
-			goto ok;
-		if (!idetape_get_logical_blk(drive, -1, 10, 1))
-			goto error;
-		if (tape->logical_blk_num < logical_blk_num)
-			estimated_address += logical_blk_num - tape->logical_blk_num;
-		else
-			break;
+	/* Write a filemark */
+	idetape_create_write_filemark_cmd(drive, &pc, 1);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		return -EIO;
 	}
-error:
-	tape->speed_control = speed_control;
-	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
-		"(at %d), %d retries\n", tape->name, logical_blk_num,
-		tape->logical_blk_num, retries);
-	return -EIO;
-ok:
-	tape->speed_control = speed_control;
-	tape->restart_speed_control_req = 1;
 	return 0;
 }
 
@@ -5266,8 +4022,6 @@
 			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
-			if (tape->onstream && !tape->raw)
-				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
 			idetape_discard_read_pipeline(drive, 0);
@@ -5298,50 +4052,13 @@
 			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
 			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
-			if (tape->onstream) {
-#if ONSTREAM_DEBUG
-				if (tape->debug_level >= 2)
-					printk(KERN_INFO "ide-tape: %s: positioning tape to eod at %d\n", tape->name, tape->eod_frame_addr);
-#endif
-				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
-				if (!idetape_get_logical_blk(drive, -1, 10, 0))
-					return -EIO;
-				if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_EOD)
-					return -EIO;
-				return 0;
-			}
 			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
 			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
-			if (tape->onstream) {
-				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
-				tape->logical_blk_num = 0;
-				tape->first_mark_addr = tape->last_mark_addr = -1;
-				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
-				idetape_write_eod(drive);
-				idetape_flush_tape_buffers(drive);
-				idetape_write_header(drive, 0);
-				/*
-				 * write filler frames to the unused frames...
-				 * REMOVE WHEN going to LIN4 application type...
-				 */
-				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
-				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers(drive);
-				(void) idetape_rewind_tape(drive);
-				return 0;
-			}
 			(void) idetape_rewind_tape(drive);
 			idetape_create_erase_cmd(&pc);
 			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
-			if (tape->onstream) {
-				if (mt_count != tape->tape_block_size) {
-					printk(KERN_INFO "ide-tape: %s: MTSETBLK %d -- only %d bytes block size supported\n", tape->name, mt_count, tape->tape_block_size);
-					return -EINVAL;
-				}
-				return 0;
-			}
 			if (mt_count) {
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
@@ -5351,28 +4068,13 @@
 				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
-			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline(drive, 0);
-				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
-			}
-			return idetape_seek_logical_blk(drive, mt_count);
+			idetape_discard_read_pipeline(drive, 0);
+			return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 		case MTSETPART:
 			idetape_discard_read_pipeline(drive, 0);
-			if (tape->onstream)
-				return -EIO;
 			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
-			if (tape->onstream) {
-				if (!idetape_get_logical_blk(drive, -1, 10, 0))
-					return -EIO;
-				if (mt_op == MTFSR)
-					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
-				else {
-					idetape_discard_read_pipeline(drive, 0);
-					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
-				}
-			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
@@ -5450,34 +4152,16 @@
 		case MTIOCGET:
 			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
-			if (!tape->onstream || tape->raw)
-				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-			else {
-				if (!idetape_get_logical_blk(drive, -1, 10, 0))
-					mtget.mt_blkno = -1;
-				else
-					mtget.mt_blkno = tape->logical_blk_num;
-			}
+			mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
 			mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
-			if (tape->onstream) {
-				mtget.mt_gstat |= GMT_ONLINE(0xffffffff);
-				if (tape->first_stage && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD)
-					mtget.mt_gstat |= GMT_EOD(0xffffffff);
-				if (position <= OS_DATA_STARTFRAME1)
-					mtget.mt_gstat |= GMT_BOT(0xffffffff);
-			} else if (tape->drv_write_prot) {
+			if (tape->drv_write_prot) {
 				mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
 			}
 			if (copy_to_user((char *) arg,(char *) &mtget, sizeof(struct mtget)))
 				return -EFAULT;
 			return 0;
 		case MTIOCPOS:
-			if (tape->onstream && !tape->raw) {
-				if (!idetape_get_logical_blk(drive, -1, 10, 0))
-					return -EIO;
-				mtpos.mt_blkno = tape->logical_blk_num;
-			} else
-				mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
+			mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
 			if (copy_to_user((char *) arg,(char *) &mtpos, sizeof(struct mtpos)))
 				return -EFAULT;
 			return 0;
@@ -5488,106 +4172,6 @@
 	}
 }
 
-static int __idetape_analyze_headers (ide_drive_t *drive, int block)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage;
-	os_header_t *header;
-	os_aux_t *aux;
-
-	if (!tape->onstream || tape->raw) {
-		tape->header_ok = tape->linux_media = 1;
-		return 1;
-	}
-	tape->header_ok = tape->linux_media = 0;
-	tape->update_frame_cntr = 0;
-	tape->wrt_pass_cntr = 0;
-	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
-	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage(tape, 0, 0);
-	if (stage == NULL)
-		return 0;
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
-#endif
-	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n",
-			tape->name);
-		__idetape_kfree_stage(stage);
-		return 0;
-	}
-	header = (os_header_t *) stage->bh->b_data;
-	aux = stage->aux;
-	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
-		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
-		__idetape_kfree_stage(stage);
-		return 0;
-	}
-	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
-		printk(KERN_INFO "ide-tape: warning: revision %d.%d "
-			"detected (up to 1.%d supported)\n",
-			header->major_rev, header->minor_rev, OS_ADR_MINREV);
-	if (header->par_num != 1)
-		printk(KERN_INFO "ide-tape: warning: %d partitions defined, only one supported\n", header->par_num);
-	tape->wrt_pass_cntr = ntohs(header->partition.wrt_pass_cntr);
-	tape->eod_frame_addr = ntohl(header->partition.eod_frame_addr);
-	tape->filemark_cnt = ntohl(aux->filemark_cnt);
-	tape->first_mark_addr = ntohl(aux->next_mark_addr);
-	tape->last_mark_addr = ntohl(aux->last_mark_addr);
-	tape->update_frame_cntr = ntohl(aux->update_frame_cntr);
-	memcpy(tape->application_sig, aux->application_sig, 4);
-	tape->application_sig[4] = 0;
-	if (memcmp(tape->application_sig, "LIN", 3) == 0) {
-		tape->linux_media = 1;
-		tape->linux_media_version = tape->application_sig[3] - '0';
-		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version "
-				"%d detected (current 3)\n",
-				 tape->name, tape->linux_media_version);
-	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
-			"(%s)\n", tape->name, tape->application_sig);
-		tape->linux_media = 0;
-	}
-#if ONSTREAM_DEBUG
-	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter "
-			"%d, eod frame addr %d\n", tape->name,
-			tape->wrt_pass_cntr, tape->eod_frame_addr);
-#endif
-	__idetape_kfree_stage(stage);
-	return 1;
-}
-
-static int idetape_analyze_headers (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	int position, block;
-
-	if (!tape->onstream || tape->raw) {
-		tape->header_ok = tape->linux_media = 1;
-		return 1;
-	}
-	tape->header_ok = tape->linux_media = 0;
-	position = idetape_read_position(drive);
-	for (block = 5; block < 10; block++)
-		if (__idetape_analyze_headers(drive, block))
-			goto ok;
-	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
-		if (__idetape_analyze_headers(drive, block))
-			goto ok;
-	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
-	return 0;
-ok:
-	if (position < OS_DATA_STARTFRAME1)
-		position = OS_DATA_STARTFRAME1;
-	idetape_position_tape(drive, position, 0, 0);
-	tape->header_ok = 1;
-	return 1;
-}
-
 static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive);
 
 /*
@@ -5613,16 +4197,6 @@
 
 	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
-	if (tape->onstream) {
-		if (minor & 64) {
-			tape->tape_block_size = tape->stage_size = 32768 + 512;
-			tape->raw = 1;
-		} else {
-			tape->tape_block_size = tape->stage_size = 32768;
-			tape->raw = 0;
-		}
-                idetape_onstream_mode_sense_tape_parameter_page(drive, tape->debug_level);
-	}
 	retval = idetape_wait_ready(drive, 60 * HZ);
 	if (retval) {
 		clear_bit(IDETAPE_BUSY, &tape->flags);
@@ -5657,7 +4231,6 @@
 
 	/*
 	 * Lock the tape drive door so user can't eject.
-	 * Analyze headers for OnStream drives.
 	 */
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
@@ -5666,9 +4239,7 @@
 					tape->door_locked = DOOR_LOCKED;
 			}
 		}
-		idetape_analyze_headers(drive);
 	}
-	tape->max_frames = tape->cur_frames = tape->req_buffer_fill = 0;
 	idetape_restart_speed_control(drive);
 	tape->restart_speed_control_req = 0;
 	return 0;
@@ -5686,9 +4257,7 @@
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
-	idetape_write_eod(drive);
 	idetape_flush_tape_buffers(drive);
-	idetape_write_header(drive, minor >= 128);
 	idetape_flush_tape_buffers(drive);
 }
 
@@ -5867,100 +4436,6 @@
 }
 
 /*
- * Notify vendor ID to the OnStream tape drive
- */
-static void idetape_onstream_set_vendor (ide_drive_t *drive, char *vendor)
-{
-	idetape_pc_t pc;
-	idetape_mode_parameter_header_t *header;
-
-	idetape_create_mode_select_cmd(&pc, sizeof(*header) + 8);
-	pc.buffer[0] = 3 + 8;	/* Mode Data Length */
-	pc.buffer[1] = 0;	/* Medium Type - ignoring */
-	pc.buffer[2] = 0;	/* Reserved */
-	pc.buffer[3] = 0;	/* Block Descriptor Length */
-	pc.buffer[4 + 0] = 0x36 | (1 << 7);
-	pc.buffer[4 + 1] = 6;
-	pc.buffer[4 + 2] = vendor[0];
-	pc.buffer[4 + 3] = vendor[1];
-	pc.buffer[4 + 4] = vendor[2];
-	pc.buffer[4 + 5] = vendor[3];
-	pc.buffer[4 + 6] = 0;
-	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail(drive, &pc))
-		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
-
-}
-
-/*
- * Various unused OnStream commands
- */
-#if ONSTREAM_DEBUG
-static void idetape_onstream_set_retries (ide_drive_t *drive, int retries)
-{
-	idetape_pc_t pc;
-
-	idetape_create_mode_select_cmd(&pc, sizeof(idetape_mode_parameter_header_t) + 4);
-	pc.buffer[0] = 3 + 4;
-	pc.buffer[1] = 0;	/* Medium Type - ignoring */
-	pc.buffer[2] = 0;	/* Reserved */
-	pc.buffer[3] = 0;	/* Block Descriptor Length */
-	pc.buffer[4 + 0] = 0x2f | (1 << 7);
-	pc.buffer[4 + 1] = 2;
-	pc.buffer[4 + 2] = 4;
-	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail(drive, &pc))
-		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
-}
-#endif
-
-/*
- * Configure 32.5KB block size.
- */
-static void idetape_onstream_configure_block_size (ide_drive_t *drive)
-{
-	idetape_pc_t pc;
-	idetape_mode_parameter_header_t *header;
-	idetape_block_size_page_t *bs;
-
-	/*
-	 * Get the current block size from the block size mode page
-	 */
-	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail(drive, &pc))
-		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
-	header = (idetape_mode_parameter_header_t *) pc.buffer;
-	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
-
-#if IDETAPE_DEBUG_INFO
-	printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No");
-	printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No");
-	printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No");
-	printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No");
-#endif /* IDETAPE_DEBUG_INFO */
-
-	/*
-	 * Configure default auto columns mode, 32.5KB block size
-	 */ 
-	bs->one = 1;
-	bs->play32 = 0;
-	bs->play32_5 = 1;
-	bs->record32 = 0;
-	bs->record32_5 = 1;
-	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail(drive, &pc))
-		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
-
-#if ONSTREAM_DEBUG
-	/*
-	 * In debug mode, we want to see as many errors as possible
-	 * to test the error recovery mechanism.
-	 */
-	idetape_onstream_set_retries(drive, 0);
-#endif
-}
-
-/*
  * Use INQUIRY to get the firmware revision
  */
 static void idetape_get_inquiry_results (ide_drive_t *drive)
@@ -5985,63 +4460,10 @@
 	r = tape->firmware_revision;
 	if (*(r + 1) == '.')
 		tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0';
-	else if (tape->onstream)
-		tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 1) - '0') * 10 + *(r + 2) - '0';
 	printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision);
 }
 
 /*
- * Configure the OnStream ATAPI tape drive for default operation
- */
-static void idetape_configure_onstream (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-
-	if (tape->firmware_revision_num < 105) {
-		printk(KERN_INFO "ide-tape: %s: Old OnStream firmware revision detected (%s)\n", tape->name, tape->firmware_revision);
-		printk(KERN_INFO "ide-tape: %s: An upgrade to version 1.05 or above is recommended\n", tape->name);
-	}
-
-	/*
-	 * Configure 32.5KB (data+aux) block size.
-	 */
-	idetape_onstream_configure_block_size(drive);
-
-	/*
-	 * Set vendor name to 'LIN3' for "Linux support version 3".
-	 */
-	idetape_onstream_set_vendor(drive, "LIN3");
-}
-
-/*
- *	idetape_get_mode_sense_parameters asks the tape about its various
- *	parameters. This may work for other drives to???
- */
-static void idetape_onstream_mode_sense_tape_parameter_page(ide_drive_t *drive, int debug)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_pc_t pc;
-	idetape_mode_parameter_header_t *header;
-	onstream_tape_paramtr_page_t *prm;
-	
-	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail(drive, &pc)) {
-		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
-		return;
-	}
-	header = (idetape_mode_parameter_header_t *) pc.buffer;
-	prm = (onstream_tape_paramtr_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
-
-        tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
-        if (debug) {
-	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
-               drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
-        }
-
-        return;
-}
-
-/*
  *	idetape_get_mode_sense_results asks the tape about its various
  *	parameters. In particular, we will adjust our data transfer buffer
  *	size to the recommended value as returned by the tape.
@@ -6084,8 +4506,6 @@
 		tape->tape_block_size = 512;
 	else if (capabilities->blk1024)
 		tape->tape_block_size = 1024;
-	else if (tape->onstream && capabilities->blk32768)
-		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
 	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
@@ -6169,18 +4589,6 @@
 	ide_add_setting(drive,	"pipeline_head_speed_u",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->uncontrolled_pipeline_head_speed,	NULL);
 	ide_add_setting(drive,	"avg_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->avg_speed,		NULL);
 	ide_add_setting(drive,	"debug_level",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->debug_level,		NULL);
-	if (tape->onstream) {
-		ide_add_setting(drive,	"cur_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->cur_frames,		NULL);
-		ide_add_setting(drive,	"max_frames",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->max_frames,		NULL);
-		ide_add_setting(drive,	"insert_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_speed,		NULL);
-		ide_add_setting(drive,	"speed_control",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->speed_control,		NULL);
-		ide_add_setting(drive,	"tape_still_time",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->tape_still_time,		NULL);
-		ide_add_setting(drive,	"max_insert_speed",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->max_insert_speed,	NULL);
-		ide_add_setting(drive,	"insert_size",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->insert_size,		NULL);
-		ide_add_setting(drive,	"capacity",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->capacity,		NULL);
-		ide_add_setting(drive,	"first_frame",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->first_frame_position,		NULL);
-		ide_add_setting(drive,	"logical_blk",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->logical_blk_num,		NULL);
-	}
 }
 
 /*
@@ -6208,11 +4616,9 @@
 	drive->driver_data = tape;
 	/* An ATAPI device ignores DRDY */
 	drive->ready_stat = 0;
-	if (strstr(drive->id->model, "OnStream DI-"))
-		tape->onstream = 1;
 	drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
+	if (HWIF(drive)->pci_dev != NULL) {
 		/*
 		 * These two ide-pci host adapters appear to need DSC overlap disabled.
 		 * This probably needs further analysis.
@@ -6245,10 +4651,6 @@
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
 	idetape_get_blocksize_from_block_descriptor(drive);
-	if (tape->onstream) {
-		idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
-		idetape_configure_onstream(drive);
-	}
 	tape->user_bs_factor = 1;
 	tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	while (tape->stage_size > 0xffff) {
@@ -6257,8 +4659,6 @@
 		tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
 	}
 	stage_size = tape->stage_size;
-	if (tape->onstream)
-		stage_size = 32768 + 512;
 	tape->pages_per_stage = stage_size / PAGE_SIZE;
 	if (stage_size % PAGE_SIZE) {
 		tape->pages_per_stage++;
@@ -6502,3 +4902,4 @@
 
 module_init(idetape_init);
 module_exit(idetape_exit);
+MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
--- diff/drivers/ide/pci/alim15x3.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ide/pci/alim15x3.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/alim15x3.c		Version 0.16	2003/01/02
+ * linux/drivers/ide/pci/alim15x3.c		Version 0.17	2003/01/02
  *
  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -19,6 +19,7 @@
  *	Don't use LBA48 mode on ALi <= 0xC4
  *	Don't poke 0x79 with a non ALi northbridge
  *	Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ *	Allow UDMA6 on revisions > 0xC4
  *
  *  Documentation
  *	Chipset documentation available under NDA only
@@ -406,7 +407,9 @@
 {
 	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
 
-	if (m5229_revision >= 0xC4 && can_ultra) {
+	if (m5229_revision > 0xC4 && can_ultra) {
+		mode = 4;
+	} else if (m5229_revision == 0xC4 && can_ultra) {
 		mode = 3;
 	} else if (m5229_revision >= 0xC2 && can_ultra) {
 		mode = 2;
@@ -439,11 +442,15 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed	= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 speed1		= speed;
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 tmpbyte		= 0x00;
 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
 
+        if (speed == XFER_UDMA_6)
+                speed1 = 0x47;
+
 	if (speed < XFER_UDMA_0) {
 		u8 ultra_enable	= (unit) ? 0x7f : 0xf7;
 		/*
@@ -461,7 +468,7 @@
 		/*
 		 * enable ultra dma and set timing
 		 */
-		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
+		tmpbyte |= ((0x08 | ((4-speed1)&0x07)) << (unit << 2));
 		pci_write_config_byte(dev, m5229_udma, tmpbyte);
 		if (speed >= XFER_UDMA_3) {
 			pci_read_config_byte(dev, 0x4b, &tmpbyte);
@@ -757,7 +764,7 @@
 	hwif->atapi_dma = 1;
 
 	if (m5229_revision > 0x20)
-		hwif->ultra_mask = 0x3f;
+		hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 
--- diff/drivers/ide/pci/siimage.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ide/pci/siimage.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/siimage.c		Version 1.06	June 11, 2003
+ * linux/drivers/ide/pci/siimage.c		Version 1.07	Nov 30, 2003
  *
  * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003		Red Hat <alan@redhat.com>
@@ -1046,6 +1046,27 @@
 	hwif->mmio			= 2;
 }
 
+static int is_dev_seagate_sata(ide_drive_t *drive)
+{
+	const char *s = &drive->id->model[0];
+	unsigned len;
+
+	if (!drive->present)
+		return 0;
+
+	len = strnlen(s, sizeof(drive->id->model));
+
+	if ((len > 4) && (!memcmp(s, "ST", 2))) {
+		if ((!memcmp(s + len - 2, "AS", 2)) ||
+		    (!memcmp(s + len - 3, "ASL", 3))) {
+			printk(KERN_INFO "%s: applying pessimistic Seagate "
+					 "errata fix\n", drive->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /**
  *	init_iops_siimage	-	set up iops
  *	@hwif: interface to set up
@@ -1067,7 +1088,7 @@
 	hwif->hwif_data = 0;
 
 	hwif->rqsize = 128;
-	if (is_sata(hwif))
+	if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0]))
 		hwif->rqsize = 15;
 
 	if (pci_get_drvdata(dev) == NULL)
--- diff/drivers/ieee1394/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -110,8 +110,12 @@
 	tristate "Ethernet over 1394"
 	depends on IEEE1394
 	help
-	  Extremely Experimental! This driver is a Linux specific way to use your
-	  IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394.
+	  This driver implements a functional majority of RFC 2734: IPv4 over
+	  1394.  It will provide IP connectivity with implementations of RFC
+	  2734 found on other operating systems.  It will not communicate with
+	  older versions of this driver found in stock kernels prior to 2.6.3.
+	  This driver is still considered experimental.  It does not yet support
+	  MCAP, therefore multicast support is significantly limited.
 
 config IEEE1394_DV1394
 	tristate "OHCI-DV I/O support"
--- diff/drivers/ieee1394/Makefile	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/ieee1394/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,8 @@
 #
 
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o nodemgr.o oui.o dma.o iso.o
+		 highlevel.o csr.o nodemgr.o oui.o dma.o iso.o \
+		 csr1212.o
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
--- diff/drivers/ieee1394/amdtp.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/amdtp.c	2004-02-18 09:03:59.000000000 +0000
@@ -862,14 +862,14 @@
 
 static void stream_free_packet_lists(struct stream *s)
 {
-	struct list_head *lh, *next;
+	struct packet_list *packet_l, *packet_l_next;
 
 	if (s->current_packet_list != NULL)
 		packet_list_free(s->current_packet_list, s);
-	list_for_each_safe(lh, next, &s->dma_packet_lists)
-		packet_list_free(list_entry(lh, struct packet_list, link), s);
-	list_for_each_safe(lh, next, &s->free_packet_lists)
-		packet_list_free(list_entry(lh, struct packet_list, link), s);
+	list_for_each_entry_safe(packet_l, packet_l_next, &s->dma_packet_lists, link)
+		packet_list_free(packet_l, s);
+	list_for_each_entry_safe(packet_l, packet_l_next, &s->free_packet_lists, link)
+		packet_list_free(packet_l, s);
 	if (s->packet_pool != NULL)
 		pci_pool_destroy(s->packet_pool);
 
--- diff/drivers/ieee1394/csr.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/csr.c	2004-02-18 09:03:59.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/param.h>
 #include <linux/spinlock.h>
 
+#include "csr1212.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
@@ -35,7 +36,10 @@
 module_param(fcp, int, 0444);
 MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
 
+static struct csr1212_keyval *node_cap = NULL;
+
 static void add_host(struct hpsb_host *host);
+static void remove_host(struct hpsb_host *host);
 static void host_reset(struct hpsb_host *host);
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
 		     u64 addr, size_t length, u16 fl);
@@ -49,10 +53,15 @@
 		     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
 static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
 		       u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
+static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+			   u64 addr, size_t length, u16 fl);
+static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
+static void release_addr_range(u64 addr, void *__host);
 
 static struct hpsb_highlevel csr_highlevel = {
 	.name =		"standard registers",
 	.add_host =	add_host,
+	.remove_host =	remove_host,
 	.host_reset =	host_reset,
 };
 
@@ -71,6 +80,15 @@
 	.lock64 = lock64_regs,
 };
 
+static struct hpsb_address_ops config_rom_ops = {
+	.read = read_config_rom,
+};
+
+struct csr1212_bus_ops csr_bus_ops = {
+	.allocate_addr_range =	allocate_addr_range,
+	.release_addr =		release_addr_range,
+};
+
 
 static u16 csr_crc16(unsigned *data, int length)
 {
@@ -162,10 +180,13 @@
 
 static void add_host(struct hpsb_host *host)
 {
+	struct csr1212_keyval *root;
+	quadlet_t bus_info[CSR_BUS_INFO_SIZE];
+
 	hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
 				CSR_REGISTER_BASE,
 				CSR_REGISTER_BASE + CSR_CONFIG_ROM);
-	hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
+	hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
 				CSR_REGISTER_BASE + CSR_CONFIG_ROM,
 				CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
 	if (fcp) {
@@ -182,8 +203,6 @@
 
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
-        host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -202,43 +221,100 @@
 			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
 		}
 	}
+
+	if (host->csr.max_rec >= 9)
+		host->csr.max_rom = 2;
+	else if (host->csr.max_rec >= 5)
+		host->csr.max_rom = 1;
+	else
+		host->csr.max_rom = 0;
+
+	host->csr.generation = 2;
+
+	bus_info[1] = __constant_cpu_to_be32(0x31333934);
+	bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) |
+				  (1 << CSR_CMC_SHIFT) |
+				  (1 << CSR_ISC_SHIFT) |
+				  (0 << CSR_BMC_SHIFT) |
+				  (0 << CSR_PMC_SHIFT) |
+				  (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
+				  (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
+				  (host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
+				  (host->csr.generation << CSR_GENERATION_SHIFT) |
+				  host->csr.lnk_spd);
+
+	bus_info[3] = cpu_to_be32(host->csr.guid_hi);
+	bus_info[4] = cpu_to_be32(host->csr.guid_lo);
+
+	/* The hardware copy of the bus info block will be set later when a
+	 * bus reset is issued. */
+
+	csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
+
+	host->csr.rom->max_rom = host->csr.max_rom;
+
+	root = host->csr.rom->root_kv;
+
+	if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
+		HPSB_ERR("Failed to attach Node Capabilities to root directory");
+	}
+
+	host->update_config_rom = 1;
 }
 
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
-	size_t size, unsigned char rom_version)
+static void remove_host(struct hpsb_host *host)
 {
-	unsigned long flags;
-	int ret;
+	quadlet_t bus_info[CSR_BUS_INFO_SIZE];
 
-        spin_lock_irqsave(&host->csr.lock, flags); 
-        if (rom_version != host->csr.rom_version)
-                 ret = -1;
-        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
-                 ret = -2;
-        else {
-                 memcpy(host->csr.rom,new_rom,size);
-                 host->csr.rom_size=size;
-                 host->csr.rom_version++;
-                 ret=0;
-        }
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-        return ret;
+	bus_info[1] = __constant_cpu_to_be32(0x31333934);
+	bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
+				  (0 << CSR_CMC_SHIFT) |
+				  (0 << CSR_ISC_SHIFT) |
+				  (0 << CSR_BMC_SHIFT) |
+				  (0 << CSR_PMC_SHIFT) |
+				  (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
+				  (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
+				  (0 << CSR_MAX_ROM_SHIFT) |
+				  (0 << CSR_GENERATION_SHIFT) |
+				  host->csr.lnk_spd);
+
+	bus_info[3] = cpu_to_be32(host->csr.guid_hi);
+	bus_info[4] = cpu_to_be32(host->csr.guid_lo);
+
+	csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
+
+	csr1212_init_local_csr(host->csr.rom, bus_info, 0);
+	host->update_config_rom = 1;
 }
 
-int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
-	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t buffersize, unsigned char rom_version)
 {
 	unsigned long flags;
 	int ret;
 
+	HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
+
         spin_lock_irqsave(&host->csr.lock, flags); 
-        *rom_version=host->csr.rom_version;
-        *rom_size=host->csr.rom_size;
-        if (buffersize < host->csr.rom_size)
-                 ret = -1;
+	if (rom_version != host->csr.generation)
+                ret = -1;
+	else if (buffersize > host->csr.rom->cache_head->size)
+		ret = -2;
         else {
-                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
-                 ret=0;
+		/* Just overwrite the generated ConfigROM image with new data,
+		 * it can be regenerated later. */
+		memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
+		host->csr.rom->cache_head->len = buffersize;
+
+		if (host->driver->set_hw_config_rom)
+			host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
+		/* Increment the generation number to keep some sort of sync
+		 * with the newer ConfigROM manipulation method. */
+		host->csr.generation++;
+		if (host->csr.generation > 0xf || host->csr.generation < 2)
+			host->csr.generation = 2;
+		ret=0;
         }
         spin_unlock_irqrestore(&host->csr.lock, flags);
         return ret;
@@ -255,13 +331,7 @@
 
         spin_lock_irqsave(&host->csr.lock, flags); 
 
-        if (csraddr < CSR_TOPOLOGY_MAP) {
-                if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
-                        spin_unlock_irqrestore(&host->csr.lock, flags);
-                        return RCODE_ADDRESS_ERROR;
-                }
-                src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM;
-        } else if (csraddr < CSR_SPEED_MAP) {
+	if (csraddr < CSR_SPEED_MAP) {
                 src = ((char *)host->csr.topology_map) + csraddr 
                         - CSR_TOPOLOGY_MAP;
         } else {
@@ -738,14 +808,52 @@
         return RCODE_COMPLETE;
 }
 
+static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+			   u64 addr, size_t length, u16 fl)
+{
+	u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
 
+	if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
+		return RCODE_COMPLETE;
+	else
+		return RCODE_ADDRESS_ERROR;
+}
 
-void init_csr(void)
+static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
 {
+ 	struct hpsb_host *host = (struct hpsb_host*)__host;
+
+	return hpsb_allocate_and_register_addrspace(&csr_highlevel,
+						    host,
+						    &config_rom_ops,
+						    size, alignment,
+						    CSR1212_UNITS_SPACE_BASE,
+						    CSR1212_UNITS_SPACE_END);
+}
+
+static void release_addr_range(u64 addr, void *__host)
+{
+ 	struct hpsb_host *host = (struct hpsb_host*)__host;
+	hpsb_unregister_addrspace(&csr_highlevel, host, addr);
+}
+
+
+int init_csr(void)
+{
+	node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
+	if (!node_cap) {
+		HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
+		return -ENOMEM;
+	}
+
 	hpsb_register_highlevel(&csr_highlevel);
+
+	return 0;
 }
 
 void cleanup_csr(void)
 {
+	if (node_cap)
+		csr1212_release_keyval(node_cap);
         hpsb_unregister_highlevel(&csr_highlevel);
 }
--- diff/drivers/ieee1394/csr.h	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/ieee1394/csr.h	2004-02-18 09:03:59.000000000 +0000
@@ -6,6 +6,8 @@
 #include <linux/sched.h>
 #endif
 
+#include "csr1212.h"
+
 #define CSR_REGISTER_BASE  0xfffff0000000ULL
 
 /* register offsets relative to CSR_REGISTER_BASE */
@@ -34,6 +36,27 @@
 #define CSR_SPEED_MAP             0x2000
 #define CSR_SPEED_MAP_END         0x3000
 
+/* IEEE 1394 bus specific Configuration ROM Key IDs */
+#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
+
+/* IEEE 1394 Bus Inforamation Block specifics */
+#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
+
+#define CSR_IRMC_SHIFT 31
+#define CSR_CMC_SHIFT  30
+#define CSR_ISC_SHIFT  29
+#define CSR_BMC_SHIFT  28
+#define CSR_PMC_SHIFT  27
+#define CSR_CYC_CLK_ACC_SHIFT 16
+#define CSR_MAX_REC_SHIFT 12
+#define CSR_MAX_ROM_SHIFT 8
+#define CSR_GENERATION_SHIFT 4
+
+#define CSR_SET_BUS_INFO_GENERATION(csr, gen)				\
+	((csr)->bus_info_data[2] =					\
+		cpu_to_be32((be32_to_cpu((csr)->bus_info_data[2]) &	\
+			     ~(0xf << CSR_GENERATION_SHIFT)) |          \
+			    (gen) << CSR_GENERATION_SHIFT))
 
 struct csr_control {
         spinlock_t lock;
@@ -49,17 +72,25 @@
         quadlet_t channels_available_hi, channels_available_lo;
 	quadlet_t broadcast_channel;
 
-        quadlet_t *rom;
-        size_t rom_size;
-        unsigned char rom_version;
+	/* Bus Info */
+	quadlet_t guid_hi, guid_lo;
+	u8 cyc_clk_acc;
+	u8 max_rec;
+	u8 max_rom;
+	u8 generation;	/* Only use values between 0x2 and 0xf */
+	u8 lnk_spd;
+
+	unsigned long gen_timestamp[16];
 
+	struct csr1212_csr *rom;
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
 };
 
+extern struct csr1212_bus_ops csr_bus_ops;
 
-void init_csr(void);
+int init_csr(void);
 void cleanup_csr(void);
 
 #endif /* _IEEE1394_CSR_H */
--- diff/drivers/ieee1394/dv1394.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/dv1394.c	2004-02-18 09:03:59.000000000 +0000
@@ -1801,15 +1801,12 @@
 		
 	} else {
 		/* look up the card by ID */
-		
-		struct list_head *lh;
 		unsigned long flags;
 		
 		spin_lock_irqsave(&dv1394_cards_lock, flags);
 		if (!list_empty(&dv1394_cards)) {
 			struct video_card *p;
-			list_for_each(lh, &dv1394_cards) {
-				p = list_entry(lh, struct video_card, list);
+			list_for_each_entry(p, &dv1394_cards, list) {
 				if ((p->id) == ieee1394_file_to_instance(file)) {
 					video = p;
 					break;
@@ -2374,7 +2371,6 @@
 	struct ti_ohci *ohci;
 	struct video_card *video = NULL;
 	unsigned long flags;
-	struct list_head *lh;
 	
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2386,8 +2382,7 @@
 	/* find the corresponding video_cards */
 	spin_lock_irqsave(&dv1394_cards_lock, flags);
 	if (!list_empty(&dv1394_cards)) {
-		list_for_each(lh, &dv1394_cards) {
-			video = list_entry(lh, struct video_card, list);
+		list_for_each_entry(video, &dv1394_cards, list) {
 			if ((video->id >> 2) == ohci->id)
 				break;
 		}
--- diff/drivers/ieee1394/eth1394.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/eth1394.c	2004-02-18 09:03:59.000000000 +0000
@@ -29,7 +29,6 @@
  *
  * TODO:
  * RFC 2734 related:
- * - Add Config ROM entry
  * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
  *
  * Non-RFC 2734 related:
@@ -38,7 +37,6 @@
  * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
  * - Stability improvements
  * - Performance enhancements
- * - Change hardcoded 1394 bus address region to a dynamic memory space allocation
  * - Consider garbage collecting old partial datagrams after X amount of time
  */
 
@@ -69,6 +67,7 @@
 #include <asm/semaphore.h>
 #include <net/arp.h>
 
+#include "csr1212.h"
 #include "ieee1394_types.h"
 #include "ieee1394_core.h"
 #include "ieee1394_transactions.h"
@@ -89,7 +88,7 @@
 #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
 
 static char version[] __devinitdata =
-	"$Rev: 1096 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1133 $ Ben Collins <bcollins@debian.org>";
 
 struct fragment_info {
 	struct list_head list;
@@ -107,8 +106,35 @@
 	struct list_head frag_info;
 };
 
+static struct csr1212_keyval *eth1394_ud = NULL;
+
+struct pdg_list {
+	struct list_head list;		/* partial datagram list per node	*/
+	unsigned int sz;		/* partial datagram list size per node	*/
+	spinlock_t lock;		/* partial datagram lock		*/
+};
+
+struct eth1394_host_info {
+	struct hpsb_host *host;
+	struct net_device *dev;
+};
+
+struct eth1394_node_ref {
+	struct unit_directory *ud;
+	struct list_head list;
+};
+
+struct eth1394_node_info {
+	u16 maxpayload;			/* Max payload			*/
+	u8 sspd;			/* Max speed			*/
+	u64 fifo;			/* FIFO address			*/
+	struct pdg_list pdg;		/* partial RX datagram lists	*/
+	int dgl;			/* Outgoing datagram label	*/
+};
+
 /* Our ieee1394 highlevel driver */
-static const char driver_name[] = "eth1394";
+#define ETH1394_DRIVER_NAME "IP/1394"
+static const char driver_name[] = ETH1394_DRIVER_NAME;
 
 static kmem_cache_t *packet_task_cache;
 
@@ -188,94 +214,36 @@
 };
 
 
-static void eth1394_iso_shutdown(struct eth1394_priv *priv)
-{
-	priv->bc_state = ETHER1394_BC_CLOSED;
-
-	if (priv->iso != NULL) {
-		if (!in_interrupt())
-			hpsb_iso_shutdown(priv->iso);
-		priv->iso = NULL;
-	}
-}
-
-static int ether1394_init_bc(struct net_device *dev)
-{
-	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-
-	/* First time sending?  Need a broadcast channel for ARP and for
-	 * listening on */
-	if (priv->bc_state == ETHER1394_BC_CHECK) {
-		quadlet_t bc;
-
-		/* Get the local copy of the broadcast channel and check its
-		 * validity (the IRM should validate it for us) */
-
-		bc = priv->host->csr.broadcast_channel;
-
-		if ((bc & 0xc0000000) != 0xc0000000) {
-			/* broadcast channel not validated yet */
-			ETH1394_PRINT(KERN_WARNING, dev->name,
-				      "Error BROADCAST_CHANNEL register valid "
-				      "bit not set, can't send IP traffic\n");
-
-			eth1394_iso_shutdown(priv);
-
-			return -EAGAIN;
-		}
-		if (priv->broadcast_channel != (bc & 0x3f)) {
-			/* This really shouldn't be possible, but just in case
-			 * the IEEE 1394 spec changes regarding broadcast
-			 * channels in the future. */
-
-			eth1394_iso_shutdown(priv);
-
-			if (in_interrupt())
-				return -EAGAIN;
-
-			priv->broadcast_channel = bc & 0x3f;
-			ETH1394_PRINT(KERN_INFO, dev->name,
-				      "Changing to broadcast channel %d...\n",
-				      priv->broadcast_channel);
-
-			priv->iso = hpsb_iso_recv_init(priv->host, 16 * 4096,
-						       16, priv->broadcast_channel,
-						       HPSB_ISO_DMA_PACKET_PER_BUFFER, 1, ether1394_iso);
-			if (priv->iso == NULL) {
-				ETH1394_PRINT(KERN_ERR, dev->name,
-					      "failed to change broadcast "
-					      "channel\n");
-				return -EAGAIN;
-			}
-		}
-		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
-			ETH1394_PRINT(KERN_ERR, dev->name,
-				      "Could not start data stream reception\n");
-
-			eth1394_iso_shutdown(priv);
-
-			return -EAGAIN;
-		}
-		priv->bc_state = ETHER1394_BC_OPENED;
-	}
-    
-	return 0;
-}
-
 /* This is called after an "ifup" */
 static int ether1394_open (struct net_device *dev)
 {
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	unsigned long flags;
-	int ret;
+	int ret = 0;
 
 	/* Something bad happened, don't even try */
-	if (priv->bc_state == ETHER1394_BC_CLOSED)
-		return -EAGAIN;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = ether1394_init_bc(dev);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	if (priv->bc_state == ETHER1394_BC_ERROR) {
+		/* we'll try again */
+		priv->iso = hpsb_iso_recv_init(priv->host,
+					       ETHER1394_GASP_BUFFERS * 2 *
+					       (1 << (priv->host->csr.max_rec +
+						      1)),
+					       ETHER1394_GASP_BUFFERS,
+					       priv->broadcast_channel,
+					       HPSB_ISO_DMA_PACKET_PER_BUFFER,
+					       1, ether1394_iso);
+		if (priv->iso == NULL) {
+			ETH1394_PRINT(KERN_ERR, dev->name,
+				      "Could not allocate isochronous receive "
+				      "context for the broadcast channel\n");
+			priv->bc_state = ETHER1394_BC_ERROR;
+			ret = -EAGAIN;
+		} else {
+			if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
+				priv->bc_state = ETHER1394_BC_STOPPED;
+			else
+				priv->bc_state = ETHER1394_BC_RUNNING;
+		}
+	}
 
 	if (ret)
 		return ret;
@@ -312,66 +280,227 @@
 static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	int phy_id = NODEID_TO_NODE(priv->host->node_id);
 
-	if ((new_mtu < 68) || (new_mtu > min(ETH1394_DATA_LEN, (int)(priv->maxpayload[phy_id] -
-					     (sizeof(union eth1394_hdr) + ETHER1394_GASP_OVERHEAD)))))
+	if ((new_mtu < 68) ||
+	    (new_mtu > min(ETH1394_DATA_LEN,
+			   (int)((1 << (priv->host->csr.max_rec + 1)) -
+				 (sizeof(union eth1394_hdr) +
+				  ETHER1394_GASP_OVERHEAD)))))
 		return -EINVAL;
 	dev->mtu = new_mtu;
 	return 0;
 }
 
-static inline void ether1394_register_limits(int nodeid, u16 maxpayload,
-					     unsigned char sspd, u64 eui, u64 fifo,
-					     struct eth1394_priv *priv)
+
+/******************************************
+ * 1394 bus activity functions
+ ******************************************/
+
+static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl,
+						  struct unit_directory *ud)
+{
+	struct eth1394_node_ref *node;
+
+	list_for_each_entry(node, inl, list)
+		if (node->ud == ud)
+			return node;
+
+	return NULL;
+}
+
+static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl,
+						       u64 guid)
 {
-	if (nodeid < 0 || nodeid >= ALL_NODES) {
-		ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid);
-		return;
+	struct eth1394_node_ref *node;
+
+	list_for_each_entry(node, inl, list)
+		if (node->ud->ne->guid == guid)
+			return node;
+
+	return NULL;
+}
+
+static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
+							 nodeid_t nodeid)
+{
+	struct eth1394_node_ref *node;
+	list_for_each_entry(node, inl, list) {
+		if (node->ud->ne->nodeid == nodeid)
+			return node;
 	}
 
-	priv->maxpayload[nodeid]	= maxpayload;
-	priv->sspd[nodeid]		= sspd;
-	priv->fifo[nodeid]		= fifo;
-	priv->eui[nodeid]		= eui;
+	return NULL;
+}
 
-	priv->maxpayload[ALL_NODES] = min(priv->maxpayload[ALL_NODES], maxpayload);
-	priv->sspd[ALL_NODES] = min(priv->sspd[ALL_NODES], sspd);
+static int eth1394_probe(struct device *dev)
+{
+	struct unit_directory *ud;
+	struct eth1394_host_info *hi;
+	struct eth1394_priv *priv;
+	struct eth1394_node_ref *new_node;
+	struct eth1394_node_info *node_info;
 
-	return;
+	ud = container_of(dev, struct unit_directory, device);
+
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
+	if (!hi)
+		return -ENOENT;
+
+	new_node = kmalloc(sizeof(struct eth1394_node_ref),
+			   in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!new_node)
+		return -ENOMEM;
+
+	node_info = kmalloc(sizeof(struct eth1394_node_info),
+			    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!node_info) {
+		kfree(new_node);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&node_info->pdg.lock);
+	INIT_LIST_HEAD(&node_info->pdg.list);
+	node_info->pdg.sz = 0;
+	node_info->fifo = ETHER1394_INVALID_ADDR;
+
+	ud->device.driver_data = node_info;
+	new_node->ud = ud;
+
+	priv = (struct eth1394_priv *)hi->dev->priv;
+	list_add_tail(&new_node->list, &priv->ip_node_list);
+
+	return 0;
+}
+
+static int eth1394_remove(struct device *dev)
+{
+	struct unit_directory *ud;
+	struct eth1394_host_info *hi;
+	struct eth1394_priv *priv;
+	struct eth1394_node_ref *old_node;
+	struct eth1394_node_info *node_info;
+	struct list_head *lh, *n;
+	unsigned long flags;
+
+	ud = container_of(dev, struct unit_directory, device);
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
+	if (!hi)
+		return -ENOENT;
+
+	priv = (struct eth1394_priv *)hi->dev->priv;
+
+	old_node = eth1394_find_node(&priv->ip_node_list, ud);
+
+	if (old_node) {
+		list_del(&old_node->list);
+		kfree(old_node);
+
+		node_info = (struct eth1394_node_info*)ud->device.driver_data;
+
+		spin_lock_irqsave(&node_info->pdg.lock, flags);
+		/* The partial datagram list should be empty, but we'll just
+		 * make sure anyway... */
+		list_for_each_safe(lh, n, &node_info->pdg.list) {
+			purge_partial_datagram(lh);
+		}
+		spin_unlock_irqrestore(&node_info->pdg.lock, flags);
+
+		kfree(node_info);
+		ud->device.driver_data = NULL;
+	}
+	return 0;
 }
 
+static void eth1394_update(struct unit_directory *ud)
+{
+	struct eth1394_host_info *hi;
+	struct eth1394_priv *priv;
+	struct eth1394_node_ref *node;
+	struct eth1394_node_info *node_info;
+
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
+	if (!hi)
+		return;
+
+	priv = (struct eth1394_priv *)hi->dev->priv;
+
+	node = eth1394_find_node(&priv->ip_node_list, ud);
+
+	if (!node) {
+		node = kmalloc(sizeof(struct eth1394_node_ref),
+			       in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+		if (!node)
+			return;
+
+
+		node_info = kmalloc(sizeof(struct eth1394_node_info),
+				    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+
+		spin_lock_init(&node_info->pdg.lock);
+		INIT_LIST_HEAD(&node_info->pdg.list);
+		node_info->pdg.sz = 0;
+
+		ud->device.driver_data = node_info;
+		node->ud = ud;
+
+		priv = (struct eth1394_priv *)hi->dev->priv;
+		list_add_tail(&node->list, &priv->ip_node_list);
+	}
+}
+
+
+static struct ieee1394_device_id eth1394_id_table[] = {
+	{
+		.match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
+				IEEE1394_MATCH_VERSION),
+		.specifier_id =	ETHER1394_GASP_SPECIFIER_ID,
+		.version = ETHER1394_GASP_VERSION,
+	},
+	{}
+};
+
+static struct hpsb_protocol_driver eth1394_proto_driver = {
+	.name		= "IPv4 over 1394 Driver",
+	.id_table	= eth1394_id_table,
+	.update		= eth1394_update,
+	.driver		= {
+		.name		= ETH1394_DRIVER_NAME,
+		.bus		= &ieee1394_bus_type,
+		.probe		= eth1394_probe,
+		.remove		= eth1394_remove,
+	},
+};
+
+
 static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
 {
 	unsigned long flags;
 	int i;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
 	struct hpsb_host *host = priv->host;
-	int phy_id = NODEID_TO_NODE(host->node_id);
-	u64 guid = *((u64*)&(host->csr.rom[3]));
-	u16 maxpayload = 1 << (((be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf) + 1);
+	u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3]));
+	u16 maxpayload = 1 << (host->csr.max_rec + 1);
+	int max_speed = IEEE1394_SPEED_MAX;
 
 	spin_lock_irqsave (&priv->lock, flags);
 
-	/* Clear the speed/payload/offset tables */
-	memset (priv->maxpayload, 0, sizeof (priv->maxpayload));
-	memset (priv->sspd, 0, sizeof (priv->sspd));
-	memset (priv->fifo, 0, sizeof (priv->fifo));
-
-	priv->sspd[ALL_NODES] = ETH1394_SPEED_DEF;
-	priv->maxpayload[ALL_NODES] = eth1394_speedto_maxpayload[priv->sspd[ALL_NODES]];
-
-	priv->bc_state = ETHER1394_BC_CHECK;
-
-	/* Register our limits now */
-	ether1394_register_limits(phy_id, maxpayload,
-				  host->speed_map[(phy_id << 6) + phy_id],
-				  guid, ETHER1394_REGION_ADDR, priv);
+	memset(priv->ud_list, 0, sizeof(struct node_entry*) * ALL_NODES);
+	priv->bc_maxpayload = 512;
+
+	/* Determine speed limit */
+	for (i = 0; i < host->node_count; i++)
+		if (max_speed > host->speed_map[NODEID_TO_NODE(host->node_id) *
+						64 + i])
+			max_speed = host->speed_map[NODEID_TO_NODE(host->node_id) *
+						    64 + i];
+	priv->bc_sspd = max_speed;
 
 	/* We'll use our maxpayload as the default mtu */
 	if (set_mtu) {
-		dev->mtu = min(ETH1394_DATA_LEN, (int)(priv->maxpayload[phy_id] -
-			       (sizeof(union eth1394_hdr) + ETHER1394_GASP_OVERHEAD)));
+		dev->mtu = min(ETH1394_DATA_LEN,
+			       (int)(maxpayload -
+				     (sizeof(union eth1394_hdr) +
+				      ETHER1394_GASP_OVERHEAD)));
 
 		/* Set our hardware address while we're at it */
 		*(u64*)dev->dev_addr = guid;
@@ -379,20 +508,6 @@
 	}
 
 	spin_unlock_irqrestore (&priv->lock, flags);
-
-	for (i = 0; i < ALL_NODES; i++) {
-		struct list_head *lh, *n;
-
-		spin_lock_irqsave(&priv->pdg[i].lock, flags);
-		if (!set_mtu) {
-			list_for_each_safe(lh, n, &priv->pdg[i].list) {
-				purge_partial_datagram(lh);
-			}
-		}
-		INIT_LIST_HEAD(&(priv->pdg[i].list));
-		priv->pdg[i].sz = 0;
-		spin_unlock_irqrestore(&priv->pdg[i].lock, flags);
-	}
 }
 
 /* This function is called right before register_netdev */
@@ -432,15 +547,21 @@
  */
 static void ether1394_add_host (struct hpsb_host *host)
 {
-	int i;
-	struct host_info *hi = NULL;
+	struct eth1394_host_info *hi = NULL;
 	struct net_device *dev = NULL;
 	struct eth1394_priv *priv;
 	static int version_printed = 0;
 
-	hpsb_register_addrspace(&eth1394_highlevel, host, &addr_ops,
-				ETHER1394_REGION_ADDR,
-				ETHER1394_REGION_ADDR_END);
+	u64 fifo_addr;
+
+	fifo_addr = hpsb_allocate_and_register_addrspace(&eth1394_highlevel,
+							 host,
+							 &addr_ops,
+							 ETHER1394_REGION_ADDR_LEN,
+							 ETHER1394_REGION_ADDR_LEN,
+							 -1, -1);
+	if (fifo_addr == ~0ULL)
+		goto out;
 
 	if (version_printed++ == 0)
 		ETH1394_PRINT_G (KERN_INFO, "%s\n", version);
@@ -461,14 +582,11 @@
 
 	priv = (struct eth1394_priv *)dev->priv;
 
+	INIT_LIST_HEAD(&priv->ip_node_list);
+
 	spin_lock_init(&priv->lock);
 	priv->host = host;
-
-	for (i = 0; i < ALL_NODES; i++) {
-                spin_lock_init(&priv->pdg[i].lock);
-		INIT_LIST_HEAD(&priv->pdg[i].list);
-		priv->pdg[i].sz = 0;
-	}
+	priv->local_fifo = fifo_addr;
 
 	hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
 
@@ -496,10 +614,30 @@
 	 * be checked when the eth device is opened. */
 	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
 
-	priv->iso = hpsb_iso_recv_init(host, 16 * 4096, 16, priv->broadcast_channel,
-					HPSB_ISO_DMA_PACKET_PER_BUFFER, 1, ether1394_iso);
+	priv->iso = hpsb_iso_recv_init(host, (ETHER1394_GASP_BUFFERS * 2 *
+					      (1 << (host->csr.max_rec + 1))),
+				       ETHER1394_GASP_BUFFERS,
+				       priv->broadcast_channel,
+				       HPSB_ISO_DMA_PACKET_PER_BUFFER,
+				       1, ether1394_iso);
 	if (priv->iso == NULL) {
-		priv->bc_state = ETHER1394_BC_CLOSED;
+		ETH1394_PRINT(KERN_ERR, dev->name,
+			      "Could not allocate isochronous receive context "
+			      "for the broadcast channel\n");
+		priv->bc_state = ETHER1394_BC_ERROR;
+	} else {
+		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
+			priv->bc_state = ETHER1394_BC_STOPPED;
+		else
+			priv->bc_state = ETHER1394_BC_RUNNING;
+	}
+
+	if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
+					       eth1394_ud) != CSR1212_SUCCESS) {
+		ETH1394_PRINT (KERN_ERR, dev->name,
+			       "Cannot attach IP 1394 Unit Directory to "
+			       "Config ROM\n");
+		goto out;
 	}
 	return;
 
@@ -515,12 +653,21 @@
 /* Remove a card from our list */
 static void ether1394_remove_host (struct hpsb_host *host)
 {
-	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-
+	struct eth1394_host_info *hi;
+	
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 	if (hi != NULL) {
 		struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv;
 
-		eth1394_iso_shutdown(priv);
+		hpsb_unregister_addrspace(&eth1394_highlevel, host,
+					  priv->local_fifo);
+
+		if (priv->iso != NULL) 
+			hpsb_iso_shutdown(priv->iso);
+
+		csr1212_detach_keyval_from_directory(hi->host->csr.rom->root_kv,
+						     eth1394_ud);
+		hi->host->update_config_rom = 1;
 
 		if (hi->dev) {
 			unregister_netdev (hi->dev);
@@ -534,18 +681,42 @@
 /* A reset has just arisen */
 static void ether1394_host_reset (struct hpsb_host *host)
 {
-	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
+	struct eth1394_host_info *hi;
+	struct eth1394_priv *priv;
 	struct net_device *dev;
+	struct list_head *lh, *n;
+	struct eth1394_node_ref *node;
+	struct eth1394_node_info *node_info;
+	unsigned long flags;
+
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 
 	/* This can happen for hosts that we don't use */
 	if (hi == NULL)
 		return;
 
 	dev = hi->dev;
+	priv = (struct eth1394_priv *)dev->priv;
 
 	/* Reset our private host data, but not our mtu */
 	netif_stop_queue (dev);
 	ether1394_reset_priv (dev, 0);
+
+	list_for_each_entry(node, &priv->ip_node_list, list) {
+		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+
+		spin_lock_irqsave(&node_info->pdg.lock, flags);
+
+		list_for_each_safe(lh, n, &node_info->pdg.list) {
+			purge_partial_datagram(lh);
+		}
+
+		INIT_LIST_HEAD(&(node_info->pdg.list));
+		node_info->pdg.sz = 0;
+
+		spin_unlock_irqrestore(&node_info->pdg.lock, flags);
+	}
+
 	netif_wake_queue (dev);
 }
 
@@ -622,7 +793,8 @@
 static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
-	struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) + 6);
+	struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) +
+						      (16 - ETH1394_HLEN));
 	struct net_device *dev = neigh->dev;
 
 	if (type == __constant_htons(ETH_P_802_3)) {
@@ -641,7 +813,7 @@
 					  struct net_device *dev,
 					  unsigned char * haddr)
 {
-	memcpy(((u8*)hh->hh_data) + 6, haddr, dev->addr_len);
+	memcpy(((u8*)hh->hh_data) + (16 - ETH1394_HLEN), haddr, dev->addr_len);
 }
 
 static int ether1394_mac_addr(struct net_device *dev, void *p)
@@ -650,7 +822,7 @@
 		return -EBUSY;
 
 	/* Not going to allow setting the MAC address, we really need to use
-	 * the real one suppliled by the hardware */
+	 * the real one supplied by the hardware */
 	 return -EINVAL;
  }
 
@@ -710,31 +882,37 @@
 	if (destid == (LOCAL_BUS | ALL_NODES))
 		dest_hw = ~0ULL;  /* broadcast */
 	else
-		dest_hw = priv->eui[NODEID_TO_NODE(destid)];
+		dest_hw = cpu_to_be64((((u64)priv->host->csr.guid_hi) << 32) |
+				      priv->host->csr.guid_lo);
 
 	/* If this is an ARP packet, convert it. First, we want to make
 	 * use of some of the fields, since they tell us a little bit
 	 * about the sending machine.  */
 	if (ether_type == __constant_htons (ETH_P_ARP)) {
-		unsigned long flags;
 		struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data;
 		struct arphdr *arp = (struct arphdr *)skb->data;
 		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
 		u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
 			ntohl(arp1394->fifo_lo);
-		u8 host_max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >>
-				   12) & 0xf;
-		u8 max_rec = min(host_max_rec, (u8)(arp1394->max_rec));
+		u8 max_rec = min(priv->host->csr.max_rec,
+				 (u8)(arp1394->max_rec));
 		u16 maxpayload = min(eth1394_speedto_maxpayload[arp1394->sspd],
 				     (u16)(1 << (max_rec + 1)));
+		struct eth1394_node_ref *node;
+		struct eth1394_node_info *node_info;
 
+		node = eth1394_find_node_guid(&priv->ip_node_list,
+					      be64_to_cpu(arp1394->s_uniq_id));
+		if (!node) {
+			return 0;
+		}
+
+		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
 
 		/* Update our speed/payload/fifo_offset table */
-		spin_lock_irqsave (&priv->lock, flags);
-		ether1394_register_limits(NODEID_TO_NODE(srcid), maxpayload,
-					  arp1394->sspd, arp1394->s_uniq_id,
-					  fifo_addr, priv);
-		spin_unlock_irqrestore (&priv->lock, flags);
+		node_info->maxpayload =	maxpayload;
+		node_info->sspd =	arp1394->sspd;
+		node_info->fifo =	fifo_addr;
 
 		/* Now that we're done with the 1394 specific stuff, we'll
 		 * need to alter some of the data.  Believe it or not, all
@@ -743,9 +921,8 @@
 		 * in and the hardware address length set to 8.
 		 *
 		 * IMPORTANT: The code below overwrites 1394 specific data
-		 * needed above data so keep the call to
-		 * ether1394_register_limits() before munging the data for the
-		 * higher level IP stack. */
+		 * needed above so keep the munging of the data for the
+		 * higher level IP stack last. */
 
 		arp->ar_hln = 8;
 		arp_ptr += arp->ar_hln;		/* skip over sender unique id */
@@ -754,9 +931,9 @@
 
 		if (arp->ar_op == 1)
 			/* just set ARP req target unique ID to 0 */
-			memset(arp_ptr, 0, ETH1394_ALEN);
+			*((u64*)arp_ptr) = 0;
 		else
-			memcpy(arp_ptr, dev->dev_addr, ETH1394_ALEN);
+			*((u64*)arp_ptr) = *((u64*)dev->dev_addr);
 	}
 
 	/* Now add the ethernet header. */
@@ -769,12 +946,9 @@
 
 static inline int fragment_overlap(struct list_head *frag_list, int offset, int len)
 {
-	struct list_head *lh;
 	struct fragment_info *fi;
 
-	list_for_each(lh, frag_list) {
-		fi = list_entry(lh, struct fragment_info, list);
-
+	list_for_each_entry(fi, frag_list, list) {
 		if ( ! ((offset > (fi->offset + fi->len - 1)) ||
 		       ((offset + len - 1) < fi->offset)))
 			return 1;
@@ -784,13 +958,11 @@
 
 static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
 {
-	struct list_head *lh;
 	struct partial_datagram *pd;
 
-	list_for_each(lh, pdgl) {
-		pd = list_entry(lh, struct partial_datagram, list);
+	list_for_each_entry(pd, pdgl, list) {
 		if (pd->dgl == dgl)
-			return lh;
+			return &pd->list;
 	}
 	return NULL;
 }
@@ -939,12 +1111,29 @@
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	struct eth1394_priv *priv;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
 	union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
 	u16 ether_type = 0;  /* initialized to clear warning */
 	int hdr_len;
+	struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
+	struct eth1394_node_info *node_info;
 
-	priv = (struct eth1394_priv *)dev->priv;
+	if (!ud) {
+		struct eth1394_node_ref *node;
+		node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
+		if (!node) {
+			HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
+				   "lookup failure: " NODE_BUS_FMT,
+				   NODE_BUS_ARGS(priv->host, srcid));
+			priv->stats.rx_dropped++;
+			return -1;
+		}
+		ud = node->ud;
+
+		priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
+	}
+
+	node_info = (struct eth1394_node_info*)ud->device.driver_data;
 
 	/* First, did we receive a fragmented or unfragmented datagram? */
 	hdr->words.word1 = ntohs(hdr->words.word1);
@@ -975,8 +1164,7 @@
 		int dg_size;
 		int dgl;
 		int retval;
-		int sid = NODEID_TO_NODE(srcid);
-                struct pdg_list *pdg = &(priv->pdg[sid]);
+		struct pdg_list *pdg = &(node_info->pdg);
 
 		hdr->words.word3 = ntohs(hdr->words.word3);
 		/* The 4th header word is reserved so no need to do ntohs() */
@@ -1110,8 +1298,9 @@
 static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
 			   quadlet_t *data, u64 addr, size_t len, u16 flags)
 {
-	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
+	struct eth1394_host_info *hi;
 
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 	if (hi == NULL) {
 		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
 				host->driver->name);
@@ -1128,7 +1317,7 @@
 {
 	quadlet_t *data;
 	char *buf;
-	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
+	struct eth1394_host_info *hi;
 	struct net_device *dev;
 	struct eth1394_priv *priv;
 	unsigned int len;
@@ -1137,6 +1326,7 @@
 	int i;
 	int nready;
 
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
 	if (hi == NULL) {
 		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
 				iso->host->driver->name);
@@ -1193,7 +1383,6 @@
 					    struct net_device *dev)
 {
 	struct eth1394_priv *priv = (struct eth1394_priv *)(dev->priv);
-	u16 phy_id = NODEID_TO_NODE(priv->host->node_id);
 
 	struct arphdr *arp = (struct arphdr *)skb->data;
 	unsigned char *arp_ptr = (unsigned char *)(arp + 1);
@@ -1203,10 +1392,10 @@
 	 * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo.  */
 	arp1394->hw_addr_len	= 16;
 	arp1394->sip		= *(u32*)(arp_ptr + ETH1394_ALEN);
-	arp1394->max_rec	= (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf;
-	arp1394->sspd		= priv->sspd[phy_id];
-	arp1394->fifo_hi	= htons (priv->fifo[phy_id] >> 32);
-	arp1394->fifo_lo	= htonl (priv->fifo[phy_id] & ~0x0);
+	arp1394->max_rec	= priv->host->csr.max_rec;
+	arp1394->sspd		= priv->host->csr.lnk_spd;
+	arp1394->fifo_hi	= htons (priv->local_fifo >> 32);
+	arp1394->fifo_lo	= htonl (priv->local_fifo & ~0x0);
 
 	return;
 }
@@ -1333,15 +1522,15 @@
 	p->data_size = length;
 	p->data = ((quadlet_t*)skb->data) - 2;
 	p->data[0] = cpu_to_be32((priv->host->node_id << 16) |
-				      ETHER1394_GASP_SPECIFIER_ID_HI);
-	p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) |
-				      ETHER1394_GASP_VERSION);
+				 ETHER1394_GASP_SPECIFIER_ID_HI);
+	p->data[1] = __constant_cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) |
+					    ETHER1394_GASP_VERSION);
 
 	/* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES)
 	 * prevents hpsb_send_packet() from setting the speed to an arbitrary
 	 * value based on packet->node_id if packet->node_id is not set. */
 	p->node_id = ALL_NODES;
-	p->speed_code = priv->sspd[ALL_NODES];
+	p->speed_code = priv->bc_sspd;
 }
 
 static inline void ether1394_free_packet(struct hpsb_packet *packet)
@@ -1458,7 +1647,8 @@
 	u16 dg_size;
 	u16 dgl;
 	struct packet_task *ptask;
-	struct node_entry *ne;
+	struct eth1394_node_ref *node;
+	struct eth1394_node_info *node_info = NULL;
 
 	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
 	if (ptask == NULL) {
@@ -1466,22 +1656,11 @@
 		goto fail;
 	}
 
-	spin_lock_irqsave (&priv->lock, flags);
-	if (priv->bc_state == ETHER1394_BC_CLOSED) {
-		ETH1394_PRINT(KERN_ERR, dev->name,
-			      "Cannot send packet, no broadcast channel available.\n");
+	if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) {
 		ret = -EAGAIN;
-		spin_unlock_irqrestore (&priv->lock, flags);
-		goto fail;
-	}
-
-	if ((ret = ether1394_init_bc(dev))) {
-		spin_unlock_irqrestore (&priv->lock, flags);
 		goto fail;
 	}
 
-	spin_unlock_irqrestore (&priv->lock, flags);
-
 	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
 		ret = -ENOMEM;
 		goto fail;
@@ -1491,28 +1670,8 @@
 	eth = (struct eth1394hdr*)skb->data;
 	skb_pull(skb, ETH1394_HLEN);
 
-	ne = hpsb_guid_get_entry(be64_to_cpu(*(u64*)eth->h_dest));
-	if (!ne)
-		dest_node = LOCAL_BUS | ALL_NODES;
-	else
-		dest_node = ne->nodeid;
-
 	proto = eth->h_proto;
-
-	/* If this is an ARP packet, convert it */
-	if (proto == __constant_htons (ETH_P_ARP))
-		ether1394_arp_to_1394arp (skb, dev);
-
-	max_payload = priv->maxpayload[NODEID_TO_NODE(dest_node)];
-
-	/* This check should be unnecessary, but we'll keep it for safety for
-	 * a while longer. */
-	if (max_payload < 512) {
-		ETH1394_PRINT(KERN_WARNING, dev->name,
-			      "max_payload too small: %d   (setting to 512)\n",
-			      max_payload);
-		max_payload = 512;
-	}
+	dg_size = skb->len;
 
 	/* Set the transmission type for the packet.  ARP packets and IP
 	 * broadcast packets are sent via GASP. */
@@ -1521,18 +1680,38 @@
 	    (proto == __constant_htons(ETH_P_IP) &&
 	     IN_MULTICAST(__constant_ntohl(skb->nh.iph->daddr)))) {
 		tx_type = ETH1394_GASP;
-                max_payload -= ETHER1394_GASP_OVERHEAD;
+		dest_node = LOCAL_BUS | ALL_NODES;
+		max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
+		BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+		dgl = priv->bc_dgl;
+		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
+			priv->bc_dgl++;
 	} else {
+		node = eth1394_find_node_guid(&priv->ip_node_list,
+					      be64_to_cpu(*(u64*)eth->h_dest));
+		if (!node) {
+			ret = -EAGAIN;
+			goto fail;
+		}
+		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+		if (node_info->fifo == ETHER1394_INVALID_ADDR) {
+			ret = -EAGAIN;
+			goto fail;
+		}
+
+		dest_node = node->ud->ne->nodeid;
+		max_payload = node_info->maxpayload;
+		BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+
+		dgl = node_info->dgl;
+		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
+			node_info->dgl++;
 		tx_type = ETH1394_WRREQ;
 	}
 
-	dg_size = skb->len;
-
-	spin_lock_irqsave (&priv->lock, flags);
-	dgl = priv->dgl[NODEID_TO_NODE(dest_node)];
-	if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
-		priv->dgl[NODEID_TO_NODE(dest_node)]++;
-	spin_unlock_irqrestore (&priv->lock, flags);
+	/* If this is an ARP packet, convert it */
+	if (proto == __constant_htons (ETH_P_ARP))
+		ether1394_arp_to_1394arp (skb, dev);
 
 	ptask->hdr.words.word1 = 0;
 	ptask->hdr.words.word2 = 0;
@@ -1545,17 +1724,8 @@
 	if (tx_type != ETH1394_GASP) {
 		u64 addr;
 
-		/* This test is just temporary until ConfigROM support has
-		 * been added to eth1394.  Until then, we need an ARP packet
-		 * after a bus reset from the current destination node so that
-		 * we can get FIFO information. */
-		if (priv->fifo[NODEID_TO_NODE(dest_node)] == 0ULL) {
-			ret = -EAGAIN;
-			goto fail;
-		}
-
 		spin_lock_irqsave(&priv->lock, flags);
-		addr = priv->fifo[NODEID_TO_NODE(dest_node)];
+		addr = node_info->fifo;
 		spin_unlock_irqrestore(&priv->lock, flags);
 
 		ptask->addr = addr;
@@ -1621,7 +1791,7 @@
 		case ETHTOOL_GDRVINFO: {
 			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
 			strcpy (info.driver, driver_name);
-			strcpy (info.version, "$Rev: 1096 $");
+			strcpy (info.version, "$Rev: 1133 $");
 			/* FIXME XXX provide sane businfo */
 			strcpy (info.bus_info, "ieee1394");
 			if (copy_to_user (useraddr, &info, sizeof (info)))
@@ -1644,19 +1814,78 @@
 
 static int __init ether1394_init_module (void)
 {
+	int ret;
+	struct csr1212_keyval *spec_id = NULL;
+	struct csr1212_keyval *spec_desc = NULL;
+	struct csr1212_keyval *ver = NULL;
+	struct csr1212_keyval *ver_desc = NULL;
+
 	packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task),
 					      0, 0, NULL, NULL);
 
+	eth1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
+	spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
+					ETHER1394_GASP_SPECIFIER_ID);
+	spec_desc = csr1212_new_string_descriptor_leaf("IANA");
+	ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
+				    ETHER1394_GASP_VERSION);
+	ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
+
+	if ((!eth1394_ud) ||
+	    (!spec_id) ||
+	    (!spec_desc) ||
+	    (!ver) ||
+	    (!ver_desc)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = csr1212_associate_keyval(spec_id, spec_desc);
+	if (ret != CSR1212_SUCCESS)
+		goto out;
+
+	ret = csr1212_associate_keyval(ver, ver_desc);
+	if (ret != CSR1212_SUCCESS)
+		goto out;
+
+	ret = csr1212_attach_keyval_to_directory(eth1394_ud, spec_id);
+	if (ret != CSR1212_SUCCESS)
+		goto out;
+
+	ret = csr1212_attach_keyval_to_directory(eth1394_ud, ver);
+	if (ret != CSR1212_SUCCESS)
+		goto out;
+
 	/* Register ourselves as a highlevel driver */
 	hpsb_register_highlevel(&eth1394_highlevel);
 
-	return 0;
+	ret = hpsb_register_protocol(&eth1394_proto_driver);
+
+out:
+	if ((ret != 0) && eth1394_ud) {
+		csr1212_release_keyval(eth1394_ud);
+	}
+	if (spec_id)
+		csr1212_release_keyval(spec_id);
+	if (spec_desc)
+		csr1212_release_keyval(spec_desc);
+	if (ver)
+		csr1212_release_keyval(ver);
+	if (ver_desc)
+		csr1212_release_keyval(ver_desc);
+
+	return ret;
 }
 
 static void __exit ether1394_exit_module (void)
 {
+	hpsb_unregister_protocol(&eth1394_proto_driver);
 	hpsb_unregister_highlevel(&eth1394_highlevel);
 	kmem_cache_destroy(packet_task_cache);
+
+	if (eth1394_ud) {
+		csr1212_release_keyval(eth1394_ud);
+	}
 }
 
 module_init(ether1394_init_module);
--- diff/drivers/ieee1394/eth1394.h	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/ieee1394/eth1394.h	2004-02-18 09:03:59.000000000 +0000
@@ -29,8 +29,8 @@
 /* Register for incoming packets. This is 4096 bytes, which supports up to
  * S3200 (per Table 16-3 of IEEE 1394b-2002). */
 #define ETHER1394_REGION_ADDR_LEN	4096
-#define ETHER1394_REGION_ADDR		0xfffff0200000ULL
-#define ETHER1394_REGION_ADDR_END	(ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
+
+#define ETHER1394_INVALID_ADDR		~0ULL
 
 /* GASP identifier numbers for IPv4 over IEEE 1394 */
 #define ETHER1394_GASP_SPECIFIER_ID	0x00005E
@@ -40,37 +40,30 @@
 
 #define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t))  /* GASP header overhead */
 
+#define ETHER1394_GASP_BUFFERS 16
+
 /* Node set == 64 */
 #define NODE_SET			(ALL_NODES + 1)
 
-enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED,
-			 ETHER1394_BC_CHECK };
+enum eth1394_bc_states { ETHER1394_BC_ERROR,
+			 ETHER1394_BC_RUNNING,
+			 ETHER1394_BC_STOPPED };
 
-struct pdg_list {
-	struct list_head list;		/* partial datagram list per node */
-	unsigned int sz;		/* partial datagram list size per node	*/
-	spinlock_t lock;		/* partial datagram lock		*/
-};
 
 /* Private structure for our ethernet driver */
 struct eth1394_priv {
 	struct net_device_stats stats;	/* Device stats			 */
 	struct hpsb_host *host;		/* The card for this dev	 */
-	u16 maxpayload[NODE_SET];	/* Max payload per node		 */
-	unsigned char sspd[NODE_SET];	/* Max speed per node		 */
-	u64 fifo[ALL_NODES];		/* FIFO offset per node		 */
-	u64 eui[ALL_NODES];		/* EUI-64 per node		 */
+	u16 bc_maxpayload;		/* Max broadcast payload	 */
+	u8 bc_sspd;			/* Max broadcast speed		 */
+	u64 local_fifo;			/* Local FIFO Address		 */
 	spinlock_t lock;		/* Private lock			 */
 	int broadcast_channel;		/* Async stream Broadcast Channel */
 	enum eth1394_bc_states bc_state; /* broadcast channel state	 */
 	struct hpsb_iso *iso;		/* Async stream recv handle	 */
-	struct pdg_list pdg[ALL_NODES]; /* partial RX datagram lists     */
-	int dgl[NODE_SET];              /* Outgoing datagram label per node */
-};
-
-struct host_info {
-	struct hpsb_host *host;
-	struct net_device *dev;
+	int bc_dgl;			/* Outgoing broadcast datagram label */
+	struct list_head ip_node_list;	/* List of IP capable nodes	 */
+	struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
 };
 
 
--- diff/drivers/ieee1394/highlevel.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/highlevel.c	2004-02-18 09:03:59.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/bitops.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -44,7 +45,6 @@
 static LIST_HEAD(hl_irqs);
 static rwlock_t hl_irqs_lock = RW_LOCK_UNLOCKED;
 
-static LIST_HEAD(addr_space);
 static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
 
 /* addr_space list will have zero and max already included as bounds */
@@ -56,21 +56,20 @@
 					      struct hpsb_host *host)
 {
 	struct hl_host_info *hi = NULL;
-	struct list_head *lh;
 
 	if (!hl || !host)
 		return NULL;
 
 	read_lock(&hl->host_info_lock);
-	list_for_each (lh, &hl->host_info_list) {
-		hi = list_entry(lh, struct hl_host_info, list);
-		if (hi->host == host)
-			break;
-		hi = NULL;
+	list_for_each_entry(hi, &hl->host_info_list, list) {
+		if (hi->host == host) {
+			read_unlock(&hl->host_info_lock);
+			return hi;
+		}
 	}
 	read_unlock(&hl->host_info_lock);
 
-	return hi;
+	return NULL;
 }
 
 
@@ -188,7 +187,6 @@
 
 void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
 {
-	struct list_head *lh;
 	struct hl_host_info *hi;
 	void *data = NULL;
 
@@ -196,8 +194,7 @@
 		return NULL;
 
 	read_lock(&hl->host_info_lock);
-	list_for_each (lh, &hl->host_info_list) {
-		hi = list_entry(lh, struct hl_host_info, list);
+	list_for_each_entry(hi, &hl->host_info_list, list) {
 		if (hi->key == key) {
 			data = hi->data;
 			break;
@@ -211,7 +208,6 @@
 
 struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key)
 {
-	struct list_head *lh;
 	struct hl_host_info *hi;
 	struct hpsb_host *host = NULL;
 
@@ -219,8 +215,7 @@
 		return NULL;
 
 	read_lock(&hl->host_info_lock);
-	list_for_each (lh, &hl->host_info_list) {
-		hi = list_entry(lh, struct hl_host_info, list);
+	list_for_each_entry(hi, &hl->host_info_list, list) {
 		if (hi->key == key) {
 			host = hi->host;
 			break;
@@ -237,6 +232,13 @@
 
 	hl->add_host(host);
 
+        if (host->update_config_rom) {
+		if (hpsb_update_config_rom_image(host) < 0) {
+			HPSB_ERR("Failed to generate Configuration ROM image for host "
+				 "%s-%d", hl->name, host->id);
+		}
+	}
+
 	return 0;
 }
 
@@ -261,12 +263,20 @@
         return;
 }
 
-static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host)
+static void __delete_addr(struct hpsb_address_serve *as)
+{
+	list_del(&as->host_list);
+	list_del(&as->hl_list);
+	kfree(as);
+}
+
+static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host, int update_cr)
 {
 	unsigned long flags;
 	struct list_head *lh, *next;
 	struct hpsb_address_serve *as;
 
+	/* First, let the highlevel driver unreg */
 	if (hl->remove_host)
 		hl->remove_host(host);
 
@@ -274,19 +284,24 @@
 	 * and this particular host. */
 	write_lock_irqsave(&addr_space_lock, flags);
 	list_for_each_safe (lh, next, &hl->addr_list) {
-		as = list_entry(lh, struct hpsb_address_serve, addr_list);
+		as = list_entry(lh, struct hpsb_address_serve, hl_list);
 
-		if (as->host != host)
-			continue;
+		if (as->host == host)
+			__delete_addr(as);
+	}
+	write_unlock_irqrestore(&addr_space_lock, flags);
 
-		if (!list_empty(&as->addr_list)) {
-			list_del(&as->as_list);
-			list_del(&as->addr_list);
-			kfree(as);
+	/* Now update the config-rom to reflect anything removed by the
+	 * highlevel driver. */
+	if (update_cr && host->update_config_rom) {
+		if (hpsb_update_config_rom_image(host) < 0) {
+			HPSB_ERR("Failed to generate Configuration ROM image for host "
+				 "%s-%d", hl->name, host->id);
 		}
 	}
-	write_unlock_irqrestore(&addr_space_lock, flags);
 
+	/* And finally, remove all the host info associated between these
+	 * two. */
 	hpsb_destroy_hostinfo(hl, host);
 }
 
@@ -294,7 +309,7 @@
 {
 	struct hpsb_highlevel *hl = __data;
 
-	__unregister_host(hl, host);
+	__unregister_host(hl, host, 1);
 
 	return 0;
 }
@@ -312,11 +327,86 @@
 	nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
 }
 
+u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
+					 struct hpsb_host *host,
+					 struct hpsb_address_ops *ops,
+					 u64 size, u64 alignment,
+					 u64 start, u64 end)
+{
+	struct hpsb_address_serve *as, *a1, *a2;
+	struct list_head *entry;
+	u64 retval = ~0ULL;
+	unsigned long flags;
+	u64 align_mask = ~(alignment - 1);
+
+	if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
+	    ((hweight32(alignment >> 32) +
+	      hweight32(alignment & 0xffffffff) != 1))) {
+		HPSB_ERR("%s called with invalid alignment: 0x%048llx",
+			 __FUNCTION__, (unsigned long long)alignment);
+		return retval;
+	}
+
+	if (start == ~0ULL && end == ~0ULL) {
+		start = CSR1212_ALL_SPACE_BASE + 0xffff00000000ULL;  /* ohci1394.c limit */
+		end = CSR1212_ALL_SPACE_END;
+	}
+
+	if (((start|end) & ~align_mask) || (start >= end) || (end > 0x1000000000000ULL)) {
+		HPSB_ERR("%s called with invalid addresses (start = %012Lx    end = %012Lx)",
+			 __FUNCTION__, (unsigned long long)start, (unsigned long long)end);
+		return retval;
+	}
+
+	as = (struct hpsb_address_serve *)
+		kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
+	if (as == NULL) {
+		return retval;
+	}
+
+	INIT_LIST_HEAD(&as->host_list);
+	INIT_LIST_HEAD(&as->hl_list);
+	as->op = ops;
+	as->host = host;
+
+	write_lock_irqsave(&addr_space_lock, flags);
+
+	list_for_each(entry, &host->addr_space) {
+		u64 a1sa, a1ea;
+		u64 a2sa, a2ea;
+
+		a1 = list_entry(entry, struct hpsb_address_serve, host_list);
+		a2 = list_entry(entry->next, struct hpsb_address_serve, host_list);
+
+		a1sa = a1->start & align_mask;
+		a1ea = (a1->end + alignment -1) & align_mask;
+		a2sa = a2->start & align_mask;
+		a2ea = (a2->end + alignment -1) & align_mask;
+
+		if ((a2sa - a1ea >= size) && (a2sa - start >= size) && (end - a1ea >= size)) {
+			as->start = max(start, a1ea);
+			as->end = as->start + size;
+			list_add(&as->host_list, entry);
+			list_add_tail(&as->hl_list, &hl->addr_list);
+			retval = as->start;
+			break;
+		}
+	}
+
+	write_unlock_irqrestore(&addr_space_lock, flags);
+
+	if (retval == ~0ULL) {
+		kfree(as);
+	}
+
+	return retval;
+}
+
 int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
                             struct hpsb_address_ops *ops, u64 start, u64 end)
 {
         struct hpsb_address_serve *as;
-        struct list_head *entry;
+	struct list_head *lh;
         int retval = 0;
         unsigned long flags;
 
@@ -331,31 +421,35 @@
                 return 0;
         }
 
-        INIT_LIST_HEAD(&as->as_list);
-        INIT_LIST_HEAD(&as->addr_list);
+        INIT_LIST_HEAD(&as->host_list);
+        INIT_LIST_HEAD(&as->hl_list);
         as->op = ops;
         as->start = start;
         as->end = end;
+	as->host = host;
 
-        write_lock_irqsave(&addr_space_lock, flags);
-        entry = host->addr_space.next;
+	write_lock_irqsave(&addr_space_lock, flags);
 
-        while (list_entry(entry, struct hpsb_address_serve, as_list)->end
-               <= start) {
-                if (list_entry(entry->next, struct hpsb_address_serve, as_list)
-                    ->start >= end) {
-                        list_add(&as->as_list, entry);
-                        list_add_tail(&as->addr_list, &hl->addr_list);
-                        retval = 1;
-                        break;
-                }
-                entry = entry->next;
-        }
-        write_unlock_irqrestore(&addr_space_lock, flags);
+	list_for_each(lh, &host->addr_space) {
+		struct hpsb_address_serve *as_this =
+			list_entry(lh, struct hpsb_address_serve, host_list);
+		struct hpsb_address_serve *as_next =
+			list_entry(lh->next, struct hpsb_address_serve, host_list);
 
-        if (retval == 0) {
-                kfree(as);
-        }
+		if (as_this->end > as->start)
+			break;
+
+		if (as_next->start >= as->end) {
+			list_add(&as->host_list, lh);
+			list_add_tail(&as->hl_list, &hl->addr_list);
+			retval = 1;
+			break;
+		}
+	}
+	write_unlock_irqrestore(&addr_space_lock, flags);
+
+	if (retval == 0)
+		kfree(as);
 
         return retval;
 }
@@ -365,20 +459,15 @@
 {
         int retval = 0;
         struct hpsb_address_serve *as;
-        struct list_head *entry;
+        struct list_head *lh, *next;
         unsigned long flags;
 
         write_lock_irqsave(&addr_space_lock, flags);
 
-        entry = hl->addr_list.next;
-
-        while (entry != &hl->addr_list) {
-                as = list_entry(entry, struct hpsb_address_serve, addr_list);
-                entry = entry->next;
+	list_for_each_safe (lh, next, &hl->addr_list) {
+                as = list_entry(lh, struct hpsb_address_serve, hl_list);
                 if (as->start == start && as->host == host) {
-                        list_del(&as->as_list);
-                        list_del(&as->addr_list);
-                        kfree(as);
+			__delete_addr(as);
                         retval = 1;
                         break;
                 }
@@ -419,18 +508,18 @@
 
 static void init_hpsb_highlevel(struct hpsb_host *host)
 {
-	INIT_LIST_HEAD(&dummy_zero_addr.as_list);
-	INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
-	INIT_LIST_HEAD(&dummy_max_addr.as_list);
-	INIT_LIST_HEAD(&dummy_max_addr.addr_list);
+	INIT_LIST_HEAD(&dummy_zero_addr.host_list);
+	INIT_LIST_HEAD(&dummy_zero_addr.hl_list);
+	INIT_LIST_HEAD(&dummy_max_addr.host_list);
+	INIT_LIST_HEAD(&dummy_max_addr.hl_list);
 
 	dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
 
 	dummy_zero_addr.start = dummy_zero_addr.end = 0;
 	dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
 
-	list_add_tail(&dummy_zero_addr.as_list, &host->addr_space);
-	list_add_tail(&dummy_max_addr.as_list, &host->addr_space);
+	list_add_tail(&dummy_zero_addr.host_list, &host->addr_space);
+	list_add_tail(&dummy_max_addr.host_list, &host->addr_space);
 }
 
 void highlevel_add_host(struct hpsb_host *host)
@@ -445,6 +534,11 @@
 			hl->add_host(host);
         }
 	up_read(&hl_drivers_sem);
+	if (host->update_config_rom) {
+		if (hpsb_update_config_rom_image(host) < 0)
+			HPSB_ERR("Failed to generate Configuration ROM image for "
+				 "host %s-%d", hl->name, host->id);
+	}
 }
 
 void highlevel_remove_host(struct hpsb_host *host)
@@ -453,7 +547,7 @@
 
 	down_read(&hl_drivers_sem);
 	list_for_each_entry(hl, &hl_drivers, hl_list)
-		__unregister_host(hl, host);
+		__unregister_host(hl, host, 0);
 	up_read(&hl_drivers_sem);
 }
 
@@ -501,16 +595,15 @@
                    u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
-        struct list_head *entry;
         unsigned int partlength;
         int rcode = RCODE_ADDRESS_ERROR;
 
         read_lock(&addr_space_lock);
 
-        entry = host->addr_space.next;
-        as = list_entry(entry, struct hpsb_address_serve, as_list);
+	list_for_each_entry(as, &host->addr_space, host_list) {
+		if (as->start > addr)
+			break;
 
-        while (as->start <= addr) {
                 if (as->end > addr) {
                         partlength = min(as->end - addr, (u64) length);
 
@@ -529,9 +622,6 @@
                                 break;
                         }
                 }
-
-                entry = entry->next;
-                as = list_entry(entry, struct hpsb_address_serve, as_list);
         }
 
         read_unlock(&addr_space_lock);
@@ -547,16 +637,15 @@
 		    void *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
-        struct list_head *entry;
         unsigned int partlength;
         int rcode = RCODE_ADDRESS_ERROR;
 
         read_lock(&addr_space_lock);
 
-        entry = host->addr_space.next;
-        as = list_entry(entry, struct hpsb_address_serve, as_list);
+	list_for_each_entry(as, &host->addr_space, host_list) {
+		if (as->start > addr)
+			break;
 
-        while (as->start <= addr) {
                 if (as->end > addr) {
                         partlength = min(as->end - addr, (u64) length);
 
@@ -575,9 +664,6 @@
                                 break;
                         }
                 }
-
-                entry = entry->next;
-                as = list_entry(entry, struct hpsb_address_serve, as_list);
         }
 
         read_unlock(&addr_space_lock);
@@ -594,15 +680,14 @@
                    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
-        struct list_head *entry;
         int rcode = RCODE_ADDRESS_ERROR;
 
         read_lock(&addr_space_lock);
 
-        entry = host->addr_space.next;
-        as = list_entry(entry, struct hpsb_address_serve, as_list);
+	list_for_each_entry(as, &host->addr_space, host_list) {
+		if (as->start > addr)
+			break;
 
-        while (as->start <= addr) {
                 if (as->end > addr) {
                         if (as->op->lock) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
@@ -613,9 +698,6 @@
 
                         break;
                 }
-
-                entry = entry->next;
-                as = list_entry(entry, struct hpsb_address_serve, as_list);
         }
 
         read_unlock(&addr_space_lock);
@@ -627,15 +709,14 @@
                      u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
-        struct list_head *entry;
         int rcode = RCODE_ADDRESS_ERROR;
 
         read_lock(&addr_space_lock);
 
-        entry = host->addr_space.next;
-        as = list_entry(entry, struct hpsb_address_serve, as_list);
+	list_for_each_entry(as, &host->addr_space, host_list) {
+		if (as->start > addr)
+			break;
 
-        while (as->start <= addr) {
                 if (as->end > addr) {
                         if (as->op->lock64) {
                                 rcode = as->op->lock64(host, nodeid, store,
@@ -647,9 +728,6 @@
 
                         break;
                 }
-
-                entry = entry->next;
-                as = list_entry(entry, struct hpsb_address_serve, as_list);
         }
 
         read_unlock(&addr_space_lock);
--- diff/drivers/ieee1394/highlevel.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/highlevel.h	2004-02-18 09:03:59.000000000 +0000
@@ -4,9 +4,9 @@
 
 
 struct hpsb_address_serve {
-        struct list_head as_list; /* global list */
+        struct list_head host_list; /* per host list */
         
-        struct list_head addr_list; /* hpsb_highlevel list */
+        struct list_head hl_list; /* hpsb_highlevel list */
 
         struct hpsb_address_ops *op;
 
@@ -140,6 +140,11 @@
  * It returns true for successful allocation.  There is no unregister function,
  * all address spaces are deallocated together with the hpsb_highlevel.
  */
+u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
+					 struct hpsb_host *host,
+					 struct hpsb_address_ops *ops,
+					 u64 size, u64 alignment,
+					 u64 start, u64 end);
 int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
                             struct hpsb_address_ops *ops, u64 start, u64 end);
 
--- diff/drivers/ieee1394/hosts.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/hosts.c	2004-02-18 09:03:59.000000000 +0000
@@ -17,14 +17,46 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/timer.h>
 
+#include "csr1212.h"
+#include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"
 #include "nodemgr.h"
+#include "csr.h"
 
 
+static void delayed_reset_bus(unsigned long __reset_info)
+{
+	struct hpsb_host *host = (struct hpsb_host*)__reset_info;
+	int generation = host->csr.generation + 1;
+
+	/* The generation field rolls over to 2 rather than 0 per IEEE
+	 * 1394a-2000. */
+	if (generation > 0xf || generation < 2)
+		generation = 2;
+
+	CSR_SET_BUS_INFO_GENERATION(host->csr.rom, generation);
+	if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
+		/* CSR image creation failed, reset generation field and do not
+		 * issue a bus reset. */
+		CSR_SET_BUS_INFO_GENERATION(host->csr.rom, host->csr.generation);
+		return;
+	}
+
+	host->csr.generation = generation;
+
+	host->update_config_rom = 0;
+	if (host->driver->set_hw_config_rom)
+		host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
+
+	host->csr.gen_timestamp[host->csr.generation] = jiffies;
+	hpsb_reset_bus(host, SHORT_RESET);
+}
+
 static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
 {
         return 0;
@@ -83,6 +115,12 @@
         if (!h) return NULL;
         memset(h, 0, sizeof(struct hpsb_host) + extra);
 
+	h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
+	if (!h->csr.rom) {
+		kfree(h);
+		return NULL;
+	}
+
 	h->hostdata = h + 1;
         h->driver = drv;
 
@@ -91,6 +129,12 @@
 
 	INIT_LIST_HEAD(&h->addr_space);
 
+	init_timer(&h->delayed_reset);
+	h->delayed_reset.function = delayed_reset_bus;
+	h->delayed_reset.data = (unsigned long)h;
+	for (i = 2; i < 16; i++)
+		h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
+
 	for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
 		HPSB_TPOOL_INIT(&h->tpool[i]);
 
@@ -116,7 +160,14 @@
 	memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
 	h->device.parent = dev;
 	snprintf(h->device.bus_id, BUS_ID_SIZE, "fw-host%d", h->id);
+
+	h->class_dev.dev = &h->device;
+	h->class_dev.class = &hpsb_host_class;
+	snprintf(h->class_dev.class_id, BUS_ID_SIZE, "fw-host%d", h->id);
+
 	device_register(&h->device);
+	class_device_register(&h->class_dev);
+	get_device(&h->device);
 
 	return h;
 }
@@ -124,7 +175,6 @@
 void hpsb_add_host(struct hpsb_host *host)
 {
         highlevel_add_host(host);
-        host->driver->devctl(host, RESET_BUS, LONG_RESET);
 }
 
 void hpsb_remove_host(struct hpsb_host *host)
@@ -134,5 +184,38 @@
 
         highlevel_remove_host(host);
 
+	class_device_unregister(&host->class_dev);
 	device_unregister(&host->device);
 }
+
+int hpsb_update_config_rom_image(struct hpsb_host *host)
+{
+	unsigned long reset_time;
+	int next_gen = host->csr.generation + 1;
+
+	if (!host->update_config_rom)
+		return -EINVAL;
+
+	if (next_gen > 0xf)
+		next_gen = 2;
+
+	/* Stop the delayed interrupt, we're about to change the config rom and
+	 * it would be a waste to do a bus reset twice. */
+	del_timer_sync(&host->delayed_reset);
+
+	/* IEEE 1394a-2000 prohibits using the same generation number
+	 * twice in a 60 second period. */
+	if (jiffies - host->csr.gen_timestamp[next_gen] < 60 * HZ)
+		/* Wait 60 seconds from the last time this generation number was
+		 * used. */
+		reset_time = (60 * HZ) + host->csr.gen_timestamp[next_gen];
+	else
+		/* Wait 1 second in case some other code wants to change the
+		 * Config ROM in the near future. */
+		reset_time = jiffies + HZ;
+
+	/* This will add the timer as well as modify it */
+	mod_timer(&host->delayed_reset, reset_time);
+
+	return 0;
+}
--- diff/drivers/ieee1394/hosts.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/hosts.h	2004-02-18 09:03:59.000000000 +0000
@@ -10,14 +10,6 @@
 #include "ieee1394_types.h"
 #include "csr.h"
 
-/* size of the array used to store config rom (in quadlets)
-   maximum is 0x100. About 0x40 is needed for the default
-   entries. So 0x80 should provide enough space for additional
-   directories etc. 
-   Note: All lowlevel drivers are required to allocate at least
-         this amount of memory for the configuration rom!
-*/
-#define CSR_CONFIG_ROM_SIZE       0x100
 
 struct hpsb_packet;
 struct hpsb_iso;
@@ -69,6 +61,10 @@
 	int id;
 
 	struct device device;
+	struct class_device class_dev;
+
+	int update_config_rom;
+	struct timer_list delayed_reset;
 
 	struct list_head addr_space;
 };
@@ -153,12 +149,10 @@
 	struct module *owner;
 	const char *name;
 
-        /* This function must store a pointer to the configuration ROM into the
-         * location referenced to by pointer and return the size of the ROM. It
-         * may not fail.  If any allocation is required, it must be done
-         * earlier.
-         */
-        size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
+	/* The hardware driver may optionally support a function that is used
+	 * to set the hardware ConfigROM if the hardware supports handling
+	 * reads to the ConfigROM on its own. */
+	void (*set_hw_config_rom) (struct hpsb_host *host, quadlet_t *config_rom);
 
         /* This function shall implement packet transmission based on
          * packet->type.  It shall CRC both parts of the packet (unless
@@ -200,24 +194,18 @@
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
 
-/* updates the configuration rom of a host.
- * rom_version must be the current version,
- * otherwise it will fail with return value -1.
- * Return value -2 indicates that the new
- * rom version is too big.
- * Return value 0 indicates success
- */
+/* The following 2 functions are deprecated and will be removed when the
+ * raw1394/libraw1394 update is complete. */
 int hpsb_update_config_rom(struct hpsb_host *host,
       const quadlet_t *new_rom, size_t size, unsigned char rom_version);
-
-/* reads the current version of the configuration rom of a host.
- * buffersize is the size of the buffer, rom_size
- * returns the size of the current rom image.
- * rom_version is the version number of the fetched rom.
- * return value -1 indicates, that the buffer was
- * too small, 0 indicates success.
- */
 int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
       size_t buffersize, size_t *rom_size, unsigned char *rom_version);
 
+/* Updates the configuration rom image of a host.  rom_version must be the
+ * current version, otherwise it will fail with return value -1. If this
+ * host does not support config-rom-update, it will return -EINVAL.
+ * Return value 0 indicates success.
+ */
+int hpsb_update_config_rom_image(struct hpsb_host *host);
+
 #endif /* _IEEE1394_HOSTS_H */
--- diff/drivers/ieee1394/ieee1394_core.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/ieee1394_core.c	2004-02-18 09:03:59.000000000 +0000
@@ -515,9 +515,9 @@
         if (packet->node_id == host->node_id)
         { /* it is a local request, so handle it locally */
                 quadlet_t *data;
-                size_t size=packet->data_size+packet->header_size;
+                size_t size = packet->data_size + packet->header_size;
 
-                data = kmalloc(packet->header_size + packet->data_size, GFP_ATOMIC);
+                data = kmalloc(size, GFP_ATOMIC);
                 if (!data) {
                         HPSB_ERR("unable to allocate memory for concatenating header and data");
                         return -ENOMEM;
@@ -526,12 +526,12 @@
                 memcpy(data, packet->header, packet->header_size);
 
                 if (packet->data_size)
-			memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
+			memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
 
                 dump_packet("send packet local:", packet->header,
                             packet->header_size);
 
-                hpsb_packet_sent(host, packet,  packet->expect_response?ACK_PENDING:ACK_COMPLETE);
+                hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
                 hpsb_packet_received(host, data, size, 0);
 
                 kfree(data);
@@ -935,8 +935,7 @@
 void abort_requests(struct hpsb_host *host)
 {
         unsigned long flags;
-        struct hpsb_packet *packet;
-        struct list_head *lh, *tlh;
+        struct hpsb_packet *packet, *packet_next;
         LIST_HEAD(llist);
 
         host->driver->devctl(host, CANCEL_REQUESTS, 0);
@@ -946,8 +945,7 @@
         INIT_LIST_HEAD(&host->pending_packets);
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
-        list_for_each_safe(lh, tlh, &llist) {
-                packet = list_entry(lh, struct hpsb_packet, list);
+        list_for_each_entry_safe(packet, packet_next, &llist, list) {
                 list_del(&packet->list);
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_ABORTED;
@@ -959,9 +957,8 @@
 {
 	struct hpsb_host *host = (struct hpsb_host *)__opaque;
         unsigned long flags;
-        struct hpsb_packet *packet;
+        struct hpsb_packet *packet, *packet_next;
         unsigned long expire;
-        struct list_head *lh, *tlh;
         LIST_HEAD(expiredlist);
 
         spin_lock_irqsave(&host->csr.lock, flags);
@@ -970,8 +967,7 @@
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
 
-	list_for_each_safe(lh, tlh, &host->pending_packets) {
-                packet = list_entry(lh, struct hpsb_packet, list);
+	list_for_each_entry_safe(packet, packet_next, &host->pending_packets, list) {
                 if (time_before(packet->sendtime + expire, jiffies)) {
                         list_del(&packet->list);
                         list_add(&packet->list, &expiredlist);
@@ -983,8 +979,7 @@
 
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
-        list_for_each_safe(lh, tlh, &expiredlist) {
-                packet = list_entry(lh, struct hpsb_packet, list);
+        list_for_each_entry_safe(packet, packet_next, &expiredlist, list) {
                 list_del(&packet->list);
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_TIMEOUT;
@@ -1008,8 +1003,11 @@
 					      0, 0, NULL, NULL);
 
 	bus_register(&ieee1394_bus_type);
+	bus_create_file(&ieee1394_bus_type, &bus_attr_destroy);
+	class_register(&hpsb_host_class);
 
-	init_csr();
+	if (init_csr())
+		return -ENOMEM;
 
 	if (!disable_nodemgr)
 		init_ieee1394_nodemgr();
@@ -1026,6 +1024,8 @@
 
 	cleanup_csr();
 
+	class_unregister(&hpsb_host_class);
+	bus_remove_file(&ieee1394_bus_type, &bus_attr_destroy);
 	bus_unregister(&ieee1394_bus_type);
 
 	kmem_cache_destroy(hpsb_packet_cache);
@@ -1043,6 +1043,7 @@
 EXPORT_SYMBOL(hpsb_alloc_host);
 EXPORT_SYMBOL(hpsb_add_host);
 EXPORT_SYMBOL(hpsb_remove_host);
+EXPORT_SYMBOL(hpsb_update_config_rom_image);
 
 /** ieee1394_core.c **/
 EXPORT_SYMBOL(hpsb_speedto_str);
@@ -1081,6 +1082,7 @@
 EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
 EXPORT_SYMBOL(hpsb_unregister_addrspace);
+EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(hpsb_get_hostinfo);
@@ -1113,7 +1115,6 @@
 
 /** csr.c **/
 EXPORT_SYMBOL(hpsb_update_config_rom);
-EXPORT_SYMBOL(hpsb_get_config_rom);
 
 /** dma.c **/
 EXPORT_SYMBOL(dma_prog_region_init);
@@ -1144,3 +1145,34 @@
 EXPORT_SYMBOL(hpsb_iso_packet_received);
 EXPORT_SYMBOL(hpsb_iso_wake);
 EXPORT_SYMBOL(hpsb_iso_recv_flush);
+
+/** csr1212.c **/
+EXPORT_SYMBOL(csr1212_create_csr);
+EXPORT_SYMBOL(csr1212_init_local_csr);
+EXPORT_SYMBOL(csr1212_new_immediate);
+EXPORT_SYMBOL(csr1212_new_leaf);
+EXPORT_SYMBOL(csr1212_new_csr_offset);
+EXPORT_SYMBOL(csr1212_new_directory);
+EXPORT_SYMBOL(csr1212_associate_keyval);
+EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
+EXPORT_SYMBOL(csr1212_new_extended_immediate);
+EXPORT_SYMBOL(csr1212_new_extended_leaf);
+EXPORT_SYMBOL(csr1212_new_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_new_textual_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_new_icon_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_new_modifiable_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_new_keyword_leaf);
+EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
+EXPORT_SYMBOL(csr1212_disassociate_keyval);
+EXPORT_SYMBOL(csr1212_release_keyval);
+EXPORT_SYMBOL(csr1212_destroy_csr);
+EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_generate_positions);
+EXPORT_SYMBOL(csr1212_generate_layout_order);
+EXPORT_SYMBOL(csr1212_fill_cache);
+EXPORT_SYMBOL(csr1212_generate_csr_image);
+EXPORT_SYMBOL(csr1212_parse_keyval);
+EXPORT_SYMBOL(csr1212_parse_csr);
+EXPORT_SYMBOL(_csr1212_read_keyval);
+EXPORT_SYMBOL(_csr1212_destroy_keyval);
--- diff/drivers/ieee1394/ieee1394_core.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/ieee1394_core.h	2004-02-18 09:03:59.000000000 +0000
@@ -215,5 +215,6 @@
 
 /* Our sysfs bus entry */
 extern struct bus_type ieee1394_bus_type;
+extern struct class hpsb_host_class;
 
 #endif /* _IEEE1394_CORE_H */
--- diff/drivers/ieee1394/nodemgr.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/ieee1394/nodemgr.c	2004-02-18 09:03:59.000000000 +0000
@@ -28,6 +28,11 @@
 #include "csr.h"
 #include "nodemgr.h"
 
+struct nodemgr_csr_info {
+	struct hpsb_host *host;
+	nodeid_t nodeid;
+	unsigned int generation;
+};
 
 
 static char *nodemgr_find_oui_name(int oui)
@@ -47,6 +52,37 @@
 }
 
 
+static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
+                            void *buffer, void *__ci)
+{
+	struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
+	int i, ret = 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
+				buffer, length);
+		if (!ret)
+			break;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout (HZ/3))
+			return -EINTR;
+	}
+
+	return ret;
+}
+
+static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
+{
+	return (bus_info_data[2] >> 8) & 0x3;
+}
+
+static struct csr1212_bus_ops nodemgr_csr_ops = {
+	.bus_read =	nodemgr_bus_read,
+	.get_max_rom =	nodemgr_get_max_rom
+};
+
+
 /* 
  * Basically what we do here is start off retrieving the bus_info block.
  * From there will fill in some info about the node, verify it is of IEEE
@@ -69,7 +105,6 @@
 
 static DECLARE_MUTEX(nodemgr_serialize);
 
-
 struct host_info {
 	struct hpsb_host *host;
 	struct list_head list;
@@ -79,19 +114,108 @@
 	char daemon_name[15];
 };
 
+static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
+static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
+			   char *buffer, int buffer_size);
+static void nodemgr_resume_ne(struct node_entry *ne);
+static void nodemgr_remove_ne(struct node_entry *ne);
+static struct node_entry *find_entry_by_guid(u64 guid);
+
+struct bus_type ieee1394_bus_type = {
+	.name		= "ieee1394",
+	.match		= nodemgr_bus_match,
+	.hotplug	= nodemgr_hotplug,
+};
+
+static void host_cls_release(struct class_device *class_dev)
+{
+	put_device(&container_of((class_dev), struct hpsb_host, class_dev)->device);
+}
+
+struct class hpsb_host_class = {
+	.name		= "ieee1394_host",
+	.release	= host_cls_release,
+};
+
+static void ne_cls_release(struct class_device *class_dev)
+{
+	put_device(&container_of((class_dev), struct node_entry, class_dev)->device);
+}
+
+struct class nodemgr_ne_class = {
+	.name		= "ieee1394_node",
+	.release	= ne_cls_release,
+};
+
 static struct hpsb_highlevel nodemgr_highlevel;
 
-static int nodemgr_driverdata_ne;
-static int nodemgr_driverdata_host;
+static int nodemgr_platform_data_ud;
+
+static int nodemgr_generic_probe(struct device *dev)
+{
+	return -ENODEV;
+}
 
 static struct device_driver nodemgr_driver_ne = {
 	.name	= "ieee1394_node",
 	.bus	= &ieee1394_bus_type,
+	.probe	= nodemgr_generic_probe,
 };
 
 static struct device_driver nodemgr_driver_host = {
 	.name	= "ieee1394_host",
 	.bus	= &ieee1394_bus_type,
+	.probe	= nodemgr_generic_probe,
+};
+
+static void nodemgr_release_ud(struct device *dev)
+{
+	struct unit_directory *ud = container_of(dev, struct unit_directory, device);
+
+	if (ud->vendor_name_kv)
+		csr1212_release_keyval(ud->vendor_name_kv);
+	if (ud->model_name_kv)
+		csr1212_release_keyval(ud->model_name_kv);
+
+	kfree(ud);
+}
+
+static void nodemgr_release_ne(struct device *dev)
+{
+	struct node_entry *ne = container_of(dev, struct node_entry, device);
+
+	if (ne->vendor_name_kv)
+		csr1212_release_keyval(ne->vendor_name_kv);
+
+	kfree(ne);
+}
+
+
+static void nodemgr_release_host(struct device *dev)
+{
+	struct hpsb_host *host = container_of(dev, struct hpsb_host, device);
+
+	csr1212_destroy_csr(host->csr.rom);
+
+	kfree(host);
+}
+
+static struct device nodemgr_dev_template_ud = {
+	.bus		= &ieee1394_bus_type,
+	.release	= nodemgr_release_ud,
+	.platform_data	= &nodemgr_platform_data_ud,
+};
+
+static struct device nodemgr_dev_template_ne = {
+	.bus		= &ieee1394_bus_type,
+	.release	= nodemgr_release_ne,
+	.driver		= &nodemgr_driver_ne,
+};
+
+struct device nodemgr_dev_template_host = {
+	.bus		= &ieee1394_bus_type,
+	.release	= nodemgr_release_host,
+	.driver		= &nodemgr_driver_host,
 };
 
 
@@ -107,6 +231,26 @@
 	.show   = fw_show_##class##_##field,				\
 };
 
+#define fw_attr_td(class, class_type, td_kv)				\
+static ssize_t fw_show_##class##_##td_kv (struct device *dev, char *buf)\
+{									\
+	int len;							\
+	class_type *class = container_of(dev, class_type, device);	\
+	len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t);	\
+	memcpy(buf,							\
+	       CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv),	\
+	       len);							\
+	while ((buf + len - 1) == '\0')					\
+		len--;							\
+	buf[len++] = '\n';						\
+	buf[len] = '\0';						\
+	return len;							\
+}									\
+static struct device_attribute dev_attr_##class##_##td_kv = {		\
+	.attr = {.name = __stringify(td_kv), .mode = S_IRUGO },		\
+	.show   = fw_show_##class##_##td_kv,				\
+};
+
 
 #define fw_drv_attr(field, type, format_string)			\
 static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
@@ -126,10 +270,13 @@
 	struct node_entry *ne = container_of(dev, struct node_entry, device);
 
 	return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
-			"LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n", ne->busopt.irmc,
-			ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-			ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
-			ne->busopt.max_rec, ne->busopt.cyc_clk_acc);
+		       "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n",
+		       ne->busopt.irmc,
+		       ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+		       ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
+		       ne->busopt.max_rec, 
+		       ne->busopt.max_rom,
+		       ne->busopt.cyc_clk_acc);
 }
 static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
 
@@ -162,16 +309,38 @@
 static DEVICE_ATTR(tlabels_mask,S_IRUGO,fw_show_ne_tlabels_mask,NULL);
 
 
+static ssize_t fw_set_destroy(struct bus_type *bus, const char *buf, size_t count)
+{
+	struct node_entry *ne;
+	u64 guid = (u64)simple_strtoull(buf, NULL, 16);
+
+	ne = find_entry_by_guid(guid);
+
+	if (ne == NULL || !ne->in_limbo)
+		return -EINVAL;
+
+	nodemgr_remove_ne(ne);
+
+	return count;
+}
+static ssize_t fw_get_destroy(struct bus_type *bus, char *buf)
+{
+	return sprintf(buf, "You can destroy in_limbo nodes by writing their GUID to this file\n");
+}
+BUS_ATTR(destroy, S_IWUGO | S_IRUGO, fw_get_destroy, fw_set_destroy);
+
+
 fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
 fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
 
 fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, vendor_name, const char *, "%s\n")
+fw_attr_td(ne, struct node_entry, vendor_name_kv)
 fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
 
 fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
 fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
 fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
+fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
 
 static struct device_attribute *const fw_ne_attrs[] = {
 	&dev_attr_ne_guid,
@@ -194,9 +363,9 @@
 fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
 fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
 fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, vendor_name, const char *, "%s\n")
+fw_attr_td(ud, struct unit_directory, vendor_name_kv)
 fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
-fw_attr(ud, struct unit_directory, model_name, const char *, "%s\n")
+fw_attr_td(ud, struct unit_directory, model_name_kv)
 
 static struct device_attribute *const fw_ud_attrs[] = {
 	&dev_attr_ud_address,
@@ -358,14 +527,14 @@
 
 	if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
 		device_create_file(dev, &dev_attr_ud_vendor_id);
-		if (ud->flags & UNIT_DIRECTORY_VENDOR_TEXT)
-			device_create_file(dev, &dev_attr_ud_vendor_name);
+		if (ud->vendor_name_kv)
+			device_create_file(dev, &dev_attr_ud_vendor_name_kv);
 	}
 
 	if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
 		device_create_file(dev, &dev_attr_ud_model_id);
-		if (ud->flags & UNIT_DIRECTORY_MODEL_TEXT)
-			device_create_file(dev, &dev_attr_ud_model_name);
+		if (ud->model_name_kv)
+			device_create_file(dev, &dev_attr_ud_model_name_kv);
 	}
 }
 
@@ -376,14 +545,17 @@
         struct unit_directory *ud;
 	struct ieee1394_device_id *id;
 
-	if (dev->driver_data == &nodemgr_driverdata_ne ||
-	    dev->driver_data == &nodemgr_driverdata_host ||
-	    drv == &nodemgr_driver_ne || drv == &nodemgr_driver_host)
+	/* We only match unit directories, and ignore our internal drivers */
+	if (dev->platform_data != &nodemgr_platform_data_ud ||
+	    drv->probe == nodemgr_generic_probe)
 		return 0;
 
 	ud = container_of(dev, struct unit_directory, device);
 	driver = container_of(drv, struct hpsb_protocol_driver, driver);
 
+	if (ud->ne->in_limbo)
+		return 0;
+
         for (id = driver->id_table; id->match_flags != 0; id++) {
                 if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
                     id->vendor_id != ud->vendor_id)
@@ -408,24 +580,6 @@
 }
 
 
-static void nodemgr_release_ud(struct device *dev)
-{
-	kfree(container_of(dev, struct unit_directory, device));
-}
-
-
-static void nodemgr_release_ne(struct device *dev)
-{
-	kfree(container_of(dev, struct node_entry, device));
-}
-
-
-static void nodemgr_release_host(struct device *dev)
-{
-	kfree(container_of(dev, struct hpsb_host, device));
-}
-
-
 static void nodemgr_remove_ud(struct unit_directory *ud)
 {
 	struct device *dev = &ud->device;
@@ -444,10 +598,10 @@
 	device_remove_file(dev, &dev_attr_ud_specifier_id);
 	device_remove_file(dev, &dev_attr_ud_version);
 	device_remove_file(dev, &dev_attr_ud_vendor_id);
-	device_remove_file(dev, &dev_attr_ud_vendor_name);
+	device_remove_file(dev, &dev_attr_ud_vendor_name_kv);
 	device_remove_file(dev, &dev_attr_ud_vendor_oui);
 	device_remove_file(dev, &dev_attr_ud_model_id);
-	device_remove_file(dev, &dev_attr_ud_model_name);
+	device_remove_file(dev, &dev_attr_ud_model_name_kv);
 
 	device_unregister(dev);
 }
@@ -470,15 +624,20 @@
 	struct device *dev = &ne->device;
 	int i;
 
+	HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+
 	nodemgr_remove_node_uds(ne);
 
 	for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
 		device_remove_file(dev, fw_ne_attrs[i]);
 
 	device_remove_file(dev, &dev_attr_ne_guid_vendor_oui);
-	device_remove_file(dev, &dev_attr_ne_vendor_name);
+	device_remove_file(dev, &dev_attr_ne_vendor_name_kv);
 	device_remove_file(dev, &dev_attr_ne_vendor_oui);
+	device_remove_file(dev, &dev_attr_ne_in_limbo);
 
+	class_device_unregister(&ne->class_dev);
 	device_unregister(dev);
 }
 
@@ -503,188 +662,13 @@
 }
 
 
-static struct device nodemgr_dev_template_ud = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_ud,
-};
-
-
-static struct device nodemgr_dev_template_ne = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_ne,
-	.driver		= &nodemgr_driver_ne,
-	.driver_data	= &nodemgr_driverdata_ne,
-};
-
-struct device nodemgr_dev_template_host = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_host,
-	.driver		= &nodemgr_driver_host,
-	.driver_data	= &nodemgr_driverdata_host,
-};
-
-
-static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
-                           char *buffer, int buffer_size);
-
-
-struct bus_type ieee1394_bus_type = {
-	.name		= "ieee1394",
-	.match		= nodemgr_bus_match,
-	.hotplug	= nodemgr_hotplug,
-};
-
-
-static int nodemgr_read_quadlet(struct hpsb_host *host,
-				nodeid_t nodeid, unsigned int generation,
-				octlet_t address, quadlet_t *quad)
-{
-	int i;
-	int ret = 0;
-
-	for (i = 0; i < 3; i++) {
-		ret = hpsb_read(host, nodeid, generation, address, quad, 4);
-		if (!ret)
-			break;
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (schedule_timeout (HZ/3))
-			return -1;
-	}
-	*quad = be32_to_cpu(*quad);
-
-	return ret;
-}
-
-static int nodemgr_size_text_leaf(struct hpsb_host *host,
-				  nodeid_t nodeid, unsigned int generation,
-				  octlet_t address)
-{
-	quadlet_t quad;
-	int size = 0;
-
-	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
-		return -1;
-
-	if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
-		/* This is the offset.  */
-		address += 4 * CONFIG_ROM_VALUE(quad); 
-		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
-			return -1;
-		/* Now we got the size of the text descriptor leaf. */
-		size = CONFIG_ROM_LEAF_LENGTH(quad);
-	}
-
-	return size;
-}
-
-static int nodemgr_read_text_leaf(struct node_entry *ne,
-				  octlet_t address,
-				  quadlet_t *quadp)
-{
-	quadlet_t quad;
-	int i, size, ret;
-
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)
-	    || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
-		return -1;
-
-	/* This is the offset.  */
-	address += 4 * CONFIG_ROM_VALUE(quad);
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
-		return -1;
-
-	/* Now we got the size of the text descriptor leaf. */
-	size = CONFIG_ROM_LEAF_LENGTH(quad) - 2;
-	if (size <= 0)
-		return -1;
-
-	address += 4;
-	for (i = 0; i < 2; i++, address += 4, quadp++) {
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp))
-			return -1;
-	}
-
-	/* Now read the text string.  */
-	ret = -ENXIO;
-	for (; size > 0; size--, address += 4, quadp++) {
-		for (i = 0; i < 3; i++) {
-			ret = hpsb_node_read(ne, address, quadp, 4);
-			if (ret != -EAGAIN)
-				break;
-		}
-		if (ret)
-			break;
-	}
-
-	return ret;
-}
-
-static struct node_entry *nodemgr_scan_root_directory
-	(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation)
+static void nodemgr_update_bus_options(struct node_entry *ne)
 {
-	octlet_t address;
-	quadlet_t quad;
-	int length;
-	int code, size, total_size;
-	struct node_entry *ne;
-
-	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	
-	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
-		return NULL;
-
-	if (CONFIG_ROM_BUS_INFO_LENGTH(quad) == 1)  /* minimal config rom */
-		return NULL;
-
-	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
-
-	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
-		return NULL;
-	length = CONFIG_ROM_ROOT_LENGTH(quad);
-	address += 4;
-
-	size = 0;
-	total_size = sizeof(struct node_entry);
-	for (; length > 0; length--, address += 4) {
-		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
-			return NULL;
-		code = CONFIG_ROM_KEY(quad);
-
-		if (code == CONFIG_ROM_VENDOR_ID && length > 0) {
-			/* Check if there is a text descriptor leaf
-			   immediately after this.  */
-			size = nodemgr_size_text_leaf(host, nodeid, generation,
-						      address + 4);
-			if (size > 0) {
-				address += 4;
-				length--;
-				total_size += (size + 1) * sizeof (quadlet_t);
-			} else if (size < 0)
-				return NULL;
-		}
-	}
-	ne = kmalloc(total_size, GFP_KERNEL);
-
-	if (!ne)
-		return NULL;
-
-	memset(ne, 0, total_size);
-
-	if (size != 0) {
-		ne->vendor_name = (const char *) &(ne->quadlets[2]);
-		ne->quadlets[size] = 0;
-	} else {
-		ne->vendor_name = NULL;
-	}
-
-	return ne; 
-}
-
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	static const u16 mr[] = { 4, 64, 1024, 0};
+#endif
+	quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
 
-static void nodemgr_update_bus_options(struct node_entry *ne,
-                                       quadlet_t busoptions)
-{
 	ne->busopt.irmc         = (busoptions >> 31) & 1;
 	ne->busopt.cmc          = (busoptions >> 30) & 1;
 	ne->busopt.isc          = (busoptions >> 29) & 1;
@@ -692,28 +676,32 @@
 	ne->busopt.pmc          = (busoptions >> 27) & 1;
 	ne->busopt.cyc_clk_acc  = (busoptions >> 16) & 0xff;
 	ne->busopt.max_rec      = 1 << (((busoptions >> 12) & 0xf) + 1);
+	ne->busopt.max_rom	= (busoptions >> 8) & 0x3;
 	ne->busopt.generation   = (busoptions >> 4) & 0xf;
 	ne->busopt.lnkspd       = busoptions & 0x7;
 	
 	HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
-		     "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d",
+		     "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
 		     busoptions, ne->busopt.irmc, ne->busopt.cmc,
 		     ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
 		     ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
+		     mr[ne->busopt.max_rom],
 		     ne->busopt.generation, ne->busopt.lnkspd);
 }
 
 
-static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
+static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr *csr,
 					      struct host_info *hi, nodeid_t nodeid,
 					      unsigned int generation)
 {
 	struct hpsb_host *host = hi->host;
         struct node_entry *ne;
 
-	ne = nodemgr_scan_root_directory (host, nodeid, generation);
+	ne = kmalloc(sizeof(struct node_entry), GFP_KERNEL);
         if (!ne) return NULL;
 
+	memset(ne, 0, sizeof(struct node_entry));
+
 	ne->tpool = &host->tpool[nodeid & NODE_MASK];
 
         ne->host = host;
@@ -724,6 +712,7 @@
         ne->guid = guid;
 	ne->guid_vendor_id = (guid >> 40) & 0xffffff;
 	ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
+	ne->csr = csr;
 
 	memcpy(&ne->device, &nodemgr_dev_template_ne,
 	       sizeof(ne->device));
@@ -731,13 +720,20 @@
 	snprintf(ne->device.bus_id, BUS_ID_SIZE, "%016Lx",
 		 (unsigned long long)(ne->guid));
 
+	ne->class_dev.dev = &ne->device;
+	ne->class_dev.class = &nodemgr_ne_class;
+	snprintf(ne->class_dev.class_id, BUS_ID_SIZE, "%016Lx",
+		 (unsigned long long)(ne->guid));
+
 	device_register(&ne->device);
+	class_device_register(&ne->class_dev);
+	get_device(&ne->device);
 
 	if (ne->guid_vendor_oui)
 		device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui);
 	nodemgr_create_ne_dev_files(ne);
 
-	nodemgr_update_bus_options(ne, busoptions);
+	nodemgr_update_bus_options(ne);
 
 	HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
 		   (host->node_id == nodeid) ? "Host" : "Node",
@@ -747,319 +743,167 @@
 }
 
 
-struct guid_search_baton {
-	u64 guid;
-	struct node_entry *ne;
-};
-
-static int nodemgr_guid_search_cb(struct device *dev, void *__data)
-{
-        struct guid_search_baton *search = __data;
-        struct node_entry *ne;
-
-        if (dev->driver_data != &nodemgr_driverdata_ne)
-                return 0;
-
-        ne = container_of(dev, struct node_entry, device);
-
-        if (ne->guid == search->guid) {
-		search->ne = ne;
-		return 1;
-	}
-
-	return 0;
-}
-
 static struct node_entry *find_entry_by_guid(u64 guid)
 {
-	struct guid_search_baton search;
-
-	search.guid = guid;
-	search.ne = NULL;
-
-	bus_for_each_dev(&ieee1394_bus_type, NULL, &search, nodemgr_guid_search_cb);
-
-        return search.ne;
-}
-
-
-struct nodeid_search_baton {
-	nodeid_t nodeid;
-	struct node_entry *ne;
-	struct hpsb_host *host;
-};
+	struct class *class = &nodemgr_ne_class;
+	struct class_device *cdev;
+	struct node_entry *ne, *ret_ne = NULL;
+
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(cdev, &class->children, node) {
+		ne = container_of(cdev, struct node_entry, class_dev);
 
-static int nodemgr_nodeid_search_cb(struct device *dev, void *__data)
-{
-	struct nodeid_search_baton *search = __data;
-	struct node_entry *ne;
-
-	if (dev->driver_data != &nodemgr_driverdata_ne)
-		return 0;
-
-	ne = container_of(dev, struct node_entry, device);
-
-	if (ne->host == search->host && ne->nodeid == search->nodeid) {
-		search->ne = ne;
-		/* Returning 1 stops the iteration */
-		return 1;
+		if (ne->guid == guid) {
+			ret_ne = ne;
+			break;
+		}
 	}
+	up_read(&class->subsys.rwsem);
 
-	return 0;
+        return ret_ne;
 }
 
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid)
-{
-	struct nodeid_search_baton search;
 
-	search.nodeid = nodeid;
-	search.ne = NULL;
-	search.host = host;
-
-	bus_for_each_dev(&ieee1394_bus_type, NULL, &search, nodemgr_nodeid_search_cb);
-
-	return search.ne;
-}
-
-static struct unit_directory *nodemgr_scan_unit_directory
-	(struct node_entry *ne, octlet_t address)
+static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid)
 {
-	struct unit_directory *ud;
-	quadlet_t quad;
-	u8 flags, todo;
-	int length, size, total_size, count;
-	int vendor_name_size, model_name_size;
-
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
-		return NULL;
-
-	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
-	address += 4;
-
-	size = 0;
-	total_size = sizeof (struct unit_directory);
-	flags = 0;
-	count = 0;
-	vendor_name_size = 0;
-	model_name_size = 0;
-	for (; length > 0; length--, address += 4) {
-		int code;
-		quadlet_t value;
-
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-					 address, &quad))
-			return NULL;
-		code = CONFIG_ROM_KEY(quad);
-		value = CONFIG_ROM_VALUE(quad);
-
-		todo = 0;
-		switch (code) {
-		case CONFIG_ROM_VENDOR_ID:
-			todo = UNIT_DIRECTORY_VENDOR_TEXT;
-			break;
-
-		case CONFIG_ROM_MODEL_ID:
-			todo = UNIT_DIRECTORY_MODEL_TEXT;
-			break;
-
-		case CONFIG_ROM_SPECIFIER_ID:
-		case CONFIG_ROM_UNIT_SW_VERSION:
-			break;
+	struct class *class = &nodemgr_ne_class;
+	struct class_device *cdev;
+	struct node_entry *ne, *ret_ne = NULL;
+
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(cdev, &class->children, node) {
+		ne = container_of(cdev, struct node_entry, class_dev);
 
-		case CONFIG_ROM_DESCRIPTOR_LEAF:
-		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
-			/* TODO: read strings... icons? */
+		if (ne->host == host && ne->nodeid == nodeid) {
+			ret_ne = ne;
 			break;
-
-		default:
-			/* Which types of quadlets do we want to
-			   store?  Only count immediate values and
-			   CSR offsets for now.  */
-			code &= CONFIG_ROM_KEY_TYPE_MASK;
-			if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0)
-				count++;
-			break;
-		}
-
-		if (todo && length > 0) {
-			/* Check if there is a text descriptor leaf
-			   immediately after this.  */
-			size = nodemgr_size_text_leaf(ne->host,
-						      ne->nodeid,
-						      ne->generation,
-						      address + 4);
-
-			if (todo == UNIT_DIRECTORY_VENDOR_TEXT)
-				vendor_name_size = size;
-			else
-				model_name_size = size;
-
-			if (size > 0) {
-				address += 4;
-				length--;
-				flags |= todo;
-				total_size += (size + 1) * sizeof (quadlet_t);
-			}
-			else if (size < 0)
-				return NULL;
 		}
 	}
+	up_read(&class->subsys.rwsem);
 
-	total_size += count * sizeof (quadlet_t);
-	ud = kmalloc (total_size, GFP_KERNEL);
-
-	if (ud != NULL) {
-		memset (ud, 0, total_size);
-		ud->flags = flags;
-		ud->length = count;
-		ud->vendor_name_size = vendor_name_size;
-		ud->model_name_size = model_name_size;
-	}
-
-	return ud;
+	return ret_ne;
 }
 
 
+
 /* This implementation currently only scans the config rom and its
  * immediate unit directories looking for software_id and
  * software_version entries, in order to get driver autoloading working. */
 static struct unit_directory *nodemgr_process_unit_directory
-	(struct host_info *hi, struct node_entry *ne, octlet_t address, unsigned int *id,
-	 struct unit_directory *parent)
+	(struct host_info *hi, struct node_entry *ne, struct csr1212_keyval *ud_kv,
+	 unsigned int *id, struct unit_directory *parent)
 {
 	struct unit_directory *ud;
-	quadlet_t quad;
-	quadlet_t *infop;
-	int length;
 	struct unit_directory *ud_temp = NULL;
+	struct csr1212_dentry *dentry;
+	struct csr1212_keyval *kv;
+	u8 last_key_id = 0;
 
-	if (!(ud = nodemgr_scan_unit_directory(ne, address)))
+	ud = kmalloc(sizeof(struct unit_directory), GFP_KERNEL);
+	if (!ud)
 		goto unit_directory_error;
 
+	memset (ud, 0, sizeof(struct unit_directory));
+
 	ud->ne = ne;
-	ud->address = address;
+	ud->address = ud_kv->offset + CSR1212_CONFIG_ROM_SPACE_BASE;
+	ud->ud_kv = ud_kv;
 	ud->id = (*id)++;
 
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-				 address, &quad))
-		goto unit_directory_error;
-	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
-	address += 4;
+	csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
+		switch (kv->key.id) {
+		case CSR1212_KV_ID_VENDOR:
+			if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
+				ud->vendor_id = kv->value.immediate;
+				ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
 
-	infop = (quadlet_t *) ud->quadlets;
-	for (; length > 0; length--, address += 4) {
-		int code;
-		quadlet_t value;
-		quadlet_t *quadp;
-
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-					 address, &quad))
-			goto unit_directory_error;
-		code = CONFIG_ROM_KEY(quad) ;
-		value = CONFIG_ROM_VALUE(quad);
-
-		switch (code) {
-		case CONFIG_ROM_VENDOR_ID:
-			ud->vendor_id = value;
-			ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
-			if (ud->vendor_id)
-				ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
-
-			if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) {
-				length--;
-				address += 4;
-				quadp = &(ud->quadlets[ud->length]);
-				if (nodemgr_read_text_leaf(ne, address, quadp) == 0
-				    && quadp[0] == 0 && quadp[1] == 0) {
-				    	/* We only support minimal
-					   ASCII and English. */
-					quadp[ud->vendor_name_size] = 0;
-					ud->vendor_name
-						= (const char *) &(quadp[2]);
-				}
+				if (ud->vendor_id)
+					ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
 			}
 			break;
 
-		case CONFIG_ROM_MODEL_ID:
-			ud->model_id = value;
+		case CSR1212_KV_ID_MODEL:
+			ud->model_id = kv->value.immediate;
 			ud->flags |= UNIT_DIRECTORY_MODEL_ID;
-			if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) {
-				length--;
-				address += 4;
-				quadp = &(ud->quadlets[ud->length + ud->vendor_name_size + 1]);
-				if (nodemgr_read_text_leaf(ne, address, quadp) == 0
-				    && quadp[0] == 0 && quadp[1] == 0) {
-				    	/* We only support minimal
-					   ASCII and English. */
-					quadp[ud->model_name_size] = 0;
-					ud->model_name
-						= (const char *) &(quadp[2]);
-				}
-			}
 			break;
 
-		case CONFIG_ROM_SPECIFIER_ID:
-			ud->specifier_id = value;
+		case CSR1212_KV_ID_SPECIFIER_ID:
+			ud->specifier_id = kv->value.immediate;
 			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
 			break;
 
-		case CONFIG_ROM_UNIT_SW_VERSION:
-			ud->version = value;
+		case CSR1212_KV_ID_VERSION:
+			ud->version = kv->value.immediate;
 			ud->flags |= UNIT_DIRECTORY_VERSION;
 			break;
 
-		case CONFIG_ROM_DESCRIPTOR_LEAF:
-		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
-			/* TODO: read strings... icons? */
+		case CSR1212_KV_ID_DESCRIPTOR:
+			if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
+			    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
+			    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
+			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
+			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
+			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
+				switch (last_key_id) {
+				case CSR1212_KV_ID_VENDOR:
+					ud->vendor_name_kv = kv;
+					csr1212_keep_keyval(kv);
+					break;
+
+				case CSR1212_KV_ID_MODEL:
+					ud->model_name_kv = kv;
+					csr1212_keep_keyval(kv);
+					break;
+
+				}
+			} /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
 			break;
 
-		case CONFIG_ROM_LOGICAL_UNIT_DIRECTORY:
-			ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
-			ud_temp = nodemgr_process_unit_directory(hi, ne, address + value * 4, id,
-								 parent);
-
-			if (ud_temp == NULL)
-				break;
-
-			/* inherit unspecified values */
-			if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) &&
-				!(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))
-			{
-				ud_temp->flags |=  UNIT_DIRECTORY_VENDOR_ID;
-				ud_temp->vendor_id = ud->vendor_id;
-				ud_temp->vendor_oui = ud->vendor_oui;
-			}
-			if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
-				!(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))
-			{
-				ud_temp->flags |=  UNIT_DIRECTORY_MODEL_ID;
-				ud_temp->model_id = ud->model_id;
-			}
-			if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
-				!(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))
-			{
-				ud_temp->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
-				ud_temp->specifier_id = ud->specifier_id;
-			}
-			if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
-				!(ud_temp->flags & UNIT_DIRECTORY_VERSION))
-			{
-				ud_temp->flags |=  UNIT_DIRECTORY_VERSION;
-				ud_temp->version = ud->version;
+		case CSR1212_KV_ID_DEPENDENT_INFO:
+			if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
+				/* This should really be done in SBP2 as this is
+				 * doing SBP2 specific parsing. */
+				ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
+				ud_temp = nodemgr_process_unit_directory(hi, ne, kv, id,
+									 parent);
+
+				if (ud_temp == NULL)
+					break;
+
+				/* inherit unspecified values */
+				if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) &&
+				    !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_VENDOR_ID;
+					ud_temp->vendor_id = ud->vendor_id;
+					ud_temp->vendor_oui = ud->vendor_oui;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
+				    !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_MODEL_ID;
+					ud_temp->model_id = ud->model_id;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
+				    !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
+					ud_temp->specifier_id = ud->specifier_id;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
+				    !(ud_temp->flags & UNIT_DIRECTORY_VERSION))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_VERSION;
+					ud_temp->version = ud->version;
+				}
 			}
 
 			break;
 
 		default:
-			/* Which types of quadlets do we want to
-			   store?  Only count immediate values and
-			   CSR offsets for now.  */
-			code &= CONFIG_ROM_KEY_TYPE_MASK;
-			if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0)
-				*infop++ = quad;
 			break;
 		}
+		last_key_id = kv->key.id;
 	}
 
 	memcpy(&ud->device, &nodemgr_dev_template_ud,
@@ -1091,76 +935,51 @@
 
 static void nodemgr_process_root_directory(struct host_info *hi, struct node_entry *ne)
 {
-	octlet_t address;
-	quadlet_t quad;
-	int length;
 	unsigned int ud_id = 0;
-
-	device_remove_file(&ne->device, &dev_attr_ne_vendor_oui);
-
-	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-				 address, &quad))
-		return;
-	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
-
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-				 address, &quad))
-		return;
-	length = CONFIG_ROM_ROOT_LENGTH(quad);
-	address += 4;
-
-	for (; length > 0; length--, address += 4) {
-		int code, value;
-
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
-					 address, &quad))
-			return;
-		code = CONFIG_ROM_KEY(quad);
-		value = CONFIG_ROM_VALUE(quad);
-
-		switch (code) {
-		case CONFIG_ROM_VENDOR_ID:
-			ne->vendor_id = value;
+	struct csr1212_dentry *dentry;
+	struct csr1212_keyval *kv;
+	u8 last_key_id = 0;
+
+	ne->needs_probe = 0;
+
+	csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {
+		switch (kv->key.id) {
+		case CSR1212_KV_ID_VENDOR:
+			ne->vendor_id = kv->value.immediate;
 
 			if (ne->vendor_id)
 				ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
-
-			/* Now check if there is a vendor name text
-			   string.  */
-			if (ne->vendor_name != NULL) {
-				length--;
-				address += 4;
-				if (nodemgr_read_text_leaf(ne, address, ne->quadlets) != 0
-				    || ne->quadlets[0] != 0 || ne->quadlets[1] != 0)
-				    	/* We only support minimal
-					   ASCII and English. */
-					ne->vendor_name = NULL;
-				else
-					device_create_file(&ne->device,
-						&dev_attr_ne_vendor_name);
-			}
 			break;
 
-		case CONFIG_ROM_NODE_CAPABILITES:
-			ne->capabilities = value;
+		case CSR1212_KV_ID_NODE_CAPABILITIES:
+			ne->capabilities = kv->value.immediate;
 			break;
 
-		case CONFIG_ROM_UNIT_DIRECTORY:
-			nodemgr_process_unit_directory(hi, ne, address + value * 4, &ud_id,
-						       NULL);
+		case CSR1212_KV_ID_UNIT:
+			nodemgr_process_unit_directory(hi, ne, kv, &ud_id, NULL);
 			break;			
 
-		case CONFIG_ROM_DESCRIPTOR_LEAF:
-		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
-			/* TODO: read strings... icons? */
+		case CSR1212_KV_ID_DESCRIPTOR:
+			if (last_key_id == CSR1212_KV_ID_VENDOR) {
+				if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
+				    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
+				    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
+				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
+				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
+				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
+					ne->vendor_name_kv = kv;
+					csr1212_keep_keyval(kv);
+				}
+			}
 			break;
 		}
+		last_key_id = kv->key.id;
 	}
 
 	if (ne->vendor_oui)
 		device_create_file(&ne->device, &dev_attr_ne_vendor_oui);
+	if (ne->vendor_name_kv)
+		device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv);
 }
 
 #ifdef CONFIG_HOTPLUG
@@ -1176,13 +995,14 @@
 	if (!dev)
 		return -ENODEV;
 
-	/* Have to check driver_data, since on remove, driver == NULL */
-	if (dev->driver_data == &nodemgr_driverdata_ne ||
-	    dev->driver_data == &nodemgr_driverdata_host)
+	if (dev->platform_data != &nodemgr_platform_data_ud)
 		return -ENODEV;
 
 	ud = container_of(dev, struct unit_directory, device);
 
+	if (ud->ne->in_limbo)
+		return -ENODEV;
+
 	scratch = buffer;
 
 #define PUT_ENVP(fmt,val) 					\
@@ -1261,7 +1081,7 @@
  * informed that this device just went through a bus reset, to allow
  * the to take whatever actions required.
  */
-static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
+static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
 				struct host_info *hi, nodeid_t nodeid,
 				unsigned int generation)
 {
@@ -1272,87 +1092,29 @@
 		ne->nodeid = nodeid;
 	}
 
-	if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) {
+	if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {
+		kfree(ne->csr->private);
+		csr1212_destroy_csr(ne->csr);
+		ne->csr = csr;
+
 		/* If the node's configrom generation has changed, we
 		 * unregister all the unit directories. */
 		nodemgr_remove_node_uds(ne);
 
-		nodemgr_update_bus_options(ne, busoptions);
+		nodemgr_update_bus_options(ne);
 
 		/* Mark the node as new, so it gets re-probed */
 		ne->needs_probe = 1;
 	}
 
+	if (ne->in_limbo)
+		nodemgr_resume_ne(ne);
+
 	/* Mark the node current */
 	ne->generation = generation;
 }
 
-static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation,
-			      quadlet_t *buffer, int buffer_length)
-{
-	octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	unsigned header_size;
-	int i;
-
-	/* IEEE P1212 says that devices should support 64byte block
-	 * reads, aligned on 64byte boundaries. That doesn't seem to
-	 * work though, and we are forced to doing quadlet sized
-	 * reads.  */
-
-	HPSB_VERBOSE("Initiating ConfigROM request for node " NODE_BUS_FMT,
-		     NODE_BUS_ARGS(host, nodeid));
-
-	/* 
-	 * Must retry a few times if config rom read returns zero (how long?). Will
-	 * not normally occur, but we should do the right thing. For example, with
-	 * some sbp2 devices, the bridge chipset cannot return valid config rom reads
-	 * immediately after power-on, since they need to detect the type of 
-	 * device attached (disk or CD-ROM).
-	 */
-	for (i = 0; i < 4; i++) {
-		if (nodemgr_read_quadlet(host, nodeid, generation,
-					 addr, &buffer[0]) < 0) {
-			HPSB_ERR("ConfigROM quadlet transaction error for node "
-				 NODE_BUS_FMT, NODE_BUS_ARGS(host, nodeid));
-			return -1;
-		}
-		if (buffer[0])
-			break;
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (schedule_timeout (HZ/4))
-			return -1;
-	}
-
-	header_size = buffer[0] >> 24;
-	addr += 4;
-
-	if (header_size == 1) {
-		HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM.  "
-			  "Vendor is %08x",
-			  NODE_BUS_ARGS(host, nodeid), buffer[0] & 0x00ffffff);
-		return -1;
-	}
-
-	if (header_size < 4) {
-		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "
-			  "format (%d quads), cannot parse",
-			  NODE_BUS_ARGS(host, nodeid), header_size);
-		return -1;
-	}
-
-	for (i = 1; i < buffer_length; i++, addr += 4) {
-		if (nodemgr_read_quadlet(host, nodeid, generation,
-					 addr, &buffer[i]) < 0) {
-			HPSB_ERR("ConfigROM quadlet transaction "
-				 "error for node " NODE_BUS_FMT,
-				 NODE_BUS_ARGS(host, nodeid));
-			return -1;
-		}
-	}
-
-	return 0;
-}		
+		
 
 
 static void nodemgr_node_scan_one(struct host_info *hi,
@@ -1360,17 +1122,32 @@
 {
 	struct hpsb_host *host = hi->host;
 	struct node_entry *ne;
-	quadlet_t buffer[5];
 	octlet_t guid;
+	struct csr1212_csr *csr;
+	struct nodemgr_csr_info *ci;
+
+	ci = kmalloc(sizeof(struct nodemgr_csr_info), GFP_KERNEL);
+	if (!ci)
+		return;
+
+	ci->host = host;
+	ci->nodeid = nodeid;
+	ci->generation = generation;
 
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
 
-	if (read_businfo_block (host, nodeid, generation,
-				buffer, sizeof(buffer) >> 2))
+	csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);
+	if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {
+		HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,
+			 NODE_BUS_ARGS(host, nodeid));
+		if (csr)
+			csr1212_destroy_csr(csr);
+		kfree(ci);
 		return;
+	}
 
-	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
+	if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {
 		/* This isn't a 1394 device, but we let it slide. There
 		 * was a report of a device with broken firmware which
 		 * reported '2394' instead of '1394', which is obviously a
@@ -1379,96 +1156,64 @@
 		 * shouldn't be held responsible, so we'll allow it with a
 		 * warning.  */
 		HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
-			  NODE_BUS_ARGS(host, nodeid), buffer[1]);
+			  NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);
 	}
 
-	guid = ((u64)buffer[3] << 32) | buffer[4];
+	guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);
 	ne = find_entry_by_guid(guid);
 
+	if (ne && ne->host != host && ne->in_limbo) {
+		/* Must have moved this device from one host to another */
+		nodemgr_remove_ne(ne);
+		ne = NULL;
+	}
+
 	if (!ne)
-		nodemgr_create_node(guid, buffer[2], hi, nodeid, generation);
+		nodemgr_create_node(guid, csr, hi, nodeid, generation);
 	else
-		nodemgr_update_node(ne, buffer[2], hi, nodeid, generation);
+		nodemgr_update_node(ne, csr, hi, nodeid, generation);
 
 	return;
 }
 
 
-struct cleanup_baton {
-	unsigned int generation;
-	struct hpsb_host *host;
-	struct node_entry *ne;
-};
-
-static int nodemgr_remove_node(struct device *dev, void *__data)
+static void nodemgr_ud_update_pdrv(struct unit_directory *ud)
 {
-	struct cleanup_baton *cleanup = __data;
-	struct node_entry *ne;
+	struct device *dev;
+	struct hpsb_protocol_driver *pdrv;
 
-	if (dev->driver_data != &nodemgr_driverdata_ne)
-		return 0;
+	list_for_each_entry(dev, &ud->device.children, node)
+		nodemgr_ud_update_pdrv(container_of(dev, struct unit_directory, device));
 
-	ne = container_of(dev, struct node_entry, device);
+	pdrv = container_of(ud->device.driver, struct hpsb_protocol_driver, driver);
 
-	if (ne->host != cleanup->host)
-		return 0;
-
-	if (ne->generation != cleanup->generation) {
-		cleanup->ne = ne;
-		return 1;
-	}
-
-	return 0;
+	if (pdrv->update)
+		pdrv->update(ud);
 }
 
-struct ne_cb_data_struct {
-	struct host_info *hi;
-	struct node_entry *ne;
-};
 
-static int nodemgr_probe_ne_cb(struct device *dev, void *__data)
+static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne)
 {
-	struct ne_cb_data_struct *ne_cb_data = __data;
-	struct host_info *hi = ne_cb_data->hi;
-	struct node_entry *ne;
-
-	if (dev->driver_data != &nodemgr_driverdata_ne)
-		return 0;
-
-	ne = ne_cb_data->ne = container_of(dev, struct node_entry, device);
+	struct device *dev;
 
-	if (ne->host != hi->host)
-		return 0;
+	if (ne->host != hi->host || ne->in_limbo)
+		return;
 
-	/* We can't call nodemgr_process_root_directory() here because
-	 * that can call device_register. Since this callback is under a
-	 * rwsem, the device_register would deadlock. So, we signal back
-	 * to the callback, and process things there. */
+	dev = get_device(&ne->device);
+	if (!dev)
+		return;
 
 	if (ne->needs_probe) {
-		ne->needs_probe = 0;
-		return 1;
+		nodemgr_process_root_directory(hi, ne);
 	} else {
-		struct list_head *lh;
+		struct device *udev;
 
 		/* Update unit_dirs with attached drivers */
-		list_for_each(lh, &dev->children) {
-			struct unit_directory *ud;
-			
-			ud = container_of(list_to_dev(lh), struct unit_directory, device);
-
-			if (ud->device.driver) {
-				struct hpsb_protocol_driver *pdrv;
-
-				pdrv = container_of(ud->device.driver,
-						    struct hpsb_protocol_driver, driver);
-
-				if (pdrv->update)
-					pdrv->update(ud);
-			}
-		}
+		list_for_each_entry(udev, &dev->children, node)
+			nodemgr_ud_update_pdrv(container_of(udev, struct unit_directory, device));
 	}
-	return 0;
+
+	put_device(dev);
 }
 
 
@@ -1492,29 +1237,87 @@
         }
 }
 
+
+static void nodemgr_suspend_ud(struct unit_directory *ud)
+{
+	struct device *dev;
+
+	list_for_each_entry(dev, &ud->device.children, node)
+		nodemgr_suspend_ud(container_of(dev, struct unit_directory, device));
+
+	if (ud->device.driver) {
+		int ret = -1;
+
+		if (ud->device.driver->suspend)
+			ret = ud->device.driver->suspend(&ud->device, 0, 0);
+
+		if (ret) {
+			dev = &ud->device;
+			down_write(&dev->bus->subsys.rwsem);
+			device_release_driver(dev);
+			up_write(&dev->bus->subsys.rwsem);
+		}
+	}								
+}
+
+
+static void nodemgr_suspend_ne(struct node_entry *ne)
+{
+	struct device *dev;
+
+	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+
+	ne->in_limbo = 1;
+	device_create_file(&ne->device, &dev_attr_ne_in_limbo);
+
+	list_for_each_entry(dev, &ne->device.children, node)
+		nodemgr_suspend_ud(container_of(dev, struct unit_directory, device));
+}
+
+
+static void nodemgr_resume_ud(struct unit_directory *ud)
+{
+	struct device *dev;
+
+	list_for_each_entry(dev, &ud->device.children, node)
+		nodemgr_resume_ud(container_of(dev, struct unit_directory, device));
+
+	if (ud->device.driver && ud->device.driver->resume)
+		ud->device.driver->resume(&ud->device, 0);
+}
+
+
+static void nodemgr_resume_ne(struct node_entry *ne)
+{
+	struct device *dev;
+
+	ne->in_limbo = 0;
+	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
+
+	list_for_each_entry(dev, &ne->device.children, node)
+		nodemgr_resume_ud(container_of(dev, struct unit_directory, device));
+
+	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+}
+
+
 static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
 	struct hpsb_host *host = hi->host;
-	struct ne_cb_data_struct ne_cb_data;
-
-	ne_cb_data.hi = hi;
-	ne_cb_data.ne = NULL;
+	struct class *class = &nodemgr_ne_class;
+	struct class_device *cdev;
 
 	/* Do some processing of the nodes we've probed. This pulls them
 	 * into the sysfs layer if needed, and can result in processing of
 	 * unit-directories, or just updating the node and it's
 	 * unit-directories. */
-	while (bus_for_each_dev(&ieee1394_bus_type, ne_cb_data.ne ? &ne_cb_data.ne->device : NULL,
-	       &ne_cb_data, nodemgr_probe_ne_cb)) {
-		/* If we get in here, we've got a node that needs it's
-		 * unit directories processed. */
-		struct device *dev = get_device(&ne_cb_data.ne->device);
-
-		if (dev) {
-			nodemgr_process_root_directory(hi, ne_cb_data.ne);
-			put_device(dev);
-		}
-	}
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(cdev, &class->children, node)
+		nodemgr_probe_ne(hi, container_of(cdev, struct node_entry, class_dev));
+        up_read(&class->subsys.rwsem);
+
 
 	/* If we had a bus reset while we were scanning the bus, it is
 	 * possible that we did not probe all nodes.  In that case, we
@@ -1523,22 +1326,22 @@
 	 * so there's a bus scan pending which will do the clean up
 	 * eventually. */
 	if (generation == get_hpsb_generation(host)) {
-		struct cleanup_baton cleanup;
+		struct node_entry *ne;
 
-		cleanup.generation = generation;
-		cleanup.host = host;
+		/* Suspend any devices that are no longer connected */
+		down_read(&class->subsys.rwsem);
+		list_for_each_entry(cdev, &class->children, node) {
+			ne = container_of(cdev, struct node_entry, class_dev);
 
-		/* This will iterate until all devices that do not match
-		 * the generation are removed. */
-		while (bus_for_each_dev(&ieee1394_bus_type, NULL, &cleanup,
-					nodemgr_remove_node)) {
-			struct node_entry *ne = cleanup.ne;
+			if (ne->in_limbo || ne->host != host)
+				continue;
 
-			HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-				   NODE_BUS_ARGS(host, ne->nodeid), (unsigned long long)ne->guid);
+			if (ne->generation == generation)
+				continue;
 
-			nodemgr_remove_ne(ne);
+			nodemgr_suspend_ne(ne);
 		}
+		up_read(&class->subsys.rwsem);
 
 		/* Now let's tell the bus to rescan our devices. This may
 		 * seem like overhead, but the driver-model core will only
@@ -1736,32 +1539,24 @@
 	return ne;
 }
 
-struct for_each_host_struct {
-	int (*cb)(struct hpsb_host *, void *);
-	void *data;
-};
 
-static int nodemgr_for_each_host_cb(struct device *dev, void *__data)
+int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
 {
-	struct for_each_host_struct *host_data = __data;
+	struct class *class = &hpsb_host_class;
+	struct class_device *cdev;
 	struct hpsb_host *host;
+	int error = 0;
 
-	if (dev->driver_data != &nodemgr_driverdata_host)
-		return 0;
-
-	host = container_of(dev, struct hpsb_host, device);
-
-	return host_data->cb(host, host_data->data);
-}
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(cdev, &class->children, node) {
+		host = container_of(cdev, struct hpsb_host, class_dev);
 
-int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
-{
-	struct for_each_host_struct host_data;
-
-	host_data.cb = cb;
-	host_data.data = __data;
+		if ((error = cb(host, __data)))
+			break;
+	}
+	up_read(&class->subsys.rwsem);
 
-	return bus_for_each_dev(&ieee1394_bus_type, NULL, &host_data, nodemgr_for_each_host_cb);
+	return error;
 }
 
 /* The following four convenience functions use a struct node_entry
@@ -1887,6 +1682,7 @@
 {
 	driver_register(&nodemgr_driver_host);
 	driver_register(&nodemgr_driver_ne);
+	class_register(&nodemgr_ne_class);
 
 	hpsb_register_highlevel(&nodemgr_highlevel);
 }
@@ -1895,6 +1691,7 @@
 {
         hpsb_unregister_highlevel(&nodemgr_highlevel);
 
+	class_unregister(&nodemgr_ne_class);
 	driver_unregister(&nodemgr_driver_ne);
 	driver_unregister(&nodemgr_driver_host);
 }
--- diff/drivers/ieee1394/nodemgr.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/ieee1394/nodemgr.h	2004-02-18 09:03:59.000000000 +0000
@@ -21,50 +21,12 @@
 #define _IEEE1394_NODEMGR_H
 
 #include <linux/device.h>
+#include "csr1212.h"
 #include "ieee1394_core.h"
 #include "ieee1394_hotplug.h"
 
-#define CONFIG_ROM_BUS_INFO_LENGTH(q)		((q) >> 24)
-#define CONFIG_ROM_BUS_CRC_LENGTH(q)		(((q) >> 16) & 0xff)
-#define CONFIG_ROM_BUS_CRC(q)			((q) & 0xffff)
-
-#define CONFIG_ROM_ROOT_LENGTH(q)		((q) >> 16)
-#define CONFIG_ROM_ROOT_CRC(q)			((q) & 0xffff)
-
-#define CONFIG_ROM_DIRECTORY_LENGTH(q)		((q) >> 16)
-#define CONFIG_ROM_DIRECTORY_CRC(q)		((q) & 0xffff)
-
-#define CONFIG_ROM_LEAF_LENGTH(q)		((q) >> 16)
-#define CONFIG_ROM_LEAF_CRC(q)			((q) & 0xffff)
-
-#define CONFIG_ROM_DESCRIPTOR_TYPE(q)		((q) >> 24)
-#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q)	((q) & 0xffffff)
-#define CONFIG_ROM_DESCRIPTOR_WIDTH(q)		((q) >> 28)
-#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q)	(((q) >> 16) & 0xfff)
-#define CONFIG_ROM_DESCRIPTOR_LANG(q)		((q) & 0xffff)
-
-#define CONFIG_ROM_KEY_ID_MASK			0x3f
-#define CONFIG_ROM_KEY_TYPE_MASK		0xc0
-#define CONFIG_ROM_KEY_TYPE_IMMEDIATE		0x00
-#define CONFIG_ROM_KEY_TYPE_OFFSET		0x40
-#define CONFIG_ROM_KEY_TYPE_LEAF		0x80
-#define CONFIG_ROM_KEY_TYPE_DIRECTORY		0xc0
-
-#define CONFIG_ROM_KEY(q)			((q) >> 24)
-#define CONFIG_ROM_VALUE(q)			((q) & 0xffffff)
-
-#define CONFIG_ROM_VENDOR_ID			0x03
-#define CONFIG_ROM_MODEL_ID			0x17
-#define CONFIG_ROM_NODE_CAPABILITES		0x0C
-#define CONFIG_ROM_UNIT_DIRECTORY		0xd1
-#define CONFIG_ROM_LOGICAL_UNIT_DIRECTORY	0xd4
-#define CONFIG_ROM_SPECIFIER_ID			0x12 
-#define CONFIG_ROM_UNIT_SW_VERSION		0x13
-#define CONFIG_ROM_DESCRIPTOR_LEAF		0x81
-#define CONFIG_ROM_DESCRIPTOR_DIRECTORY		0xc1
-
 /* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC	0x31333934
+#define IEEE1394_BUSID_MAGIC	__constant_cpu_to_be32(0x31333934)
 
 /* This is the start of a Node entry structure. It should be a stable API
  * for which to gather info from the Node Manager about devices attached
@@ -76,6 +38,7 @@
 	u8	bmc;		/* Bus Master Capable */
 	u8	pmc;		/* Power Manager Capable (PNP spec) */
 	u8	cyc_clk_acc;	/* Cycle clock accuracy */
+	u8	max_rom;	/* Maximum block read supported in the CSR */
 	u8	generation;	/* Incremented when configrom changes */
 	u8	lnkspd;		/* Link speed */
 	u16	max_rec;	/* Maximum packet size node can receive */
@@ -86,10 +49,8 @@
 #define UNIT_DIRECTORY_MODEL_ID			0x02
 #define UNIT_DIRECTORY_SPECIFIER_ID		0x04
 #define UNIT_DIRECTORY_VERSION			0x08
-#define UNIT_DIRECTORY_VENDOR_TEXT		0x10
-#define UNIT_DIRECTORY_MODEL_TEXT		0x20
-#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY	0x40
-#define UNIT_DIRECTORY_LUN_DIRECTORY		0x80
+#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY	0x10
+#define UNIT_DIRECTORY_LUN_DIRECTORY		0x20
 
 /*
  * A unit directory corresponds to a protocol supported by the
@@ -98,17 +59,15 @@
  */
 struct unit_directory {
 	struct node_entry *ne;  /* The node which this directory belongs to */
-	octlet_t address;	/* Address of the unit directory on the node */
+	octlet_t address;       /* Address of the unit directory on the node */
 	u8 flags;		/* Indicates which entries were read */
 
 	quadlet_t vendor_id;
-	const char *vendor_name;
+	struct csr1212_keyval *vendor_name_kv;
 	const char *vendor_oui;
 
-	int vendor_name_size;
 	quadlet_t model_id;
-	const char *model_name;
-	int model_name_size;
+	struct csr1212_keyval *model_name_kv;
 	quadlet_t specifier_id;
 	quadlet_t version;
 
@@ -118,8 +77,7 @@
 
 	struct device device;
 
-	/* XXX Must be last in the struct! */
-	quadlet_t quadlets[0];
+	struct csr1212_keyval *ud_kv;
 };
 
 struct node_entry {
@@ -135,7 +93,7 @@
 
 	/* The following is read from the config rom */
 	u32 vendor_id;
-	const char *vendor_name;
+	struct csr1212_keyval *vendor_name_kv;
 	const char *vendor_oui;
 
 	u32 capabilities;
@@ -143,8 +101,12 @@
 
 	struct device device;
 
-	/* XXX Must be last in the struct! */
-	quadlet_t quadlets[0];
+	struct class_device class_dev;
+
+	/* Means this node is not attached anymore */
+	int in_limbo;
+
+	struct csr1212_csr *csr;
 };
 
 struct hpsb_protocol_driver {
@@ -231,4 +193,7 @@
 /* The template for a host device */
 extern struct device nodemgr_dev_template_host;
 
+/* Bus attribute to destroy limbo'd nodes */
+extern struct bus_attribute bus_attr_destroy;
+
 #endif /* _IEEE1394_NODEMGR_H */
--- diff/drivers/ieee1394/ohci1394.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/ohci1394.c	2004-02-18 09:03:59.000000000 +0000
@@ -115,6 +115,7 @@
 #include <asm/pci-bridge.h>
 #endif
 
+#include "csr1212.h"
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
@@ -161,7 +162,7 @@
 printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 1097 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1131 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 static int phys_dma = 1;
@@ -495,8 +496,6 @@
 	return ctx;
 }
 
-static void ohci_init_config_rom(struct ti_ohci *ohci);
-
 /* Global initialization */
 static void ohci_initialize(struct ti_ohci *ohci)
 {
@@ -540,9 +539,6 @@
 	/* Set the Config ROM mapping register */
 	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
 
-	/* Initialize the Config ROM */
-	ohci_init_config_rom(ohci);
-
 	/* Now get our max packet size */
 	ohci->max_packet_size = 
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
@@ -2211,14 +2207,12 @@
 				       quadlet_t rx_event,
 				       quadlet_t tx_event)
 {
-	struct list_head *lh;
 	struct ohci1394_iso_tasklet *t;
 	unsigned long mask;
 
 	spin_lock(&ohci->iso_tasklet_list_lock);
 
-	list_for_each(lh, &ohci->iso_tasklet_list) {
-		t = list_entry(lh, struct ohci1394_iso_tasklet, link);
+	list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
 		mask = 1 << t->context;
 
 		if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask)
@@ -3085,154 +3079,16 @@
 	return 0;
 }
 
-static u16 ohci_crc16 (u32 *ptr, int length)
-{
-	int shift;
-	u32 crc, sum, data;
-
-	crc = 0;
-	for (; length > 0; length--) {
-		data = be32_to_cpu(*ptr++);
-		for (shift = 28; shift >= 0; shift -= 4) {
-			sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;
-			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
-		}
-		crc &= 0xffff;
-	}
-	return crc;
-}
-
-/* Config ROM macro implementation influenced by NetBSD OHCI driver */
-
-struct config_rom_unit {
-	u32 *start;
-	u32 *refer;
-	int length;
-	int refunit;
-};
-
-struct config_rom_ptr {
-	u32 *data;
-	int unitnum;
-	struct config_rom_unit unitdir[10];
-};
-
-#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q))
-
-#define cf_put_4bytes(cr, b1, b2, b3, b4) \
-	(((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4)))
-
-#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))
-
-static inline void cf_put_str(struct config_rom_ptr *cr, const char *str)
-{
-	int t;
-	char fourb[4];
-
-	while (str[0]) {
-		memset(fourb, 0, 4);
-		for (t = 0; t < 4 && str[t]; t++)
-			fourb[t] = str[t];
-		cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]);
-		str += strlen(str) < 4 ? strlen(str) : 4;
-	}
-	return;
-}
-
-static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
-{
-	*cr->unitdir[unit].start =
-		cpu_to_be32((cr->unitdir[unit].length << 16) |
-			    ohci_crc16(cr->unitdir[unit].start + 1,
-				       cr->unitdir[unit].length));
-}
-
-static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit)
-{
-	if (cr->unitdir[unit].refer != NULL) {
-		*cr->unitdir[unit].refer |=
-			cpu_to_be32 (cr->data - cr->unitdir[unit].refer);
-		cf_put_crc16(cr, cr->unitdir[unit].refunit);
-	}
-	cr->unitnum = unit;
-	cr->unitdir[unit].start = cr->data++;
-}
-
-static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit)
-{
-	cr->unitdir[unit].refer = cr->data;
-	cr->unitdir[unit].refunit = cr->unitnum;
-	(cr->data++)[0] = cpu_to_be32(key << 24);
-}
-
-static inline void cf_unit_end(struct config_rom_ptr *cr)
+static void ohci_set_hw_config_rom(struct hpsb_host *host, quadlet_t *config_rom)
 {
-	cr->unitdir[cr->unitnum].length = cr->data -
-		(cr->unitdir[cr->unitnum].start + 1);
-	cf_put_crc16(cr, cr->unitnum);
-}
-
-/* End of NetBSD derived code.  */
-
-static void ohci_init_config_rom(struct ti_ohci *ohci)
-{
-	struct config_rom_ptr cr;
-
-	memset(&cr, 0, sizeof(cr));
-	memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
-
-	cr.data = ohci->csr_config_rom_cpu;
-
-	/* Bus info block */
-	cf_unit_begin(&cr, 0);
-	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID));
-	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions));
-	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi));
-	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo));
-	cf_unit_end(&cr);
-
-	DBGMSG(ohci->id, "GUID: %08x:%08x", reg_read(ohci, OHCI1394_GUIDHi),
-		reg_read(ohci, OHCI1394_GUIDLo));
-
-	/* IEEE P1212 suggests the initial ROM header CRC should only
-	 * cover the header itself (and not the entire ROM). Since we do
-	 * this, then we can make our bus_info_len the same as the CRC
-	 * length.  */
-	ohci->csr_config_rom_cpu[0] |= cpu_to_be32(
-		(be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8);
-	reg_write(ohci, OHCI1394_ConfigROMhdr,
-		  be32_to_cpu(ohci->csr_config_rom_cpu[0]));
-
-	/* Root directory */
-	cf_unit_begin(&cr, 1);
-	/* Vendor ID */
-	cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);
-	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
-	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
-	/* NOTE: Add other unit referers here, and append at bottom */
-	cf_unit_end(&cr);
+	struct ti_ohci *ohci = host->hostdata;
 
-	/* Textual description - "Linux 1394" */
-	cf_unit_begin(&cr, 2);
-	cf_put_keyval(&cr, 0, 0);
-	cf_put_1quad(&cr, 0);
-	cf_put_str(&cr, "Linux OHCI-1394");
-	cf_unit_end(&cr);
+	reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
+	reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
 
-	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
+	memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
 }
 
-static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
-{
-	struct ti_ohci *ohci=host->hostdata;
-
-	DBGMSG(ohci->id, "request csr_rom address: %p",
-		ohci->csr_config_rom_cpu);
-
-	*ptr = ohci->csr_config_rom_cpu;
-
-	return ohci->csr_config_rom_length * 4;
-}
 
 static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
                                  quadlet_t data, quadlet_t compare)
@@ -3257,7 +3113,7 @@
 static struct hpsb_host_driver ohci1394_driver = {
 	.owner =		THIS_MODULE,
 	.name =			OHCI1394_DRIVER_NAME,
-	.get_rom =		ohci_get_rom,
+	.set_hw_config_rom =	ohci_set_hw_config_rom,
 	.transmit_packet =	ohci_transmit,
 	.devctl =		ohci_devctl,
 	.isoctl =               ohci_isoctl,
@@ -3280,6 +3136,11 @@
 static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
 					const struct pci_device_id *ent)
 {
+	struct csr1212_keyval *root;
+	struct csr1212_keyval *vend_id = NULL;
+	struct csr1212_keyval *text = NULL;
+	int ret;
+
 	static int version_printed = 0;
 
 	struct hpsb_host *host;
@@ -3458,6 +3319,45 @@
 	ohci->init_state = OHCI_INIT_HAVE_IRQ;
 	ohci_initialize(ohci);
 
+	/* Setup initial root directory entries */
+	root = host->csr.rom->root_kv;
+
+	vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR,
+					reg_read(ohci, OHCI1394_GUIDHi) >> 8);
+	text = csr1212_new_string_descriptor_leaf("Linux 1394 - OHCI");
+
+	if (!vend_id || !text) {
+		if (vend_id) {
+			csr1212_release_keyval(vend_id);
+		}
+		if (text) {
+			csr1212_release_keyval(text);
+		}
+		FAIL(-ENOMEM, "Failed to allocate memory for mandatory ConfigROM entries!");
+	}
+
+	ret = csr1212_associate_keyval(vend_id, text);
+	csr1212_release_keyval(text);
+	if(ret != CSR1212_SUCCESS) {
+		csr1212_release_keyval(vend_id);
+		FAIL(ret, "Failed to associate text descriptor to vendor id");
+	}
+
+	ret = csr1212_attach_keyval_to_directory(root, vend_id);
+	if(ret != CSR1212_SUCCESS) {
+		csr1212_release_keyval(vend_id);
+		FAIL(ret, "Failed to attach vendor id to root directory");
+	}
+
+	host->update_config_rom = 1;
+
+	/* Set certain csr values */
+	host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
+	host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
+	host->csr.cyc_clk_acc = 100;  /* how do we determine clk accuracy? */
+	host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
+	host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
+
 	/* Tell the highlevel this host is ready */
 	hpsb_add_host(host);
 	ohci->init_state = OHCI_INIT_DONE;
@@ -3574,13 +3474,11 @@
 }
 
 
-#ifdef  CONFIG_PM
 static int ohci1394_pci_resume (struct pci_dev *dev)
 {
 	pci_enable_device(dev);
 	return 0;
 }
-#endif
 
 
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
@@ -3604,10 +3502,7 @@
 	.id_table =	ohci1394_pci_tbl,
 	.probe =	ohci1394_pci_probe,
 	.remove =	ohci1394_pci_remove,
-
-#ifdef  CONFIG_PM
 	.resume =	ohci1394_pci_resume,
-#endif  /* PM */
 };
 
 
--- diff/drivers/ieee1394/pcilynx.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/ieee1394/pcilynx.c	2004-02-18 09:03:59.000000000 +0000
@@ -49,6 +49,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+#include "csr1212.h"
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
@@ -1515,6 +1516,11 @@
         return error; \
         } while (0)
 
+	struct csr1212_keyval *root;
+	struct csr1212_keyval *vend_id = NULL;
+	struct csr1212_keyval *text = NULL;
+	int ret;
+
 	char irq_buf[16];
 	struct hpsb_host *host;
         struct ti_lynx *lynx; /* shortcut to currently handled device */
@@ -1527,8 +1533,6 @@
         struct i2c_adapter i2c_adapter;
         struct i2c_algo_bit_data i2c_adapter_data;
 
-        int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */
-
         error = -ENXIO;
 
         if (pci_set_dma_mask(dev, 0xffffffff))
@@ -1814,14 +1818,15 @@
 
         	if (i2c_bit_add_bus(&i2c_adapter) < 0)
         	{
-	        	PRINT(KERN_ERR, lynx->id,  "unable to register i2c");
+			error = -ENXIO;
+			FAIL("unable to register i2c");
         	}
         	else
         	{
                         /* do i2c stuff */
                         unsigned char i2c_cmd = 0x10;
                         struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd }, 
-                                                  { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom }
+                                                  { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
                                                 };
 
 
@@ -1858,16 +1863,16 @@
 
                                 for (i = 0; i < 5 ; i++)
                                         PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
-					       i, be32_to_cpu(lynx->config_rom[i]));
+					       i, be32_to_cpu(lynx->bus_info_block[i]));
 
                                 /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
-                                if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) &&
-                                    (lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934)))
+				if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
+				    (lynx->bus_info_block[1] == __constant_cpu_to_be32(0x31333934)))
                                 {
                                         PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
-                                        got_valid_bus_info_block = 1;
                                 } else {
-                                        PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block");
+					error = -ENXIO;
+					FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
                                 }
 
                         }
@@ -1876,29 +1881,55 @@
                 }
         }
 
-        if (got_valid_bus_info_block) {
-                memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20);
-        } else {
-                PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID");
-                memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom));
-        }
-
-        hpsb_add_host(host);
-        lynx->state = is_host;
+	host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
+	host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
+	host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
+	host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
+	if (!lynx->phyic.reg_1394a)
+		host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
+	else
+		host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
+
+	/* Setup initial root directory entries */
+	root = host->csr.rom->root_kv;
+
+	vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR,
+					be32_to_cpu(lynx->bus_info_block[3]) >> 8);
+	text = csr1212_new_string_descriptor_leaf("Linux 1394 - PCI-Lynx");
+
+	if (!vend_id || !text) {
+		if (vend_id)
+			csr1212_release_keyval(vend_id);
+		if (text)
+			csr1212_release_keyval(text);
+		error = -ENOMEM;
+		FAIL("Failed to allocate memory for mandatory ConfigROM entries!");
+	}
 
-        return 0;
-#undef FAIL
-}
+	ret = csr1212_associate_keyval(vend_id, text);
+	csr1212_release_keyval(text);		/* no longer needed locally. */
+	if(ret != CSR1212_SUCCESS) {
+		csr1212_release_keyval(vend_id);
+		error = ret;
+		FAIL("Failed to associate text descriptor to vendor id");
+	}
 
+	ret = csr1212_attach_keyval_to_directory(root, vend_id);
+	csr1212_release_keyval(vend_id);	/* no longer needed locally. */
+	if(ret != CSR1212_SUCCESS) {
+		error = ret;
+		FAIL("Failed to attach vendor id to root directory");
+	}
 
+	host->update_config_rom = 1;
+	hpsb_add_host(host);
+	lynx->state = is_host;
 
-static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        *ptr = lynx->config_rom;
-        return sizeof(lynx_csr_rom);
+	return ret;
+#undef FAIL
 }
 
+
 static struct pci_device_id pci_table[] = {
 	{
                 .vendor =    PCI_VENDOR_ID_TI,
@@ -1919,7 +1950,7 @@
 static struct hpsb_host_driver lynx_driver = {
 	.owner =	   THIS_MODULE,
 	.name =		   PCILYNX_DRIVER_NAME,
-        .get_rom =         get_lynx_rom,
+	.set_hw_config_rom = NULL,
         .transmit_packet = lynx_transmit,
         .devctl =          lynx_devctl,
 	.isoctl =          NULL,
--- diff/drivers/ieee1394/pcilynx.h	2003-02-26 16:01:01.000000000 +0000
+++ source/drivers/ieee1394/pcilynx.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,3 +1,6 @@
+#ifndef __PCILYNX_H__
+#define __PCILYNX_H__
+
 #include <linux/config.h>
 
 #define PCILYNX_DRIVER_NAME      "pcilynx"
@@ -50,7 +53,7 @@
         void *local_rom;
         void *local_ram;
         void *aux_port;
-        quadlet_t config_rom[PCILYNX_CONFIG_ROM_LENGTH/4];
+	quadlet_t bus_info_block[5];
 
 #ifdef CONFIG_IEEE1394_PCILYNX_PORTS
         atomic_t aux_intr_seen;
@@ -510,76 +513,4 @@
 #define PCL_BIGENDIAN          (1<<16)
 #define PCL_ISOMODE            (1<<12)
 
-
-#define _(x) (__constant_cpu_to_be32(x))
-
-static quadlet_t lynx_csr_rom[] = {
-/* bus info block     offset (hex) */
-        _(0x04046aaf), /* info/CRC length, CRC              400  */
-        _(0x31333934), /* 1394 magic number                 404  */
-        _(0xf064a000), /* misc. settings                    408  */
-        _(0x08002850), /* vendor ID, chip ID high           40c  */
-        _(0x0000ffff), /* chip ID low                       410  */
-/* root directory */
-        _(0x00095778), /* directory length, CRC             414  */
-        _(0x03080028), /* vendor ID (Texas Instr.)          418  */
-        _(0x81000008), /* offset to textual ID              41c  */
-        _(0x0c000200), /* node capabilities                 420  */
-        _(0x8d00000e), /* offset to unique ID               424  */
-        _(0xc7000010), /* offset to module independent info 428  */
-        _(0x04000000), /* module hardware version           42c  */
-        _(0x81000014), /* offset to textual ID              430  */
-        _(0x09000000), /* node hardware version             434  */
-        _(0x81000018), /* offset to textual ID              438  */
-/* module vendor ID textual */
-        _(0x00070812), /* CRC length, CRC                   43c  */
-        _(0x00000000), /*                                   440  */
-        _(0x00000000), /*                                   444  */
-        _(0x54455841), /* "Texas Instruments"               448  */
-        _(0x5320494e), /*                                   44c  */
-        _(0x53545255), /*                                   450  */
-        _(0x4d454e54), /*                                   454  */
-        _(0x53000000), /*                                   458  */
-/* node unique ID leaf */
-        _(0x00022ead), /* CRC length, CRC                   45c  */
-        _(0x08002850), /* vendor ID, chip ID high           460  */
-        _(0x0000ffff), /* chip ID low                       464  */
-/* module dependent info */
-        _(0x0005d837), /* CRC length, CRC                   468  */
-        _(0x81000012), /* offset to module textual ID       46c  */
-        _(0x81000017), /* textual descriptor                470  */
-        _(0x39010000), /* SRAM size                         474  */
-        _(0x3a010000), /* AUXRAM size                       478  */
-        _(0x3b000000), /* AUX device                        47c  */
-/* module textual ID */
-        _(0x000594df), /* CRC length, CRC                   480  */
-        _(0x00000000), /*                                   484  */
-        _(0x00000000), /*                                   488  */
-        _(0x54534231), /* "TSB12LV21"                       48c  */
-        _(0x324c5632), /*                                   490  */
-        _(0x31000000), /*                                   494  */
-/* part number */
-        _(0x00068405), /* CRC length, CRC                   498  */
-        _(0x00000000), /*                                   49c  */
-        _(0x00000000), /*                                   4a0  */
-        _(0x39383036), /* "9806000-0001"                    4a4  */
-        _(0x3030302d), /*                                   4a8  */
-        _(0x30303031), /*                                   4ac  */
-        _(0x20000001), /*                                   4b0  */
-/* module hardware version textual */
-        _(0x00056501), /* CRC length, CRC                   4b4  */
-        _(0x00000000), /*                                   4b8  */
-        _(0x00000000), /*                                   4bc  */
-        _(0x5453424b), /* "TSBKPCITST"                      4c0  */
-        _(0x50434954), /*                                   4c4  */
-        _(0x53540000), /*                                   4c8  */
-/* node hardware version textual */
-        _(0x0005d805), /* CRC length, CRC                   4d0  */
-        _(0x00000000), /*                                   4d4  */
-        _(0x00000000), /*                                   4d8  */
-        _(0x54534232), /* "TSB21LV03"                       4dc  */
-        _(0x314c5630), /*                                   4e0  */
-        _(0x33000000)  /*                                   4e4  */
-};
-
-#undef _
+#endif
--- diff/drivers/ieee1394/raw1394-private.h	2003-02-26 16:01:01.000000000 +0000
+++ source/drivers/ieee1394/raw1394-private.h	2004-02-18 09:03:59.000000000 +0000
@@ -7,6 +7,8 @@
 #define RAW1394_DEVICE_MAJOR      171
 #define RAW1394_DEVICE_NAME       "raw1394"
 
+#define RAW1394_MAX_USER_CSR_DIRS	16
+
 struct iso_block_store {
         atomic_t refcount;
         size_t data_size;
@@ -45,6 +47,12 @@
 	/* new rawiso API */
 	enum raw1394_iso_state iso_state;
 	struct hpsb_iso *iso_handle;
+
+	/* User space's CSR1212 dynamic ConfigROM directories */
+	struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
+
+	/* Legacy ConfigROM update flag */
+	u8 cfgrom_upd;
 };
 
 struct arm_addr {
--- diff/drivers/ieee1394/raw1394.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/raw1394.c	2004-02-18 09:03:59.000000000 +0000
@@ -43,6 +43,7 @@
 #include <asm/atomic.h>
 #include <linux/devfs_fs_kernel.h>
 
+#include "csr1212.h"
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "ieee1394_core.h"
@@ -214,15 +215,11 @@
 
 static struct host_info *find_host_info(struct hpsb_host *host)
 {
-        struct list_head *lh;
         struct host_info *hi;
 
-        list_for_each(lh, &host_info_list) {
-                hi = list_entry(lh, struct host_info, list);
-                if (hi->host == host) {
+        list_for_each_entry(hi, &host_info_list, list)
+                if (hi->host == host)
                         return hi;
-                }
-        }
 
         return NULL;
 }
@@ -261,7 +258,6 @@
 static void host_reset(struct hpsb_host *host)
 {
         unsigned long flags;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi;
         struct pending_request *req;
@@ -270,8 +266,7 @@
         hi = find_host_info(host);
 
         if (hi != NULL) {
-                list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
+                list_for_each_entry(fi, &hi->file_info_list, list) {
                         if (fi->notification == RAW1394_NOTIFY_ON) {
                                 req = __alloc_pending_request(SLAB_ATOMIC);
 
@@ -298,7 +293,6 @@
                         size_t length)
 {
         unsigned long flags;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi;
         struct pending_request *req;
@@ -314,12 +308,9 @@
         hi = find_host_info(host);
 
         if (hi != NULL) {
-		list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
-
-                        if (!(fi->listen_channels & (1ULL << channel))) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+                        if (!(fi->listen_channels & (1ULL << channel)))
                                 continue;
-                        }
 
                         req = __alloc_pending_request(SLAB_ATOMIC);
                         if (!req) break;
@@ -354,20 +345,14 @@
         }
         spin_unlock_irqrestore(&host_info_lock, flags);
 
-        lh = reqs.next;
-        while (lh != &reqs) {
-                req = list_entry(lh, struct pending_request, list);
-                lh = lh->next;
-
+	list_for_each_entry(req, &reqs, list)
                 queue_complete_req(req);
-        }
 }
 
 static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
 			int cts, u8 *data, size_t length)
 {
         unsigned long flags;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi;
         struct pending_request *req;
@@ -383,12 +368,9 @@
         hi = find_host_info(host);
 
         if (hi != NULL) {
-		list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
-
-                        if (!fi->fcp_buffer) {
+		list_for_each_entry(fi, &hi->file_info_list, list) {
+                        if (!fi->fcp_buffer)
                                 continue;
-                        }
 
                         req = __alloc_pending_request(SLAB_ATOMIC);
                         if (!req) break;
@@ -423,13 +405,8 @@
         }
         spin_unlock_irqrestore(&host_info_lock, flags);
 
-        lh = reqs.next;
-        while (lh != &reqs) {
-                req = list_entry(lh, struct pending_request, list);
-                lh = lh->next;
-
+	list_for_each_entry(req, &reqs, list)
                 queue_complete_req(req);
-        }
 }
 
 
@@ -505,7 +482,6 @@
 
 static int state_initialized(struct file_info *fi, struct pending_request *req)
 {
-        struct list_head *lh;
         struct host_info *hi;
         struct raw1394_khost_list *khl;
 
@@ -527,12 +503,9 @@
                         req->req.misc = host_count;
                         req->data = (quadlet_t *)khl;
                         
-                        list_for_each(lh, &host_info_list) {
-                                hi = list_entry(lh, struct host_info, list);
-
+                        list_for_each_entry(hi, &host_info_list, list) {
                                 khl->nodes = hi->host->node_count;
                                 strcpy(khl->name, hi->host->driver->name);
-
                                 khl++;
                         }
                 }
@@ -550,23 +523,17 @@
                 break;
 
         case RAW1394_REQ_SET_CARD:
-                lh = NULL;
-
                 spin_lock_irq(&host_info_lock);
                 if (req->req.misc < host_count) {
-                        lh = host_info_list.next;
-                        while (req->req.misc--) {
-                                lh = lh->next;
-                        }
-                        hi = list_entry(lh, struct host_info, list);
+			list_for_each_entry(hi, &host_info_list, list) {
+				if (!req->req.misc--)
+					break;
+			}
 			get_device(&hi->host->device); // XXX Need to handle failure case
                         list_add_tail(&fi->list, &hi->file_info_list);
                         fi->host = hi->host;
                         fi->state = connected;
-                }
-                spin_unlock_irq(&host_info_lock);
 
-                if (lh != NULL) {
                         req->req.error = RAW1394_ERROR_NONE;
                         req->req.generation = get_hpsb_generation(fi->host);
                         req->req.misc = (fi->host->node_id << 16) 
@@ -577,6 +544,7 @@
                 } else {
                         req->req.error = RAW1394_ERROR_INVALID_ARG;
                 }
+		spin_unlock_irq(&host_info_lock);
 
                 req->req.length = 0;
                 break;
@@ -898,7 +866,6 @@
 		     u64 addr, size_t length, u16 flags)
 {
         struct pending_request *req;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi = NULL;
         struct list_head *entry;
@@ -915,8 +882,7 @@
         spin_lock(&host_info_lock);
         hi = find_host_info(host); /* search address-entry */
         if (hi != NULL) {
-                list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
+                list_for_each_entry(fi, &hi->file_info_list, list) {
                         entry = fi->addr_list.next;
                         while (entry != &(fi->addr_list)) {
                                 arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1034,7 +1000,6 @@
 		      quadlet_t *data, u64 addr, size_t length, u16 flags)
 {
         struct pending_request *req;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi = NULL;
         struct list_head *entry;
@@ -1051,8 +1016,7 @@
         spin_lock(&host_info_lock);
         hi = find_host_info(host); /* search address-entry */
         if (hi != NULL) {
-                list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
+                list_for_each_entry(fi, &hi->file_info_list, list) {
                         entry = fi->addr_list.next;
                         while (entry != &(fi->addr_list)) {
                                 arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1161,7 +1125,6 @@
              u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct pending_request *req;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi = NULL;
         struct list_head *entry;
@@ -1187,8 +1150,7 @@
         spin_lock(&host_info_lock);
         hi = find_host_info(host); /* search address-entry */
         if (hi != NULL) {
-                list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
+                list_for_each_entry(fi, &hi->file_info_list, list) {
                         entry = fi->addr_list.next;
                         while (entry != &(fi->addr_list)) {
                                 arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1359,7 +1321,6 @@
                u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct pending_request *req;
-        struct list_head *lh;
         struct host_info *hi;
         struct file_info *fi = NULL;
         struct list_head *entry;
@@ -1394,8 +1355,7 @@
         spin_lock(&host_info_lock);
         hi = find_host_info(host); /* search addressentry in file_info's for host */
         if (hi != NULL) {
-                list_for_each(lh, &hi->file_info_list) {
-                        fi = list_entry(lh, struct file_info, list);
+                list_for_each_entry(fi, &hi->file_info_list, list) {
                         entry = fi->addr_list.next;
                         while (entry != &(fi->addr_list)) {
                                 arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1566,7 +1526,6 @@
 {
         int retval;
         struct arm_addr *addr;
-        struct list_head *lh, *lh_1, *lh_2;
         struct host_info *hi;
         struct file_info *fi_hlp = NULL;
         struct list_head *entry;
@@ -1630,8 +1589,7 @@
         same_host = 0;
         another_host = 0;
         /* same host with address-entry containing same addressrange ? */
-        list_for_each(lh, &hi->file_info_list) {
-                fi_hlp = list_entry(lh, struct file_info, list);
+        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
                 entry = fi_hlp->addr_list.next;
                 while (entry != &(fi_hlp->addr_list)) {
                         arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1656,11 +1614,9 @@
                 return (-EALREADY);
         }
         /* another host with valid address-entry containing same addressrange */
-        list_for_each(lh_1, &host_info_list) {
-                hi = list_entry(lh_1, struct host_info, list);
+        list_for_each_entry(hi, &host_info_list, list) {
                 if (hi->host != fi->host) {
-                        list_for_each(lh_2, &hi->file_info_list) {
-                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
                                 entry = fi_hlp->addr_list.next;
                                 while (entry != &(fi_hlp->addr_list)) {
                                         arm_addr = list_entry(entry, struct arm_addr, addr_list);
@@ -1719,7 +1675,6 @@
         int retval = 0;
         struct list_head *entry;
         struct arm_addr  *addr = NULL;
-        struct list_head *lh_1, *lh_2;
         struct host_info *hi;
         struct file_info *fi_hlp = NULL;
         struct arm_addr  *arm_addr = NULL;
@@ -1750,11 +1705,9 @@
         another_host = 0;
         /* another host with valid address-entry containing 
            same addressrange */
-        list_for_each(lh_1, &host_info_list) {
-                hi = list_entry(lh_1, struct host_info, list);
+        list_for_each_entry(hi, &host_info_list, list) {
                 if (hi->host != fi->host) {
-                        list_for_each(lh_2, &hi->file_info_list) {
-                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                        list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
                                 entry = fi_hlp->addr_list.next;
                                 while (entry != &(fi_hlp->addr_list)) {
                                         arm_addr = list_entry(entry, 
@@ -1822,9 +1775,9 @@
 			if (req->req.address + req->req.length <= arm_addr->end) {
 				offset = req->req.address - arm_addr->start;
 
-				DBGMSG("arm_get_buf copy_to_user( %08X, %08X, %u )",
+				DBGMSG("arm_get_buf copy_to_user( %08X, %p, %u )",
 				       (u32) req->req.recvb,
-				       (u32) (arm_addr->addr_space_buffer+offset),
+				       arm_addr->addr_space_buffer+offset,
 				       (u32) req->req.length);
 
 				if (copy_to_user(int2ptr(req->req.recvb), arm_addr->addr_space_buffer+offset, req->req.length)) {
@@ -1833,7 +1786,10 @@
 				}
 
 				spin_unlock_irqrestore(&host_info_lock, flags);
-				free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+				/* We have to free the request, because we
+				 * queue no response, and therefore nobody
+				 * will free it. */
+				free_pending_request(req);
 				return sizeof(struct raw1394_request);
 			} else {
 				DBGMSG("arm_get_buf request exceeded mapping");
@@ -1873,8 +1829,8 @@
 			if (req->req.address + req->req.length <= arm_addr->end) {
 				offset = req->req.address - arm_addr->start;
 
-				DBGMSG("arm_set_buf copy_from_user( %08X, %08X, %u )",
-				       (u32) (arm_addr->addr_space_buffer+offset),
+				DBGMSG("arm_set_buf copy_from_user( %p, %08X, %u )",
+				       arm_addr->addr_space_buffer+offset,
 				       (u32) req->req.sendb,
 				       (u32) req->req.length);
 
@@ -1941,22 +1897,22 @@
 
 static int get_config_rom(struct file_info *fi, struct pending_request *req)
 {
-        size_t return_size;
-        unsigned char rom_version;
         int ret=sizeof(struct raw1394_request);
         quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
         int status;
+
         if (!data) return -ENOMEM;
-        status = hpsb_get_config_rom(fi->host, data, 
-                req->req.length, &return_size, &rom_version);
+
+	status = csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
+			      data, req->req.length);
         if (copy_to_user(int2ptr(req->req.recvb), data, 
                 req->req.length))
                 ret = -EFAULT;
-        if (copy_to_user(int2ptr(req->req.tag), &return_size, 
-                sizeof(return_size)))
+	if (copy_to_user(int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
+			 sizeof(fi->host->csr.rom->cache_head->len)))
                 ret = -EFAULT;
-        if (copy_to_user(int2ptr(req->req.address), &rom_version, 
-                sizeof(rom_version)))
+	if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
+			 sizeof(fi->host->csr.generation)))
                 ret = -EFAULT;
         if (copy_to_user(int2ptr(req->req.sendb), &status, 
                 sizeof(status)))
@@ -1987,10 +1943,122 @@
         kfree(data);
         if (ret >= 0) {
                 free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+		fi->cfgrom_upd = 1;
         }
         return ret;
 }
 
+static int modify_config_rom(struct file_info *fi, struct pending_request *req)
+{
+	struct csr1212_keyval *kv;
+	struct csr1212_csr_rom_cache *cache;
+	struct csr1212_dentry *dentry;
+	u32 dr;
+	int ret = 0;
+
+	if (req->req.misc == ~0) {
+		if (req->req.length == 0) return -EINVAL;
+
+		/* Find an unused slot */
+		for (dr = 0; dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr]; dr++);
+
+		if (dr == RAW1394_MAX_USER_CSR_DIRS) return -ENOMEM;
+
+		fi->csr1212_dirs[dr] = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
+		if (!fi->csr1212_dirs[dr]) return -ENOMEM;
+	} else {
+		dr = req->req.misc;
+		if (!fi->csr1212_dirs[dr]) return -EINVAL;
+
+		/* Delete old stuff */
+		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		     dentry; dentry = dentry->next) {
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv,
+							     dentry->kv);
+		}
+
+		if (req->req.length == 0) {
+			csr1212_release_keyval(fi->csr1212_dirs[dr]);
+			fi->csr1212_dirs[dr] = NULL;
+
+			hpsb_update_config_rom_image(fi->host);
+			free_pending_request(req);
+			return sizeof(struct raw1394_request);
+		}
+	}
+
+	cache = csr1212_rom_cache_malloc(0, req->req.length);
+	if (!cache) {
+		csr1212_release_keyval(fi->csr1212_dirs[dr]);
+		fi->csr1212_dirs[dr] = NULL;
+		return -ENOMEM;
+	}
+
+	cache->filled_head = kmalloc(sizeof(struct csr1212_cache_region), GFP_KERNEL);
+	if (!cache->filled_head) {
+		csr1212_release_keyval(fi->csr1212_dirs[dr]);
+		fi->csr1212_dirs[dr] = NULL;
+		CSR1212_FREE(cache);
+		return -ENOMEM;
+	}
+	cache->filled_tail = cache->filled_head;
+
+	if (copy_from_user(cache->data, int2ptr(req->req.sendb),
+			   req->req.length)) {
+		csr1212_release_keyval(fi->csr1212_dirs[dr]);
+		fi->csr1212_dirs[dr] = NULL;
+		CSR1212_FREE(cache);
+		ret= -EFAULT;
+	} else {
+		cache->len = req->req.length;
+		cache->filled_head->offset_start = 0;
+		cache->filled_head->offset_end = cache->size -1;
+
+		cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
+
+		ret = CSR1212_SUCCESS;
+		/* parse all the items */
+		for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
+		     kv = kv->next) {
+			ret = csr1212_parse_keyval(kv, cache);
+		}
+
+		/* attach top level items to the root directory */
+		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		     ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
+			ret = csr1212_attach_keyval_to_directory(fi->host->csr.rom->root_kv,
+								 dentry->kv);
+		}
+
+		if (ret == CSR1212_SUCCESS) {
+			ret = hpsb_update_config_rom_image(fi->host);
+
+			if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb), 
+						    &dr, sizeof(dr))) {
+				ret = -ENOMEM;
+			}
+		}
+	}
+	kfree(cache->filled_head);
+	kfree(cache);
+
+	if (ret >= 0) {
+		/* we have to free the request, because we queue no response,
+		 * and therefore nobody will free it */		
+		free_pending_request(req);
+		return sizeof(struct raw1394_request);
+	} else {
+		for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head;
+		     dentry; dentry = dentry->next) {
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv,
+							     dentry->kv);
+		}
+		csr1212_release_keyval(fi->csr1212_dirs[dr]);
+		fi->csr1212_dirs[dr] = NULL;
+		return ret;
+	}
+}
+
 static int state_connected(struct file_info *fi, struct pending_request *req)
 {
         int node = req->req.address >> 48;
@@ -2049,6 +2117,9 @@
 
         case RAW1394_REQ_UPDATE_ROM:
                 return update_config_rom(fi, req);
+
+	case RAW1394_REQ_MODIFY_ROM:
+		return modify_config_rom(fi, req);
         }
 
         if (req->req.generation != get_hpsb_generation(fi->host)) {
@@ -2125,15 +2196,11 @@
  * completion queue (reqlists_lock must be taken) */
 static inline int __rawiso_event_in_queue(struct file_info *fi)
 {
-	struct list_head *lh;
 	struct pending_request *req;
 
-	list_for_each(lh, &fi->req_complete) {
-		req = list_entry(lh, struct pending_request, list);
-		if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) {
+	list_for_each_entry(req, &fi->req_complete, list)
+		if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
 			return 1;
-		}
-	}
 
 	return 0;
 }
@@ -2167,15 +2234,14 @@
 static void rawiso_activity_cb(struct hpsb_iso *iso)
 {
 	unsigned long flags;
-        struct list_head *lh;
         struct host_info *hi;
+	struct file_info *fi;
 
         spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(iso->host);
 
 	if (hi != NULL) {
-		list_for_each(lh, &hi->file_info_list) {
-			struct file_info *fi = list_entry(lh, struct file_info, list);
+		list_for_each_entry(fi, &hi->file_info_list, list) {
 			if (fi->iso_handle == iso)
 				queue_rawiso_event(fi);
 		}
@@ -2495,11 +2561,11 @@
         int retval = 0;
         struct list_head *entry;
         struct arm_addr  *addr = NULL;
-        struct list_head *lh_1, *lh_2;
         struct host_info *hi;
         struct file_info *fi_hlp = NULL;
         struct arm_addr  *arm_addr = NULL;
         int another_host;
+	int csr_mod = 0;
 
 	if (fi->iso_state != RAW1394_ISO_INACTIVE)
 		raw1394_iso_shutdown(fi);
@@ -2524,11 +2590,9 @@
                 addr = list_entry(lh, struct arm_addr, addr_list);
                 /* another host with valid address-entry containing 
                    same addressrange? */
-                list_for_each(lh_1, &host_info_list) {
-                        hi = list_entry(lh_1, struct host_info, list);
+                list_for_each_entry(hi, &host_info_list, list) {
                         if (hi->host != fi->host) {
-                                list_for_each(lh_2, &hi->file_info_list) {
-                                        fi_hlp = list_entry(lh_2, struct file_info, list);
+                                list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
                                         entry = fi_hlp->addr_list.next;
                                         while (entry != &(fi_hlp->addr_list)) {
                                                 arm_addr = list_entry(entry, 
@@ -2587,6 +2651,22 @@
                 if (!done) down_interruptible(&fi->complete_sem);
         }
 
+	/* Remove any sub-trees left by user space programs */
+	for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
+		struct csr1212_dentry *dentry;
+		if (!fi->csr1212_dirs[i]) continue;
+		for (dentry = fi->csr1212_dirs[i]->value.directory.dentries_head;
+		     dentry; dentry = dentry->next) {
+			csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv, dentry->kv);
+		}
+		csr1212_release_keyval(fi->csr1212_dirs[i]);
+		fi->csr1212_dirs[i] = NULL;
+		csr_mod = 1;
+	}
+
+	if ((csr_mod || fi->cfgrom_upd) && hpsb_update_config_rom_image(fi->host) < 0)
+		HPSB_ERR("Failed to generate Configuration ROM image for host %d", fi->host->id);
+
         if (fi->state == connected) {
                 spin_lock_irq(&host_info_lock);
                 list_del(&fi->list);
--- diff/drivers/ieee1394/raw1394.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/ieee1394/raw1394.h	2004-02-18 09:03:59.000000000 +0000
@@ -27,6 +27,7 @@
 #define RAW1394_REQ_GET_ROM         203
 #define RAW1394_REQ_UPDATE_ROM      204
 #define RAW1394_REQ_ECHO            205
+#define RAW1394_REQ_MODIFY_ROM      206
 
 #define RAW1394_REQ_ARM_REGISTER    300
 #define RAW1394_REQ_ARM_UNREGISTER  301
--- diff/drivers/ieee1394/sbp2.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/sbp2.c	2004-02-18 09:03:59.000000000 +0000
@@ -67,6 +67,7 @@
 #include "../scsi/scsi.h"
 #include "../scsi/hosts.h"
 
+#include "csr1212.h"
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "ieee1394_core.h"
@@ -77,7 +78,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 1096 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 1130 $ Ben Collins <bcollins@debian.org>";
 
 /*
  * Module load parameter definitions
@@ -233,6 +234,7 @@
 static struct hpsb_highlevel sbp2_highlevel = {
 	.name =		SBP2_DEVICE_NAME,
 	.remove_host =	sbp2_remove_host,
+	.host_reset =	sbp2_host_reset,
 };
 
 static struct hpsb_address_ops sbp2_ops = {
@@ -468,14 +470,12 @@
 static struct sbp2_command_info *sbp2util_find_command_for_orb(
 		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
 {
-	struct list_head *lh;
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
 	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
-		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
-			command = list_entry(lh, struct sbp2_command_info, list);
+		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
 			if (command->command_orb_dma == orb) {
 				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 				return (command);
@@ -495,14 +495,12 @@
  */
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
 {
-	struct list_head *lh;
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
 	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
-		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
-			command = list_entry(lh, struct sbp2_command_info, list);
+		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
 			if (command->Current_SCpnt == SCpnt) {
 				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 				return (command);
@@ -665,6 +663,8 @@
 			 * Ok, reconnect has failed. Perhaps we didn't
 			 * reconnect fast enough. Try doing a regular login.
 			 */
+			sbp2_logout_device(scsi_id);
+
 			if (sbp2_login_device(scsi_id)) {
 				/* Login failed too, just remove the device. */
 				SBP2_ERR("sbp2_reconnect_device failed!");
@@ -771,9 +771,8 @@
 
 static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *ud)
 {
-	struct scsi_id_instance_data *scsi_id;
+	struct scsi_id_instance_data *scsi_id, *scsi_id_tmp;
 	struct scsi_id_group *scsi_group;
-	struct list_head *lh, *next;
 
 	SBP2_DEBUG("sbp2_start_ud");
 
@@ -785,22 +784,13 @@
 
 	INIT_LIST_HEAD(&scsi_group->scsi_id_list);
 	ud->device.driver_data = scsi_group;
-	sbp2_parse_unit_directory(scsi_group, ud);
-
-	list_for_each_safe (lh, next, &scsi_group->scsi_id_list) {
-		scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
+	sbp2_parse_unit_directory(scsi_group, ud, hi);
 
-		scsi_id->ne = ud->ne;
-		scsi_id->hi = hi;
-		scsi_id->speed_code = IEEE1394_SPEED_100;
-		scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
-		atomic_set(&scsi_id->sbp2_login_complete, 0);
-		INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
-		INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
-		scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
+	/* Make sure the scsi_host is ready for this */
+	scsi_unblock_requests(hi->scsi_host);
 
+	list_for_each_entry_safe(scsi_id, scsi_id_tmp, &scsi_group->scsi_id_list, list)
 		sbp2_start_device(scsi_id);
-	}
 
 	/* Check to see if any of our devices survived the ordeal */
 	if (list_empty(&scsi_group->scsi_id_list)) {
@@ -812,6 +802,16 @@
 }
 
 
+static void sbp2_host_reset(struct hpsb_host *host)
+{
+	struct sbp2scsi_host_info *hi;
+
+	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
+
+	scsi_block_requests(hi->scsi_host);
+}
+
+
 /*
  * This function is where we first pull the node unique ids, and then
  * allocate memory and register a SBP-2 device.
@@ -1012,7 +1012,7 @@
 	/* Remove it from the scsi layer now */
 	if (scsi_id->sdev) {
 		scsi_remove_device(scsi_id->sdev);
-		scsi_device_put(scsi_id->sdev);
+		//scsi_device_put(scsi_id->sdev);
 	}
 
 	sbp2util_remove_command_orb_pool(scsi_id);
@@ -1530,16 +1530,35 @@
 	return(0);
 }
 
+
+static void sbp2_prep_scsi_id(struct scsi_id_instance_data *scsi_id,
+			      struct unit_directory *ud,
+			      struct sbp2scsi_host_info *hi)
+{
+	memset(scsi_id, 0, sizeof(*scsi_id));
+
+	scsi_id->ne = ud->ne;
+	scsi_id->hi = hi;
+	scsi_id->speed_code = IEEE1394_SPEED_100;
+	scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
+	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
+	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
+	scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
+}
+
 /*
  * This function is called to parse sbp2 device's config rom unit
  * directory. Used to determine things like sbp2 management agent offset,
  * and command set used (SCSI or RBC). 
  */
 static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
-				      struct unit_directory *ud)
+				      struct unit_directory *ud,
+				      struct sbp2scsi_host_info *hi)
 {
+	struct csr1212_keyval *kv;
+	struct csr1212_dentry *dentry;
 	struct scsi_id_instance_data *scsi_id;
-	struct list_head *lh;
 	u64 management_agent_addr;
 	u32 command_set_spec_id, command_set, unit_characteristics,
 		firmware_revision, workarounds;
@@ -1554,29 +1573,46 @@
 	firmware_revision = 0x0;
 
 	/* Handle different fields in the unit directory, based on keys */
-	for (i = 0; i < ud->length; i++) {
-		switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
-		case SBP2_CSR_OFFSET_KEY:
-			/* Save off the management agent address */
-			management_agent_addr =
-				CSR_REGISTER_BASE + 
-				(CONFIG_ROM_VALUE(ud->quadlets[i]) << 2);
+	csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
+		switch (kv->key.id) {
+		case CSR1212_KV_ID_DEPENDENT_INFO:
+			if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET) {
+				/* Save off the management agent address */
+				management_agent_addr =
+					CSR1212_REGISTER_SPACE_BASE +
+					(kv->value.csr_offset << 2);
+
+				SBP2_DEBUG("sbp2_management_agent_addr = %x",
+					   (unsigned int) management_agent_addr);
+			} else {
+				/*
+				 * Device type and lun (used for
+				 * detemining type of sbp2 device)
+				 */
+				scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
+				if (!scsi_id) {
+					SBP2_ERR("Out of memory adding scsi_id, not all LUN's will be added");
+					break;
+				}
+				sbp2_prep_scsi_id(scsi_id, ud, hi);
 
-			SBP2_DEBUG("sbp2_management_agent_addr = %x",
-				   (unsigned int) management_agent_addr);
+				scsi_id->sbp2_device_type_and_lun = kv->value.immediate;
+				SBP2_DEBUG("sbp2_device_type_and_lun = %x",
+					   (unsigned int) scsi_id->sbp2_device_type_and_lun);
+				list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list);
+			}
 			break;
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
 			/* Command spec organization */
-			command_set_spec_id
-				= CONFIG_ROM_VALUE(ud->quadlets[i]);
+			command_set_spec_id = kv->value.immediate;
 			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
 				   (unsigned int) command_set_spec_id);
 			break;
 
 		case SBP2_COMMAND_SET_KEY:
 			/* Command set used by sbp2 device */
-			command_set = CONFIG_ROM_VALUE(ud->quadlets[i]);
+			command_set = kv->value.immediate;
 			SBP2_DEBUG("sbp2_command_set = %x",
 				   (unsigned int) command_set);
 			break;
@@ -1586,35 +1622,14 @@
 			 * Unit characterisitcs (orb related stuff
 			 * that I'm not yet paying attention to)
 			 */
-			unit_characteristics
-				= CONFIG_ROM_VALUE(ud->quadlets[i]);
+			unit_characteristics = kv->value.immediate;
 			SBP2_DEBUG("sbp2_unit_characteristics = %x",
 				   (unsigned int) unit_characteristics);
 			break;
 
-		case SBP2_DEVICE_TYPE_AND_LUN_KEY:
-			/*
-			 * Device type and lun (used for
-			 * detemining type of sbp2 device)
-			 */
-			scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
-			if (!scsi_id) {
-				SBP2_ERR("Out of memory adding scsi_id, not all LUN's will be added");
-				break;
-			}
-			memset(scsi_id, 0, sizeof(*scsi_id));
-
-			scsi_id->sbp2_device_type_and_lun
-				= CONFIG_ROM_VALUE(ud->quadlets[i]);
-			SBP2_DEBUG("sbp2_device_type_and_lun = %x",
-				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
-			list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list);
-			break;
-
 		case SBP2_FIRMWARE_REVISION_KEY:
 			/* Firmware revision */
-			firmware_revision
-				= CONFIG_ROM_VALUE(ud->quadlets[i]);
+			firmware_revision = kv->value.immediate;
 			if (force_inquiry_hack)
 				SBP2_INFO("sbp2_firmware_revision = %x",
 				   (unsigned int) firmware_revision);
@@ -1668,7 +1683,7 @@
 	if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
 		struct unit_directory *parent_ud =
 			container_of(ud->device.parent, struct unit_directory, device);
-		sbp2_parse_unit_directory(scsi_group, parent_ud);
+		sbp2_parse_unit_directory(scsi_group, parent_ud, hi);
 	} else {
 		/* If our list is empty, add a base scsi_id (happens in a normal
 		 * case where there is no logical_unit_number entry */
@@ -1678,16 +1693,15 @@
 				SBP2_ERR("Out of memory adding scsi_id");
 				return;
 			}
-			memset(scsi_id, 0, sizeof(*scsi_id));
+
+			sbp2_prep_scsi_id(scsi_id, ud, hi);
 
 			scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
 			list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list);
 		}
 
 		/* Update the generic fields in all the LUN's */
-		list_for_each (lh, &scsi_group->scsi_id_list) {
-			scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
-
+		list_for_each_entry(scsi_id, &scsi_group->scsi_id_list, list) {
 			scsi_id->sbp2_management_agent_addr = management_agent_addr;
 			scsi_id->sbp2_command_set_spec_id = command_set_spec_id;
 			scsi_id->sbp2_command_set = command_set;
@@ -1727,7 +1741,7 @@
 	/* Payload size is the lesser of what our speed supports and what
 	 * our host supports.  */
 	scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code],
-					(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
+					(u8)(hi->host->csr.max_rec - 1));
 
 	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
 		 NODE_BUS_ARGS(hi->host, scsi_id->ne->nodeid),
@@ -2654,6 +2668,8 @@
 		}
 	}
 
+	scsi_unblock_requests(hi->scsi_host);
+
 	return;
 }
 
--- diff/drivers/ieee1394/sbp2.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/ieee1394/sbp2.h	2004-02-18 09:03:59.000000000 +0000
@@ -470,6 +470,7 @@
  */
 static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host);
 static void sbp2_remove_host(struct hpsb_host *host);
+static void sbp2_host_reset(struct hpsb_host *host);
 
 static int sbp2_probe(struct device *dev);
 static int sbp2_remove(struct device *dev);
@@ -512,7 +513,8 @@
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
 static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
 static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
-				      struct unit_directory *ud);
+				      struct unit_directory *ud,
+				      struct sbp2scsi_host_info *hi);
 static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id);
 static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id);
 
--- diff/drivers/ieee1394/video1394.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/ieee1394/video1394.c	2004-02-18 09:03:59.000000000 +0000
@@ -476,11 +476,9 @@
 static struct dma_iso_ctx *
 find_ctx(struct list_head *list, int type, int channel)
 {
-	struct list_head *lh;
+	struct dma_iso_ctx *ctx;
 
-	list_for_each(lh, list) {
-		struct dma_iso_ctx *ctx;
-		ctx = list_entry(lh, struct dma_iso_ctx, link);
+	list_for_each_entry(ctx, list, link) {
 		if (ctx->type == type && ctx->channel == channel)
 			return ctx;
 	}
--- diff/drivers/input/gameport/ns558.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/input/gameport/ns558.c	2004-02-18 09:03:59.000000000 +0000
@@ -77,7 +77,7 @@
  * No one should be using this address.
  */
 
-	if (check_region(io, 1))
+	if (!request_region(io, 1, "ns558-isa"))
 		return;
 
 /*
@@ -89,7 +89,8 @@
 	outb(~c & ~3, io);
 	if (~(u = v = inb(io)) & 3) {
 		outb(c, io);
-		return;
+		i = 0;
+		goto out;
 	}
 /*
  * After a trigger, there must be at least some bits changing.
@@ -99,7 +100,8 @@
 
 	if (u == v) {
 		outb(c, io);
-		return;
+		i = 0;
+		goto out;
 	}
 	wait_ms(3);
 /*
@@ -110,7 +112,8 @@
 	for (i = 0; i < 1000; i++)
 		if ((u ^ inb(io)) & 0xf) {
 			outb(c, io);
-			return;
+			i = 0;
+			goto out;
 		}
 /* 
  * And now find the number of mirrors of the port.
@@ -118,7 +121,9 @@
 
 	for (i = 1; i < 5; i++) {
 
-		if (check_region(io & (-1 << i), (1 << i)))	/* Don't disturb anyone */
+		release_region(io & (-1 << (i-1)), (1 << (i-1)));
+
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))	/* Don't disturb anyone */
 			break;
 
 		outb(0xff, io & (-1 << i));
@@ -126,18 +131,25 @@
 			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
 		wait_ms(3);
 
-		if (b > 300)					/* We allow 30% difference */
+		if (b > 300) {					/* We allow 30% difference */
+			release_region(io & (-1 << i), (1 << i));
 			break;
+		}
 	}
 
 	i--;
 
+	if (i != 4) {
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
+			return;
+	}
+
 	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
 		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		return;
+		goto out;
 	}
-       	memset(port, 0, sizeof(struct ns558));
-	
+	memset(port, 0, sizeof(struct ns558));
+
 	port->type = NS558_ISA;
 	port->size = (1 << i);
 	port->gameport.io = io;
@@ -148,8 +160,6 @@
 	sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
 	sprintf(port->name, "NS558 ISA");
 
-	request_region(io & (-1 << i), (1 << i), "ns558-isa");
-
 	gameport_register_port(&port->gameport);
 
 	printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
@@ -157,6 +167,9 @@
 	printk(" speed %d kHz\n", port->gameport.speed);
 
 	list_add(&port->node, &ns558_list);
+	return;
+out:
+	release_region(io & (-1 << i), (1 << i));
 }
 
 #ifdef CONFIG_PNP
--- diff/drivers/input/keyboard/Kconfig	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/input/keyboard/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -17,6 +17,7 @@
 	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	select SERIO_I8042 if PC
+	select SERIO_GSCPS2 if GSC
 	help
 	  Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
 	  you'll need this, unless you have a different type keyboard (USB, ADB
--- diff/drivers/input/keyboard/atkbd.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/keyboard/atkbd.c	2004-02-18 09:03:59.000000000 +0000
@@ -37,14 +37,13 @@
 
 static int atkbd_set = 2;
 module_param_named(set, atkbd_set, int, 0);
-MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)");
+MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
+
 #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
 static int atkbd_reset;
 #else
 static int atkbd_reset = 1;
 #endif
-static int atkbd_softrepeat;
-
 module_param_named(reset, atkbd_reset, bool, 0);
 MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
 
@@ -52,6 +51,14 @@
 module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
 MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
 
+static int atkbd_scroll;
+module_param_named(scroll, atkbd_scroll, bool, 0);
+MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
+
+static int atkbd_extra;
+module_param_named(extra, atkbd_extra, bool, 0);
+MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
+
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via an userland utility.
@@ -127,11 +134,11 @@
 #define ATKBD_CMD_EX_SETLEDS	0x20eb
 #define ATKBD_CMD_OK_GETID	0x02e8
 
+
 #define ATKBD_RET_ACK		0xfa
 #define ATKBD_RET_NAK		0xfe
 #define ATKBD_RET_BAT		0xaa
 #define ATKBD_RET_EMUL0		0xe0
-#define ATKBD_RET_EMULX		0x80
 #define ATKBD_RET_EMUL1		0xe1
 #define ATKBD_RET_RELEASE	0xf0
 #define ATKBD_RET_HANGUEL	0xf1
@@ -141,6 +148,22 @@
 #define ATKBD_KEY_UNKNOWN	  0
 #define ATKBD_KEY_NULL		255
 
+#define ATKBD_SCR_1		254
+#define ATKBD_SCR_2		253
+#define ATKBD_SCR_4		252
+#define ATKBD_SCR_8		251
+#define ATKBD_SCR_CLICK		250
+
+#define ATKBD_SPECIAL		250
+
+static unsigned char atkbd_scroll_keys[5][2] = {
+	{ ATKBD_SCR_1,     0x45 },
+	{ ATKBD_SCR_2,     0x29 },
+	{ ATKBD_SCR_4,     0x36 },
+	{ ATKBD_SCR_8,     0x27 },
+	{ ATKBD_SCR_CLICK, 0x60 },
+};
+
 /*
  * The atkbd control structure
  */
@@ -155,6 +178,7 @@
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
 	unsigned char set;
+	unsigned char extra;
 	unsigned char release;
 	int lastkey;
 	volatile signed char ack;
@@ -189,6 +213,7 @@
 {
 	struct atkbd *atkbd = serio->private;
 	unsigned int code = data;
+	int scroll = 0, click = -1;
 	int value;
 
 #ifdef ATKBD_DEBUG
@@ -284,6 +309,21 @@
 			else
 				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",						code & 0x80 ? "e0" : "", code & 0x7f);
 			break;
+		case ATKBD_SCR_1:
+			scroll = 1 - atkbd->release * 2;
+			break;
+		case ATKBD_SCR_2:
+			scroll = 2 - atkbd->release * 4;
+			break;
+		case ATKBD_SCR_4:
+			scroll = 4 - atkbd->release * 8;
+			break;
+		case ATKBD_SCR_8:
+			scroll = 8 - atkbd->release * 16;
+			break;
+		case ATKBD_SCR_CLICK:
+			click = !atkbd->release;
+			break;
 		default:
 			value = atkbd->release ? 0 :
 				(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
@@ -305,6 +345,13 @@
 			atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
 	}
 
+	if (scroll || click != -1) {
+		input_regs(&atkbd->dev, regs);
+		input_report_key(&atkbd->dev, BTN_MIDDLE, click);
+		input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
+		input_sync(&atkbd->dev);
+	}
+
 	atkbd->release = 0;
 out:
 	return IRQ_HANDLED;
@@ -420,7 +467,7 @@
 			         | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
 		        atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
 
-			if (atkbd->set == 4) {
+			if (atkbd->extra) {
 				param[0] = 0;
 				param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
 					 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
@@ -529,21 +576,22 @@
 		return 3;
 	}
 
-	if (atkbd_set != 2) 
-		if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
-			atkbd->id = param[0] << 8 | param[1];
+	if (atkbd_extra) {
+		param[0] = 0x71;
+		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) {
+			atkbd->extra = 1;
 			return 2;
 		}
-
-	if (atkbd_set == 4) {
-		param[0] = 0x71;
-		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE))
-			return 4;
 	}
 
 	if (atkbd_set != 3) 
 		return 2;
 
+	if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
+		atkbd->id = param[0] << 8 | param[1];
+		return 2;
+	}
+
 	param[0] = 3;
 	if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
 		return 2;
@@ -696,24 +744,32 @@
 		atkbd->id = 0xab00;
 	}
 
-	if (atkbd->set == 4) {
+	if (atkbd->extra) {
 		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
-		sprintf(atkbd->name, "AT Set 2 Extended keyboard");
+		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
 	} else
 		sprintf(atkbd->name, "AT %s Set %d keyboard",
 			atkbd->translated ? "Translated" : "Raw", atkbd->set);
 
 	sprintf(atkbd->phys, "%s/input0", serio->phys);
 
+	if (atkbd_scroll) {
+		for (i = 0; i < 5; i++)
+			atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+		atkbd->dev.evbit[0] |= BIT(EV_REL);
+		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
+		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
+	}
+
 	if (atkbd->translated) {
 		for (i = 0; i < 128; i++) {
 			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
 		}
-	} else if (atkbd->set == 2) {
-		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
-	} else {
+	} else if (atkbd->set == 3) {
 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+	} else {
+		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
 	}
 
 	atkbd->dev.name = atkbd->name;
@@ -724,7 +780,7 @@
 	atkbd->dev.id.version = atkbd->id;
 
 	for (i = 0; i < 512; i++)
-		if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
+		if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
 			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
 
 	input_register_device(&atkbd->dev);
@@ -741,46 +797,20 @@
 {
 	struct atkbd *atkbd = serio->private;
 	struct serio_dev *dev = serio->dev;
-	int i;
 
-        if (!dev) {
-                printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
-                return -1;
-        }
+	if (!dev) {
+		printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+		return -1;
+	}
 
 	if (atkbd->write) {
 		if (atkbd_probe(atkbd))
 			return -1;
-
-		atkbd->set = atkbd_set_3(atkbd);
+		if (atkbd->set != atkbd_set_3(atkbd))
+			return -1;
 		atkbd_enable(atkbd);
-	} else {
-		atkbd->set = 2;
-		atkbd->id = 0xab00;
-	}
-
-	/*
-	 * Here we probably should check if the keyboard has the same set that
-         * it had before and bail out if it's different. But this will most likely
-         * cause new keyboard device be created... and for the user it will look
-         * like keyboard is lost
-	 */
-
-	if (atkbd->translated) {
-		for (i = 0; i < 128; i++) {
-			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
-			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
-		}
-	} else if (atkbd->set == 2) {
-		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
-	} else {
-		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
 	}
 
-	for (i = 0; i < 512; i++)
-		if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
-			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
-
 	return 0;
 }
 
--- diff/drivers/input/keyboard/hpps2atkbd.h	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/keyboard/hpps2atkbd.h	2004-02-18 09:03:59.000000000 +0000
@@ -4,14 +4,9 @@
  * Copyright (c) 2004 Helge Deller <deller@gmx.de>
  * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
  * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
  *
- * based on linux-2.4's hp_mouse.c & hp_keyb.c
- * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
- *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
- *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
- *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
- *
- * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations
+ * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -19,87 +14,100 @@
  */
 
 
-#define KBD_UNKNOWN 0
-
-/* Raw SET 2 scancode table */
+/* undefine if you have a RDI PRECISIONBOOK */
+#define STANDARD_KEYBOARD
 
-#if 0
-	/* conflicting keys between a RDI Precisionbook keyboard and a normal HP keyboard */
-        keytable[0x07] = KEY_F1;        /* KEY_F12      */
-        keytable[0x11] = KEY_LEFTCTRL;  /* KEY_LEFTALT  */
-        keytable[0x14] = KEY_CAPSLOCK;  /* KEY_LEFTCTRL */
-        keytable[0x61] = KEY_LEFT;      /* KEY_102ND    */
+#if defined(STANDARD_KEYBOARD)
+# define CONFLICT(x,y) x
+#else
+# define CONFLICT(x,y) y
 #endif
 
+/* sadly RDI (Tadpole) decided to ship a different keyboard layout
+   than HP for their PS/2 laptop keyboard which leads to conflicting
+   keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook.
+                                HP:		RDI:            */
+#define C_07	CONFLICT(	KEY_F12,	KEY_F1		)
+#define C_11	CONFLICT(	KEY_LEFTALT,	KEY_LEFTCTRL	)
+#define C_14	CONFLICT(	KEY_LEFTCTRL,	KEY_CAPSLOCK	)
+#define C_58	CONFLICT(	KEY_CAPSLOCK,	KEY_RIGHTCTRL	)
+#define C_61	CONFLICT(	KEY_102ND,	KEY_LEFT	)
 
-static unsigned char atkbd_set2_keycode[512] = {
+/* Raw SET 2 scancode table */
 
-	/* 00 */  KBD_UNKNOWN,  KEY_F9,        KBD_UNKNOWN,   KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        KEY_F1,
-	/* 08 */  KEY_ESC,      KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KEY_F2,
-	/* 10 */  KBD_UNKNOWN,  KEY_LEFTCTRL,  KEY_LEFTSHIFT, KBD_UNKNOWN,   KEY_CAPSLOCK,  KEY_Q,        KEY_1,         KEY_F3,
-	/* 18 */  KBD_UNKNOWN,  KEY_LEFTALT,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KEY_F4,
-	/* 20 */  KBD_UNKNOWN,  KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KEY_F5,
-	/* 28 */  KBD_UNKNOWN,  KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KEY_F6,
-	/* 30 */  KBD_UNKNOWN,  KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KEY_F7,
-	/* 38 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KEY_F8,
-	/* 40 */  KBD_UNKNOWN,  KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KEY_F9,
-	/* 48 */  KBD_UNKNOWN,  KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KEY_F10,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_APOSTROPHE,KBD_UNKNOWN,   KEY_LEFTBRACE, KEY_EQUAL,    KEY_F11,       KEY_SYSRQ,
-	/* 58 */  KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12,       KEY_SCROLLLOCK,
-	/* 60 */  KEY_DOWN,     KEY_LEFT,      KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
-	/* 68 */  KBD_UNKNOWN,  KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
-	/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-	/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-
-	/* These are offset for escaped keycodes: */
-
-	/* 00 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_F7,        KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 08 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_LEFTMETA,  KEY_RIGHTMETA, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_RIGHTCTRL, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPSLASH,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPENTER,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_END,       KBD_UNKNOWN,   KEY_LEFT,      KEY_HOME,      KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KBD_UNKNOWN,   KEY_RIGHT,     KEY_UP,       KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 78 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_PAGEDOWN,  KBD_UNKNOWN,   KEY_SYSRQ,     KEY_PAGEUP,   KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN
+/* 00 */  KEY_RESERVED, KEY_F9,        KEY_RESERVED,  KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        C_07,
+/* 08 */  KEY_ESC,      KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KEY_F2,
+/* 10 */  KEY_RESERVED, C_11,          KEY_LEFTSHIFT, KEY_RESERVED,  C_14,          KEY_Q,        KEY_1,         KEY_F3,
+/* 18 */  KEY_RESERVED, KEY_LEFTALT,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KEY_F4,
+/* 20 */  KEY_RESERVED, KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KEY_F5,
+/* 28 */  KEY_RESERVED, KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KEY_F6,
+/* 30 */  KEY_RESERVED, KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KEY_F7,
+/* 38 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KEY_F8,
+/* 40 */  KEY_RESERVED, KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KEY_F9,
+/* 48 */  KEY_RESERVED, KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KEY_F10,
+/* 50 */  KEY_RESERVED, KEY_RESERVED,  KEY_APOSTROPHE,KEY_RESERVED,  KEY_LEFTBRACE, KEY_EQUAL,    KEY_F11,       KEY_SYSRQ,
+/* 58 */  C_58,         KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12,       KEY_SCROLLLOCK,
+/* 60 */  KEY_DOWN,     C_61,          KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
+/* 68 */  KEY_RESERVED, KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
+/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
+/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
+/* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_SYSRQ,     KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_CAPSLOCK, KEY_RESERVED,  KEY_LEFTMETA,
+/* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RIGHTMETA,
+/* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_COMPOSE,
+/* b0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c8 */  KEY_RESERVED, KEY_RESERVED,  KEY_KPSLASH,   KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d8 */  KEY_RESERVED, KEY_RESERVED,  KEY_KPENTER,   KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e8 */  KEY_RESERVED, KEY_END,       KEY_RESERVED,  KEY_LEFT,      KEY_HOME,      KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f0 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KEY_RESERVED,  KEY_RIGHT,     KEY_UP,       KEY_RESERVED,  KEY_PAUSE,
+/* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_PAGEDOWN,  KEY_RESERVED,  KEY_SYSRQ,     KEY_PAGEUP,   KEY_RESERVED,  KEY_RESERVED,
+
+/* These are offset for escaped keycodes: */
+
+/* 00 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_F7,        KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 08 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_LEFTMETA,  KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 10 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_RESERVED,  KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 18 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 20 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 28 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 30 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 38 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 40 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 48 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 50 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 58 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 60 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 68 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 70 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 78 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* b8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* c8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* d8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* e8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED
+
+#undef STANDARD_KEYBOARD
+#undef CONFLICT
+#undef C_07
+#undef C_11
+#undef C_14
+#undef C_58
+#undef C_61
 
-};
--- diff/drivers/input/keyboard/sunkbd.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/input/keyboard/sunkbd.c	2004-02-18 09:03:59.000000000 +0000
@@ -77,6 +77,7 @@
 	struct input_dev dev;
 	struct serio *serio;
 	struct work_struct tq;
+	wait_queue_head_t wait;
 	char name[64];
 	char phys[32];
 	char type;
@@ -96,11 +97,13 @@
 
 	if (sunkbd->reset <= -1) {		/* If cp[i] is 0xff, sunkbd->reset will stay -1. */
 		sunkbd->reset = data;		/* The keyboard sends 0xff 0xff 0xID on powerup */
+		wake_up_interruptible(&sunkbd->wait);
 		goto out;
 	}
 
 	if (sunkbd->layout == -1) {
 		sunkbd->layout = data;
+		wake_up_interruptible(&sunkbd->wait);
 		goto out;
 	}
 
@@ -176,22 +179,19 @@
 
 static int sunkbd_initialize(struct sunkbd *sunkbd)
 {
-	int t;
-
-	t = 1000;
 	sunkbd->reset = -2;
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
-	while (sunkbd->reset < 0 && --t) mdelay(1);
-	if (!t) return -1;
+	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
+	if (sunkbd->reset <0)
+		return -1;
 
 	sunkbd->type = sunkbd->reset;
 
 	if (sunkbd->type == 4) {	/* Type 4 keyboard */
-		t = 250;
 		sunkbd->layout = -2;
 		sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
-		while (sunkbd->layout < 0 && --t) mdelay(1);
-		if (!t) return -1;
+		wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
+		if (sunkbd->layout < 0) return -1;
 		if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
 	}
 
@@ -206,9 +206,8 @@
 static void sunkbd_reinit(void *data)
 {
 	struct sunkbd *sunkbd = data;
-	int t = 1000;
 
-	while (sunkbd->reset < 0 && --t) mdelay(1);
+	wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
 	sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
 	sunkbd->serio->write(sunkbd->serio, 
@@ -239,6 +238,7 @@
 	memset(sunkbd, 0, sizeof(struct sunkbd));
 
 	init_input_dev(&sunkbd->dev);
+	init_waitqueue_head(&sunkbd->wait);
 
 	sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
 	sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
@@ -275,7 +275,7 @@
 		set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
 	clear_bit(0, sunkbd->dev.keybit);
 
-	sprintf(sunkbd->name, "%s/input", serio->phys);
+	sprintf(sunkbd->phys, "%s/input0", serio->phys);
 
 	sunkbd->dev.name = sunkbd->name;
 	sunkbd->dev.phys = sunkbd->phys;
--- diff/drivers/input/misc/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/input/misc/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -54,12 +54,3 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called uinput.
 
-config INPUT_GSC
-	tristate "PA-RISC GSC PS/2 keyboard/mouse support"
-	depends on GSC && INPUT && INPUT_MISC
-	help
-	  Say Y here if you have a PS/2 keyboard and/or mouse attached
-	  to your PA-RISC box.	HP run the keyboard in AT mode rather than
-	  XT mode like everyone else, so we need our own driver.
-	  Furthermore, the GSC PS/2 controller shares IRQ between mouse and
-	  keyboard.
--- diff/drivers/input/misc/Makefile	2003-02-26 16:00:54.000000000 +0000
+++ source/drivers/input/misc/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -9,4 +9,3 @@
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_98SPKR)		+= 98spkr.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
-obj-$(CONFIG_INPUT_GSC)			+= gsc_ps2.o
--- diff/drivers/input/mouse/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -17,6 +17,7 @@
 	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	select SERIO_I8042 if PC
+	select SERIO_GSCPS2 if GSC
 	---help---
 	  Say Y here if you have a PS/2 mouse connected to your system. This
 	  includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
--- diff/drivers/input/mouse/psmouse-base.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/input/mouse/psmouse-base.c	2004-02-18 09:03:59.000000000 +0000
@@ -134,6 +134,13 @@
 		goto out;
 	}
 
+	if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
+		printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
+			flags & SERIO_TIMEOUT ? " timeout" : "",
+			flags & SERIO_PARITY ? " bad parity" : "");
+		goto out;
+	}
+
 	if (psmouse->acking) {
 		switch (data) {
 			case PSMOUSE_RET_ACK:
--- diff/drivers/input/serio/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/input/serio/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -20,6 +20,7 @@
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
 	select SERIO
+	depends on !PARISC
 	---help---
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,
@@ -48,6 +49,7 @@
 config SERIO_CT82C710
 	tristate "ct82c710 Aux port controller"
 	depends on SERIO
+	depends on !PARISC
 	---help---
 	  Say Y here if you have a Texas Instruments TravelMate notebook
 	  equipped with the ct82c710 chip and want to use a mouse connected
@@ -105,6 +107,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called 98kbd-io.
 
+config SERIO_GSCPS2
+	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
+	depends on GSC && SERIO
+	default y
+	help
+	  This driver provides support for the PS/2 ports on PA-RISC machines
+	  over which HP PS/2 keyboards and PS/2 mice may be connected.
+	  If you use these devices, you'll need to say Y here.
+
+	  It's safe to enable this driver, so if unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gscps2.
+
 config SERIO_PCIPS2
 	tristate "PCI PS/2 keyboard and PS/2 mouse controller"
 	depends on PCI && SERIO
--- diff/drivers/input/serio/Makefile	2003-06-30 10:07:29.000000000 +0100
+++ source/drivers/input/serio/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -14,4 +14,5 @@
 obj-$(CONFIG_SERIO_AMBAKMI)	+= ambakmi.o
 obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 obj-$(CONFIG_SERIO_98KBD)	+= 98kbd-io.o
+obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
--- diff/drivers/isdn/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -4,8 +4,8 @@
 
 menu "ISDN subsystem"
 
-config ISDN_BOOL
-	bool "ISDN support"
+config ISDN
+	tristate "ISDN support"
 	depends on NET
 	---help---
 	  ISDN ("Integrated Services Digital Networks", called RNIS in France)
@@ -22,9 +22,9 @@
 
 
 menu "Old ISDN4Linux"
-	depends on NET && ISDN_BOOL && BROKEN_ON_SMP
+	depends on NET && ISDN
 
-config ISDN
+config ISDN_I4L
 	tristate "Old ISDN4Linux (obsolete)"
 	---help---
 	  This driver allows you to use an ISDN-card for networking
@@ -41,18 +41,18 @@
 	  Therefore the old ISDN4Linux layer is becoming obsolete. It is 
 	  still usable, though, if you select this option.
 
-if ISDN
+if ISDN_I4L
 source "drivers/isdn/i4l/Kconfig"
 endif
 
 endmenu
 
 comment "CAPI subsystem"
-	depends on NET && ISDN_BOOL
+	depends on NET && ISDN
 
 config ISDN_CAPI
 	tristate "CAPI2.0 support"
-	depends on ISDN_BOOL
+	depends on ISDN
 	help
 	  This provides the CAPI (Common ISDN Application Programming
 	  Interface, a standard making it easy for programs to access ISDN
--- diff/drivers/isdn/Makefile	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -2,7 +2,7 @@
 
 # Object files in subdirectories
 
-obj-$(CONFIG_ISDN)			+= i4l/
+obj-$(CONFIG_ISDN_I4L)			+= i4l/
 obj-$(CONFIG_ISDN_CAPI)			+= capi/
 obj-$(CONFIG_ISDN_CAPI)			+= hardware/
 obj-$(CONFIG_ISDN_DIVERSION)		+= divert/
--- diff/drivers/isdn/act2000/Kconfig	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/act2000/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ACT2000
 	tristate "IBM Active 2000 support"
-	depends on ISDN && ISA
+	depends on ISDN_I4L && ISA
 	help
 	  Say Y here if you have an IBM Active 2000 ISDN card. In order to use
 	  this card, additional firmware is necessary, which has to be loaded
--- diff/drivers/isdn/act2000/act2000.h	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/isdn/act2000/act2000.h	2004-02-18 09:03:59.000000000 +0000
@@ -147,34 +147,36 @@
  * Per card driver data
  */
 typedef struct act2000_card {
-        unsigned short port;             /* Base-port-address                */
-        unsigned short irq;              /* Interrupt                        */
-        u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
-        u_char bus;                      /* Cardtype (ISA, MCA, PCMCIA)      */
-        struct act2000_card *next;	 /* Pointer to next device struct    */
-        int myid;                        /* Driver-Nr. assigned by linklevel */
-        unsigned long flags;             /* Statusflags                      */
-        unsigned long ilock;             /* Semaphores for IRQ-Routines      */
-	struct sk_buff_head rcvq;        /* Receive-Message queue            */
-	struct sk_buff_head sndq;        /* Send-Message queue               */
-	struct sk_buff_head ackq;        /* Data-Ack-Message queue           */
-	u_char *ack_msg;                 /* Ptr to User Data in User skb     */
-	__u16 need_b3ack;                /* Flag: Need ACK for current skb   */
-	struct sk_buff *sbuf;            /* skb which is currently sent      */
-	struct timer_list ptimer;        /* Poll timer                       */
-	struct work_struct snd_tq;         /* Task struct for xmit bh          */
-	struct work_struct rcv_tq;         /* Task struct for rcv bh           */
-	struct work_struct poll_tq;        /* Task struct for polled rcv bh    */
+	unsigned short port;		/* Base-port-address                */
+	unsigned short irq;		/* Interrupt                        */
+	u_char ptype;			/* Protocol type (1TR6 or Euro)     */
+	u_char bus;			/* Cardtype (ISA, MCA, PCMCIA)      */
+	struct act2000_card *next;	/* Pointer to next device struct    */
+	spinlock_t lock;		/* protect critical operations      */
+	int myid;			/* Driver-Nr. assigned by linklevel */
+	unsigned long flags;		/* Statusflags                      */
+	unsigned long ilock;		/* Semaphores for IRQ-Routines      */
+	struct sk_buff_head rcvq;	/* Receive-Message queue            */
+	struct sk_buff_head sndq;	/* Send-Message queue               */
+	struct sk_buff_head ackq;	/* Data-Ack-Message queue           */
+	u_char *ack_msg;		/* Ptr to User Data in User skb     */
+	__u16 need_b3ack;		/* Flag: Need ACK for current skb   */
+	struct sk_buff *sbuf;		/* skb which is currently sent      */
+	struct timer_list ptimer;	/* Poll timer                       */
+	struct work_struct snd_tq;	/* Task struct for xmit bh          */
+	struct work_struct rcv_tq;	/* Task struct for rcv bh           */
+	struct work_struct poll_tq;	/* Task struct for polled rcv bh    */
 	msn_entry *msn_list;
-	unsigned short msgnum;           /* Message number fur sending       */
-	act2000_chan bch[ACT2000_BCH];   /* B-Channel status/control         */
-	char   status_buf[256];          /* Buffer for status messages       */
+	unsigned short msgnum;		/* Message number for sending       */
+	spinlock_t mnlock;		/* lock for msgnum                  */
+	act2000_chan bch[ACT2000_BCH];	/* B-Channel status/control         */
+	char   status_buf[256];		/* Buffer for status messages       */
 	char   *status_buf_read;
 	char   *status_buf_write;
 	char   *status_buf_end;
-	irq_data idat;                   /* Data used for IRQ handler        */
-        isdn_if interface;               /* Interface to upper layer         */
-        char regname[35];                /* Name used for request_region     */
+	irq_data idat;			/* Data used for IRQ handler        */
+	isdn_if interface;		/* Interface to upper layer         */
+	char regname[35];		/* Name used for request_region     */
 } act2000_card;
 
 extern __inline__ void act2000_schedule_tx(act2000_card *card)
--- diff/drivers/isdn/act2000/act2000_isa.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/act2000/act2000_isa.c	2004-02-18 09:03:59.000000000 +0000
@@ -21,10 +21,8 @@
 static void
 act2000_isa_delay(long t)
 {
-        sti();
         set_current_state(TASK_INTERRUPTIBLE);
         schedule_timeout(t);
-        sti();
 }
 
 /*
@@ -64,8 +62,10 @@
 {
         int ret = 0;
 
-        if (!check_region(portbase, ISA_REGION))
+	if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
                 ret = act2000_isa_reset(portbase);
+		release_region(portbase, ISA_REGION);
+	}
         return ret;
 }
 
@@ -177,14 +177,13 @@
                 release_region(card->port, ISA_REGION);
                 card->flags &= ~ACT2000_FLAGS_PVALID;
         }
-        if (!check_region(portbase, ISA_REGION)) {
-                if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
-			return -EIO;
+	if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
+		return -EBUSY;
+	else {
                 card->port = portbase;
                 card->flags |= ACT2000_FLAGS_PVALID;
                 return 0;
         }
-        return -EBUSY;
 }
 
 /*
@@ -195,8 +194,7 @@
 {
         unsigned long flags;
 
-        save_flags(flags);
-        cli();
+        spin_lock_irqsave(&card->lock, flags);
         if (card->flags & ACT2000_FLAGS_IVALID) {
                 free_irq(card->irq, NULL);
                 irq2card_map[card->irq] = NULL;
@@ -205,7 +203,7 @@
         if (card->flags & ACT2000_FLAGS_PVALID)
                 release_region(card->port, ISA_REGION);
         card->flags &= ~ACT2000_FLAGS_PVALID;
-        restore_flags(flags);
+        spin_unlock_irqrestore(&card->lock, flags);
 }
 
 static int
@@ -316,8 +314,7 @@
         if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
 		return;
 	while (1) {
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&card->lock, flags);
 		if (!(card->sbuf)) {
 			if ((card->sbuf = skb_dequeue(&card->sndq))) {
 				card->ack_msg = card->sbuf->data;
@@ -330,7 +327,7 @@
 				}
 			}
 		}
-		restore_flags(flags);
+		spin_unlock_irqrestore(&card->lock, flags);
 		if (!(card->sbuf)) {
 			/* No more data to send */
 			test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
--- diff/drivers/isdn/act2000/capi.c	2002-10-16 04:29:02.000000000 +0100
+++ source/drivers/isdn/act2000/capi.c	2004-02-18 09:03:59.000000000 +0000
@@ -591,10 +591,9 @@
 	struct actcapi_msg *m;
 	int ret = 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	skb = skb_peek(&card->ackq);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
         if (!skb) {
 		printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
 		return 0;
@@ -614,10 +613,9 @@
 				chan->queued = 0;
                         return ret;
                 }
-		save_flags(flags);
-		cli();
+                spin_lock_irqsave(&card->lock, flags);
                 tmp = skb_peek((struct sk_buff_head *)tmp);
-		restore_flags(flags);
+                spin_unlock_irqrestore(&card->lock, flags);
                 if ((tmp == skb) || (tmp == NULL)) {
 			/* reached end of queue */
 			printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
--- diff/drivers/isdn/act2000/capi.h	2002-10-16 04:29:05.000000000 +0100
+++ source/drivers/isdn/act2000/capi.h	2004-02-18 09:03:59.000000000 +0000
@@ -336,12 +336,11 @@
 	unsigned long flags;
 	unsigned short n;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->mnlock, flags);
 	n = card->msgnum;
 	card->msgnum++;
 	card->msgnum &= 0x7fff;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->mnlock, flags);
 	return n;
 }
 #define DEBUG_MSG
--- diff/drivers/isdn/act2000/module.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/act2000/module.c	2004-02-18 09:03:59.000000000 +0000
@@ -62,19 +62,18 @@
 static void
 act2000_clear_msn(act2000_card *card)
 {
-        struct msn_entry *p = card->msn_list;
-        struct msn_entry *q;
+	struct msn_entry *p = card->msn_list;
+	struct msn_entry *q;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-        card->msn_list = NULL;
-	restore_flags(flags);
-        while (p) {
-                q  = p->next;
-                kfree(p);
-                p = q;
-        }
+	spin_lock_irqsave(&card->lock, flags);
+	card->msn_list = NULL;
+	spin_unlock_irqrestore(&card->lock, flags);
+	while (p) {
+		q  = p->next;
+		kfree(p);
+		p = q;
+	}
 }
 
 /*
@@ -143,13 +142,12 @@
 		/* Delete a single MSN */
 		while (p) {
 			if (p->eaz == eazmsn[0]) {
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&card->lock, flags);
 				if (q)
 					q->next = p->next;
 				else
 					card->msn_list = p->next;
-				restore_flags(flags);
+				spin_unlock_irqrestore(&card->lock, flags);
 				kfree(p);
 				printk(KERN_DEBUG
 				       "Mapping for EAZ %c deleted\n",
@@ -165,10 +163,9 @@
 	while (p) {
 		/* Found in list, replace MSN */
 		if (p->eaz == eazmsn[0]) {
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&card->lock, flags);
 			strcpy(p->msn, &eazmsn[1]);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&card->lock, flags);
 			printk(KERN_DEBUG
 			       "Mapping for EAZ %c changed to %s\n",
 			       eazmsn[0],
@@ -184,10 +181,9 @@
 	p->eaz = eazmsn[0];
 	strcpy(p->msn, &eazmsn[1]);
 	p->next = card->msn_list;
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	card->msn_list = p;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 	printk(KERN_DEBUG
 	       "Mapping %c -> %s added\n",
 	       eazmsn[0],
@@ -232,10 +228,9 @@
 	unsigned long flags;
 
 	act2000_receive(card);
-        save_flags(flags);
-        cli();
-        mod_timer(&card->ptimer, jiffies+3);
-        restore_flags(flags);
+	spin_lock_irqsave(&card->lock, flags);
+	mod_timer(&card->ptimer, jiffies+3);
+	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 static int
@@ -311,10 +306,9 @@
 				return -ENODEV;
 			if (!(chan = find_channel(card, c->arg & 0x0f)))
 				break;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&card->lock, flags);
 			if (chan->fsm_state != ACT2000_STATE_NULL) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&card->lock, flags);
 				printk(KERN_WARNING "Dial on channel with state %d\n",
 					chan->fsm_state);
 				return -EBUSY;
@@ -325,7 +319,7 @@
 				tmp[0] = c->parm.setup.eazmsn[0];
 			chan->fsm_state = ACT2000_STATE_OCALL;
 			chan->callref = 0xffff;
-			restore_flags(flags);
+			spin_unlock_irqrestore(&card->lock, flags);
 			ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
 						  tmp[0], c->parm.setup.si1,
 						  c->parm.setup.si2);
@@ -580,6 +574,8 @@
                 return;
         }
         memset((char *) card, 0, sizeof(act2000_card));
+        spin_lock_init(&card->lock);
+        spin_lock_init(&card->mnlock);
 	skb_queue_head_init(&card->sndq);
 	skb_queue_head_init(&card->rcvq);
 	skb_queue_head_init(&card->ackq);
--- diff/drivers/isdn/capi/Kconfig	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/capi/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -44,7 +44,7 @@
 
 config ISDN_CAPI_CAPIDRV
 	tristate "CAPI2.0 capidrv interface support"
-	depends on ISDN_CAPI && ISDN
+	depends on ISDN_CAPI && ISDN_I4L
 	help
 	  This option provides the glue code to hook up CAPI driven cards to
 	  the legacy isdn4linux link layer.  If you have a card which is
--- diff/drivers/isdn/capi/capi.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/capi/capi.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.1.4.1.2.2 2001/12/21 15:00:17 kai Exp $
+/* $Id: capi.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
@@ -44,7 +44,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.1.4.1.2.2 $";
+static char *revision = "$Revision: 1.1.2.3 $";
 
 MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
 MODULE_AUTHOR("Carsten Paeth");
@@ -203,7 +203,7 @@
 	struct list_head *l;
 	unsigned int minor = 0;
 	unsigned long flags;
-  
+
 	mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
   	if (!mp) {
   		printk(KERN_ERR "capi: can't alloc capiminor\n");
@@ -220,19 +220,24 @@
 	skb_queue_head_init(&mp->outqueue);
 
 	write_lock_irqsave(&capiminor_list_lock, flags);
-	list_for_each(l, &capiminor_list) {
-		p = list_entry(l, struct capiminor, list);
-		if (p->minor > minor) {
-			mp->minor = minor;
-			list_add_tail(&mp->list, &p->list);
-			break;
+	if (list_empty(&capiminor_list)) {
+		list_add(&mp->list, &capiminor_list);
+		write_unlock_irqrestore(&capiminor_list_lock, flags);
+	} else {
+		list_for_each(l, &capiminor_list) {
+			p = list_entry(l, struct capiminor, list);
+			if (p->minor > minor) {
+				mp->minor = minor;
+				list_add_tail(&mp->list, &p->list);
+				break;
+			}
+			minor++;
+		}
+		write_unlock_irqrestore(&capiminor_list_lock, flags);
+		if (l == &capiminor_list) {
+			kfree(mp);
+			return NULL;
 		}
-		minor++;
-	}
-	write_unlock_irqrestore(&capiminor_list_lock, flags);
-	if (l == &capiminor_list) {
-		kfree(mp);
-		return NULL;
 	}
 	return mp;
 }
@@ -297,7 +302,7 @@
 		printk(KERN_DEBUG "set mp->nccip\n");
 #endif
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
-		capifs_new_ncci(0, mp->minor, MKDEV(capi_ttymajor, mp->minor));
+		capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor));
 #endif
 	}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -322,8 +327,7 @@
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 			if ((mp = np->minorp) != 0) {
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
-				capifs_free_ncci('r', mp->minor);
-				capifs_free_ncci(0, mp->minor);
+				capifs_free_ncci(mp->minor);
 #endif
 				if (mp->tty) {
 					mp->nccip = 0;
--- diff/drivers/isdn/capi/capidrv.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/capi/capidrv.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: capidrv.c,v 1.39.6.7 2001/09/23 22:24:33 kai Exp $
+/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
@@ -34,7 +34,7 @@
 #include <linux/isdn/capicmd.h>
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.39.6.7 $";
+static char *revision = "$Revision: 1.1.2.2 $";
 static int debugmode = 0;
 
 MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
@@ -1263,6 +1263,10 @@
 		goto ignored;
 
 	case CAPI_DATA_B3_CONF:	/* ncci */
+		if (cmsg->Info) {
+			printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
+				cmsg->Info, capi_info2str(cmsg->Info));
+		}
 		if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
 			goto notfound;
 
@@ -1368,7 +1372,7 @@
 static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
 {
 	capi_message2cmsg(&s_cmsg, skb->data);
-	if (debugmode > 2)
+	if (debugmode > 3)
 		printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
 		       ap->applid, capi_cmsg2str(&s_cmsg));
 	
@@ -1825,7 +1829,7 @@
 		       id);
 		return 0;
 	}
-	if (debugmode > 1)
+	if (debugmode > 4)
 		printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
 					card->contrnr, len, skb, doack);
 	bchan = &card->bchans[channel % card->nbchan];
@@ -1866,6 +1870,9 @@
 			nccip->datahandle++;
 			return len;
 		}
+		if (debugmode > 3)
+			printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
+				card->contrnr, errcode, capi_info2str(errcode));
 	        (void)capidrv_del_ack(nccip, datahandle);
 	        dev_kfree_skb(nskb);
 		return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
@@ -1876,6 +1883,9 @@
 			nccip->datahandle++;
 			return len;
 		}
+		if (debugmode > 3)
+			printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
+				card->contrnr, errcode, capi_info2str(errcode));
 		skb_pull(skb, msglen);
 	        (void)capidrv_del_ack(nccip, datahandle);
 		return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
--- diff/drivers/isdn/capi/capifs.c	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/isdn/capi/capifs.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: capifs.c,v 1.14.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
  * 
  * Copyright 2000 by Carsten Paeth <calle@calle.de>
  *
@@ -20,99 +20,75 @@
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
-static char *revision = "$Revision: 1.14.6.8 $";
+/* ------------------------------------------------------------------ */
+
+static char *revision = "$Revision: 1.1.2.3 $";
+
+/* ------------------------------------------------------------------ */
 
-struct options {
+#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
+
+static struct vfsmount *capifs_mnt;
+static struct dentry *capifs_root;
+
+static struct {
 	int setuid;
 	int setgid;
 	uid_t   uid;
 	gid_t   gid;
 	umode_t mode;
-};
-static struct options options = {.mode = 0600};
-
-#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
+} config = {.mode = 0600};
 
 /* ------------------------------------------------------------------ */
 
-
-static int capifs_parse_options(char *s, struct options *p)
+static int capifs_remount(struct super_block *s, int *flags, char *data)
 {
 	int setuid = 0;
 	int setgid = 0;
 	uid_t uid = 0;
 	gid_t gid = 0;
 	umode_t mode = 0600;
-	char *this_char, *value;
+	char *this_char;
 
-	if (!s)
-		return 0;
-
-	while ((this_char = strsep(&s, ",")) != NULL) {
+	this_char = NULL;
+	while ((this_char = strsep(&data, ",")) != NULL) {
+		int n;
+		char dummy;
 		if (!*this_char)
 			continue;
-		if ((value = strchr(this_char,'=')) != NULL)
-			*value++ = 0;
-		if (!strcmp(this_char,"uid")) {
-			if (!value || !*value)
-				return 1;
-			uid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 1;
+		if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
 			setuid = 1;
-		}
-		else if (!strcmp(this_char,"gid")) {
-			if (!value || !*value)
-				return 1;
-			gid = simple_strtoul(value,&value,0);
-			if (*value)
-				return 1;
+			uid = n;
+		} else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
 			setgid = 1;
+			gid = n;
+		} else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
+			mode = n & ~S_IFMT;
+		else {
+			printk("capifs: called with bogus options\n");
+			return -EINVAL;
 		}
-		else if (!strcmp(this_char,"mode")) {
-			if (!value || !*value)
-				return 1;
-			mode = simple_strtoul(value,&value,8);
-			if (*value)
-				return 1;
-		}
-	}
-	p->setuid   = setuid;
-	p->setgid   = setgid;
-	p->uid      = uid;
-	p->gid      = gid;
-	p->mode     = mode & ~S_IFMT;
-
-	return 0;
-}
-
-static int capifs_remount(struct super_block *s, int *flags, char *data)
-{
-	struct options new;
-	if (capifs_parse_options(data, &new)) {
-		printk("capifs: called with bogus options\n");
-		return -EINVAL;
 	}
-	options = new;
+	config.setuid  = setuid;
+	config.setgid  = setgid;
+	config.uid     = uid;
+	config.gid     = gid;
+	config.mode    = mode;
 	return 0;
 }
 
-
 static struct super_operations capifs_sops =
 {
 	.statfs		= simple_statfs,
 	.remount_fs	= capifs_remount,
 };
 
-static int capifs_fill_super(struct super_block *s, void *data, int silent)
+
+static int
+capifs_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct inode * inode;
 
-	if (capifs_parse_options(data, &options)) {
-		printk("capifs: called with bogus options\n");
-		return -EINVAL;
-	}
-
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = CAPIFS_SUPER_MAGIC;
@@ -120,24 +96,25 @@
 
 	inode = new_inode(s);
 	if (!inode)
-		return -ENOMEM;
+		goto fail;
+	inode->i_ino = 1;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = 0;
 	inode->i_blksize = 1024;
 	inode->i_uid = inode->i_gid = 0;
-	inode->i_ino = 1;
 	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
 	inode->i_nlink = 2;
-	s->s_root = d_alloc_root(inode);
 
-	if (!s->s_root) {
-		printk("capifs: get root dentry failed\n");
-		iput(inode);
-		return -ENOMEM;
-	}
-	return 0;
+	capifs_root = s->s_root = d_alloc_root(inode);
+	if (s->s_root)
+		return 0;
+	
+	printk("capifs: get root dentry failed\n");
+	iput(inode);
+fail:
+	return -ENOMEM;
 }
 
 static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
@@ -153,78 +130,48 @@
 	.kill_sb	= kill_anon_super,
 };
 
-static struct vfsmount *capifs_mnt;
-static int entry_count;
-
-static int grab_instance(void)
-{
-	return simple_pin_fs("capifs", &capifs_mnt, &entry_count);
-}
-
-static void drop_instance(void)
-{
-	return simple_release_fs(&capifs_mnt, &entry_count);
-}
-
-static struct dentry *get_node(int type, int num)
+static struct dentry *get_node(int num)
 {
 	char s[10];
-	int len;
-	struct dentry *root = capifs_mnt->mnt_root;
-	if (type)
-		len = sprintf(s, "%d", num);
-	else
-		len = sprintf(s, "%c%d", type, num);
+	struct dentry *root = capifs_root;
 	down(&root->d_inode->i_sem);
-	return lookup_one_len(s, root, len);
+	return lookup_one_len(s, root, sprintf(s, "%d", num));
 }
 
-void capifs_new_ncci(char type, unsigned int num, dev_t device)
+void capifs_new_ncci(unsigned int number, dev_t device)
 {
-	struct super_block *sb;
 	struct dentry *dentry;
-	struct inode *inode;
-
-	if (grab_instance() < 0)
+	struct inode *inode = new_inode(capifs_mnt->mnt_sb);
+	if (!inode)
 		return;
-	sb = capifs_mnt->mnt_sb;
-	inode = new_inode(sb);
-	if (inode) {
-		inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-		inode->i_blocks = 0;
-		inode->i_blksize = 1024;
-		inode->i_uid = options.setuid ? options.uid : current->fsuid;
-		inode->i_gid = options.setgid ? options.gid : current->fsgid;
-		inode->i_nlink = 1;
-		init_special_inode(inode, S_IFCHR | options.mode, device);
-		dentry = get_node(type, num);
-		if (!IS_ERR(dentry) && !dentry->d_inode) {
-			grab_instance();
-			d_instantiate(dentry, inode);
-		} else
-			iput(inode);
-		up(&sb->s_root->d_inode->i_sem);
-	}
-	drop_instance();
+	inode->i_ino = number+2;
+	inode->i_blksize = 1024;
+	inode->i_uid = config.setuid ? config.uid : current->fsuid;
+	inode->i_gid = config.setgid ? config.gid : current->fsgid;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	init_special_inode(inode, S_IFCHR|config.mode, device);
+	//inode->i_op = &capifs_file_inode_operations;
+
+	dentry = get_node(number);
+	if (!IS_ERR(dentry) && !dentry->d_inode)
+		d_instantiate(dentry, inode);
+	up(&capifs_root->d_inode->i_sem);
 }
 
-void capifs_free_ncci(char type, unsigned int num)
+void capifs_free_ncci(unsigned int number)
 {
-	if (grab_instance() == 0) {
-		struct dentry *dentry = get_node(type, num);
-		if (!IS_ERR(dentry)) {
-			struct inode *inode = dentry->d_inode;
-			if (inode) {
-				inode->i_nlink--;
-				d_delete(dentry);
-				dput(dentry);
-				drop_instance();
-			}
+	struct dentry *dentry = get_node(number);
+
+	if (!IS_ERR(dentry)) {
+		struct inode *inode = dentry->d_inode;
+		if (inode) {
+			inode->i_nlink--;
+			d_delete(dentry);
 			dput(dentry);
 		}
-		up(&capifs_mnt->mnt_root->d_inode->i_sem);
-		drop_instance();
+		dput(dentry);
 	}
+	up(&capifs_root->d_inode->i_sem);
 }
 
 static int __init capifs_init(void)
@@ -241,14 +188,20 @@
 		strcpy(rev, "1.0");
 
 	err = register_filesystem(&capifs_fs_type);
+	if (!err) {
+		capifs_mnt = kern_mount(&capifs_fs_type);
+		if (IS_ERR(capifs_mnt))
+			err = PTR_ERR(capifs_mnt);
+	}
 	if (!err)
 		printk(KERN_NOTICE "capifs: Rev %s\n", rev);
-	return 0;
+	return err;
 }
 
 static void __exit capifs_exit(void)
 {
 	unregister_filesystem(&capifs_fs_type);
+	mntput(capifs_mnt);
 }
 
 EXPORT_SYMBOL(capifs_new_ncci);
--- diff/drivers/isdn/capi/capifs.h	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/capi/capifs.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: capifs.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $
+/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $
  * 
  * Copyright 2000 by Carsten Paeth <calle@calle.de>
  *
@@ -7,5 +7,5 @@
  *
  */
 
-void capifs_new_ncci(char type, unsigned int num, dev_t device);
-void capifs_free_ncci(char type, unsigned int num);
+void capifs_new_ncci(unsigned int num, dev_t device);
+void capifs_free_ncci(unsigned int num);
--- diff/drivers/isdn/capi/kcapi.c	2003-10-27 09:20:43.000000000 +0000
+++ source/drivers/isdn/capi/kcapi.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: kcapi.c,v 1.21.6.8 2001/09/23 22:24:33 kai Exp $
+/* $Id: kcapi.c,v 1.1.2.4 2004/02/10 01:07:11 keil Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
@@ -31,7 +31,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.8 $";
+static char *revision = "$Revision: 1.1.2.4 $";
 
 /* ------------------------------------------------------------- */
 
@@ -61,7 +61,7 @@
 #define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
 
 LIST_HEAD(capi_drivers);
-spinlock_t capi_drivers_lock = SPIN_LOCK_UNLOCKED;
+rwlock_t capi_drivers_list_lock = RW_LOCK_UNLOCKED;
 
 struct capi20_appl *capi_applications[CAPI_MAXAPPL];
 struct capi_ctr *capi_cards[CAPI_MAXCONTR];
@@ -309,12 +309,10 @@
 			continue;
 		}
 
-		if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
-		    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+		if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
 			ap->nrecvdatapkt++;
-		} else {
+		else
 			ap->nrecvctlpkt++;
-		}
 		ap->recv_message(ap, skb);
 	}
 }
@@ -498,6 +496,28 @@
 
 EXPORT_SYMBOL(detach_capi_ctr);
 
+void register_capi_driver(struct capi_driver *driver)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&capi_drivers_list_lock, flags);
+	list_add_tail(&driver->list, &capi_drivers);
+	write_unlock_irqrestore(&capi_drivers_list_lock, flags);
+}
+
+EXPORT_SYMBOL(register_capi_driver);
+
+void unregister_capi_driver(struct capi_driver *driver)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&capi_drivers_list_lock, flags);
+	list_del(&driver->list);
+	write_unlock_irqrestore(&capi_drivers_list_lock, flags);
+}
+
+EXPORT_SYMBOL(unregister_capi_driver);
+
 /* ------------------------------------------------------------- */
 /* -------- CAPI2.0 Interface ---------------------------------- */
 /* ------------------------------------------------------------- */
@@ -704,12 +724,68 @@
 static int old_capi_manufacturer(unsigned int cmd, void *data)
 {
 	avmb1_loadandconfigdef ldef;
+	avmb1_extcarddef cdef;
 	avmb1_resetdef rdef;
+	capicardparams cparams;
 	struct capi_ctr *card;
+	struct capi_driver *driver = 0;
 	capiloaddata ldata;
+	struct list_head *l;
+	unsigned long flags;
 	int retval;
 
 	switch (cmd) {
+	case AVMB1_ADDCARD:
+	case AVMB1_ADDCARD_WITH_TYPE:
+		if (cmd == AVMB1_ADDCARD) {
+		   if ((retval = copy_from_user((void *) &cdef, data,
+					    sizeof(avmb1_carddef))))
+			   return retval;
+		   cdef.cardtype = AVM_CARDTYPE_B1;
+		} else {
+		   if ((retval = copy_from_user((void *) &cdef, data,
+					    sizeof(avmb1_extcarddef))))
+			   return retval;
+		}
+		cparams.port = cdef.port;
+		cparams.irq = cdef.irq;
+		cparams.cardnr = cdef.cardnr;
+
+		read_lock_irqsave(&capi_drivers_list_lock, flags);
+                switch (cdef.cardtype) {
+			case AVM_CARDTYPE_B1:
+				list_for_each(l, &capi_drivers) {
+					driver = list_entry(l, struct capi_driver, list);
+					if (strcmp(driver->name, "b1isa") == 0)
+						break;
+				}
+				break;
+			case AVM_CARDTYPE_T1:
+				list_for_each(l, &capi_drivers) {
+					driver = list_entry(l, struct capi_driver, list);
+					if (strcmp(driver->name, "t1isa") == 0)
+						break;
+				}
+				break;
+			default:
+				driver = 0;
+				break;
+		}
+		if (!driver) {
+			read_unlock_irqrestore(&capi_drivers_list_lock, flags);
+			printk(KERN_ERR "kcapi: driver not loaded.\n");
+			return -EIO;
+		}
+		if (!driver->add_card) {
+			read_unlock_irqrestore(&capi_drivers_list_lock, flags);
+			printk(KERN_ERR "kcapi: driver has no add card function.\n");
+			return -EIO;
+		}
+
+		retval = driver->add_card(driver, &cparams);
+		read_unlock_irqrestore(&capi_drivers_list_lock, flags);
+		return retval;
+
 	case AVMB1_LOAD:
 	case AVMB1_LOAD_AND_CONFIG:
 
@@ -832,6 +908,43 @@
 			card->cnr, card->traceflag);
 		return 0;
 	}
+	case KCAPI_CMD_ADDCARD:
+	{
+		struct list_head *l;
+		struct capi_driver *driver = 0;
+		capicardparams cparams;
+		kcapi_carddef cdef;
+		int retval;
+
+		if ((retval = copy_from_user((void *) &cdef, data,
+							sizeof(cdef))))
+			return retval;
+
+		cparams.port = cdef.port;
+		cparams.irq = cdef.irq;
+		cparams.membase = cdef.membase;
+		cparams.cardnr = cdef.cardnr;
+		cparams.cardtype = 0;
+		cdef.driver[sizeof(cdef.driver)-1] = 0;
+
+		list_for_each(l, &capi_drivers) {
+			driver = list_entry(l, struct capi_driver, list);
+			if (strcmp(driver->name, cdef.driver) == 0)
+				break;
+		}
+		if (driver == 0) {
+			printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
+					cdef.driver);
+			return -ESRCH;
+		}
+
+		if (!driver->add_card) {
+			printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
+			return -EIO;
+		}
+
+		return driver->add_card(driver, &cparams);
+	}
 
 	default:
 		printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
--- diff/drivers/isdn/capi/kcapi.h	2002-10-16 04:27:48.000000000 +0100
+++ source/drivers/isdn/capi/kcapi.h	2004-02-18 09:03:59.000000000 +0000
@@ -15,10 +15,13 @@
 #include <linux/list.h>
 #include <linux/isdn/capilli.h>
 
+#ifdef KCAPI_DEBUG
 #define DBG(format, arg...) do { \
 printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
 } while (0)
-
+#else
+#define DBG(format, arg...) /* */
+#endif
 
 enum {
 	CARD_DETECTED = 1,
@@ -27,7 +30,7 @@
 };
 
 extern struct list_head capi_drivers;
-extern spinlock_t capi_drivers_lock;
+extern rwlock_t capi_drivers_list_lock;
 
 extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
 extern struct capi_ctr *capi_cards[CAPI_MAXCONTR];
--- diff/drivers/isdn/capi/kcapi_proc.c	2002-10-16 04:28:22.000000000 +0100
+++ source/drivers/isdn/capi/kcapi_proc.c	2004-02-18 09:03:59.000000000 +0000
@@ -243,16 +243,84 @@
 
 // ---------------------------------------------------------------------------
 
+
+static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos)
+{
+	struct capi_driver *drv = 0;
+	struct list_head *l;
+	loff_t i;
+
+	i = 0;
+	list_for_each(l, &capi_drivers) {
+		drv = list_entry(l, struct capi_driver, list);
+		if (i++ == pos)
+			return drv;
+	}
+	return 0;
+}
+
+static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
+{
+	struct capi_driver *drv;
+	read_lock(&capi_drivers_list_lock);
+	drv = capi_driver_get_idx(*pos);
+	return drv;
+}
+
+static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct capi_driver *drv = (struct capi_driver *)v;
+	++*pos;
+	if (drv->list.next == &capi_drivers) return 0;
+	return list_entry(drv->list.next, struct capi_driver, list);
+}
+
+static void capi_driver_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&capi_drivers_list_lock);
+}
+
+static int capi_driver_show(struct seq_file *seq, void *v)
+{
+	struct capi_driver *drv = (struct capi_driver *)v;
+	seq_printf(seq, "%-32s %s\n", drv->name, drv->revision);
+	return 0;
+}
+
+struct seq_operations seq_capi_driver_ops = {
+	.start	= capi_driver_start,
+	.next	= capi_driver_next,
+	.stop	= capi_driver_stop,
+	.show	= capi_driver_show,
+};
+
+static int
+seq_capi_driver_open(struct inode *inode, struct file *file)
+{
+	int err;
+	err = seq_open(file, &seq_capi_driver_ops);
+	return err;
+}
+
+static struct file_operations proc_driver_ops = {
+	.open		= seq_capi_driver_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+// ---------------------------------------------------------------------------
+
 void __init 
 kcapi_proc_init(void)
 {
 	proc_mkdir("capi",             NULL);
 	proc_mkdir("capi/controllers", NULL);
-	proc_mkdir("capi/drivers",     NULL);
 	create_seq_entry("capi/controller",   0, &proc_controller_ops);
 	create_seq_entry("capi/contrstats",   0, &proc_contrstats_ops);
 	create_seq_entry("capi/applications", 0, &proc_applications_ops);
 	create_seq_entry("capi/applstats",    0, &proc_applstats_ops);
+	create_seq_entry("capi/driver",       0, &proc_driver_ops);
 }
 
 void __exit
@@ -263,7 +331,6 @@
 	remove_proc_entry("capi/contrstats",   NULL);
 	remove_proc_entry("capi/applications", NULL);
 	remove_proc_entry("capi/applstats",    NULL);
-	remove_proc_entry("capi/drivers",      NULL);
 	remove_proc_entry("capi/controllers",  NULL);
 	remove_proc_entry("capi",              NULL);
 }
--- diff/drivers/isdn/hardware/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/hardware/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -2,32 +2,9 @@
 # ISDN hardware drivers
 #
 comment "CAPI hardware drivers"
-	depends on NET && ISDN_BOOL && ISDN_CAPI
+	depends on NET && ISDN && ISDN_CAPI
 
 source "drivers/isdn/hardware/avm/Kconfig"
 
 source "drivers/isdn/hardware/eicon/Kconfig"
 
-comment "ISDN4Linux hardware drivers"
-	depends on NET && ISDN_BOOL && ISDN
-
-source "drivers/isdn/hisax/Kconfig"
-
-
-menu "Active cards"
-	depends on NET && ISDN_BOOL && ISDN!=n
-
-source "drivers/isdn/icn/Kconfig"
-
-source "drivers/isdn/pcbit/Kconfig"
-
-source "drivers/isdn/sc/Kconfig"
-
-source "drivers/isdn/act2000/Kconfig"
-
-source "drivers/isdn/tpam/Kconfig"
-
-source "drivers/isdn/hysdn/Kconfig"
-
-endmenu
-
--- diff/drivers/isdn/hardware/avm/Kconfig	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hardware/avm/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 
 menu "Active AVM cards"
-	depends on NET && ISDN_BOOL && ISDN_CAPI!=n
+	depends on NET && ISDN && ISDN_CAPI!=n
 
 config CAPI_AVM
 	bool "Support AVM cards"
--- diff/drivers/isdn/hardware/avm/b1.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hardware/avm/b1.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: b1.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
+/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Common module for AVM B1 cards.
  * 
@@ -28,7 +28,7 @@
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
 
-static char *revision = "$Revision: 1.1.4.1.2.1 $";
+static char *revision = "$Revision: 1.1.2.2 $";
 
 /* ------------------------------------------------------------- */
 
@@ -76,7 +76,7 @@
 		kfree(card);
 		return 0;
 	}
-	memset(cinfo, 0, sizeof(*cinfo));
+	memset(cinfo, 0, sizeof(*cinfo) * nr_controllers);
 
 	card->ctrlinfo = cinfo;
 	for (i = 0; i < nr_controllers; i++) {
@@ -308,14 +308,13 @@
 		return -EIO;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	b1_setinterrupt(port, card->irq, card->cardtype);
 	b1_put_byte(port, SEND_INIT);
 	b1_put_word(port, CAPI_MAXAPPL);
 	b1_put_word(port, AVM_NCCI_PER_CHANNEL*2);
 	b1_put_word(port, ctrl->cnr - 1);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return 0;
 }
@@ -348,15 +347,14 @@
 	else nconn = ctrl->profile.nbchannel * -want;
 	if (nconn == 0) nconn = ctrl->profile.nbchannel;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	b1_put_byte(port, SEND_REGISTER);
 	b1_put_word(port, appl);
 	b1_put_word(port, 1024 * (nconn+1));
 	b1_put_word(port, nconn);
 	b1_put_word(port, rp->datablkcnt);
 	b1_put_word(port, rp->datablklen);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
@@ -368,11 +366,10 @@
 
 	capilib_release_appl(&cinfo->ncci_head, appl);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	b1_put_byte(port, SEND_RELEASE);
 	b1_put_word(port, appl);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 }
 
 u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
@@ -396,20 +393,18 @@
 
 		dlen = CAPIMSG_DATALEN(skb->data);
 
-		save_flags(flags);
-		cli();
+	 	spin_lock_irqsave(&card->lock, flags);
 		b1_put_byte(port, SEND_DATA_B3_REQ);
 		b1_put_slice(port, skb->data, len);
 		b1_put_slice(port, skb->data + len, dlen);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&card->lock, flags);
 	} else {
 		retval = CAPI_NOERROR;
 
-		save_flags(flags);
-		cli();
+	 	spin_lock_irqsave(&card->lock, flags);
 		b1_put_byte(port, SEND_MESSAGE);
 		b1_put_slice(port, skb->data, len);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
  out:
 	dev_kfree_skb_any(skb);
@@ -505,9 +500,14 @@
 	unsigned DataB3Len;
 	unsigned NCCI;
 	unsigned WindowSize;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
 
-	if (!b1_rx_full(card->port))
-	   return IRQ_NONE;
+	if (!b1_rx_full(card->port)) {
+		spin_unlock_irqrestore(&card->lock, flags);
+		return IRQ_NONE;
+	}
 
 	b1cmd = b1_get_byte(card->port);
 
@@ -518,6 +518,7 @@
 		ApplId = (unsigned) b1_get_word(card->port);
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
 		DataB3Len = b1_get_slice(card->port, card->databuf);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		if (MsgLen < 30) { /* not CAPI 64Bit */
 			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
@@ -538,6 +539,7 @@
 
 		ApplId = (unsigned) b1_get_word(card->port);
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
+		spin_unlock_irqrestore(&card->lock, flags);
 		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
 			printk(KERN_ERR "%s: incoming packet dropped\n",
 					card->name);
@@ -557,6 +559,7 @@
 		ApplId = b1_get_word(card->port);
 		NCCI = b1_get_word(card->port);
 		WindowSize = b1_get_word(card->port);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
 
@@ -566,6 +569,7 @@
 
 		ApplId = b1_get_word(card->port);
 		NCCI = b1_get_word(card->port);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		if (NCCI != 0xffffffff)
 			capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
@@ -574,16 +578,19 @@
 
 	case RECEIVE_START:
 	   	/* b1_put_byte(card->port, SEND_POLLACK); */
+		spin_unlock_irqrestore(&card->lock, flags);
 		capi_ctr_resume_output(ctrl);
 		break;
 
 	case RECEIVE_STOP:
+		spin_unlock_irqrestore(&card->lock, flags);
 		capi_ctr_suspend_output(ctrl);
 		break;
 
 	case RECEIVE_INIT:
 
 		cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
+		spin_unlock_irqrestore(&card->lock, flags);
 		b1_parse_version(cinfo);
 		printk(KERN_INFO "%s: %s-card (%s) now active\n",
 		       card->name,
@@ -595,6 +602,7 @@
 	case RECEIVE_TASK_READY:
 		ApplId = (unsigned) b1_get_word(card->port);
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
+		spin_unlock_irqrestore(&card->lock, flags);
 		card->msgbuf[MsgLen] = 0;
 		while (    MsgLen > 0
 		       && (   card->msgbuf[MsgLen-1] == '\n'
@@ -608,6 +616,7 @@
 
 	case RECEIVE_DEBUGMSG:
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
+		spin_unlock_irqrestore(&card->lock, flags);
 		card->msgbuf[MsgLen] = 0;
 		while (    MsgLen > 0
 		       && (   card->msgbuf[MsgLen-1] == '\n'
@@ -619,9 +628,11 @@
 		break;
 
 	case 0xff:
+		spin_unlock_irqrestore(&card->lock, flags);
 		printk(KERN_ERR "%s: card removed ?\n", card->name);
 		return IRQ_NONE;
 	default:
+		spin_unlock_irqrestore(&card->lock, flags);
 		printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
 				card->name, b1cmd);
 		return IRQ_HANDLED;
--- diff/drivers/isdn/hardware/avm/b1dma.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/hardware/avm/b1dma.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: b1dma.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
+/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
@@ -28,11 +28,9 @@
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
 
-#if BITS_PER_LONG != 32
-#error FIXME: driver requires 32-bit platform
-#endif
+static char *revision = "$Revision: 1.1.2.3 $";
 
-static char *revision = "$Revision: 1.1.4.1.2.1 $";
+#undef CONFIG_B1DMA_DEBUG
 
 /* ------------------------------------------------------------- */
 
@@ -239,7 +237,7 @@
 
 /* ------------------------------------------------------------- */
 
-int b1dma_detect(avmcard *card)
+static int b1dma_detect(avmcard *card)
 {
 	b1dma_writel(card, 0, AMCC_MCSR);
 	mdelay(10);
@@ -578,11 +576,16 @@
 
 static void b1dma_handle_interrupt(avmcard *card)
 {
-	u32 status = b1dma_readl(card, AMCC_INTCSR);
+	u32 status;
 	u32 newcsr;
 
-	if ((status & ANY_S5933_INT) == 0) 
+	spin_lock(&card->lock);
+
+	status = b1dma_readl(card, AMCC_INTCSR);
+	if ((status & ANY_S5933_INT) == 0) {
+		spin_unlock(&card->lock);
 		return;
+	}
 
         newcsr = card->csr | (status & ALL_INT);
 	if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
@@ -593,20 +596,28 @@
 		struct avmcard_dmainfo *dma = card->dma;
 		u32 rxlen;
 	   	if (card->dma->recvlen == 0) {
-			dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
-			rxlen = (dma->recvlen + 3) & ~3;
-			b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
-			b1dma_writel(card, rxlen, AMCC_RXLEN);
+	        	rxlen = b1dma_readl(card, AMCC_RXLEN);
+			if (rxlen == 0) {
+				dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
+				rxlen = (dma->recvlen + 3) & ~3;
+				b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
+				b1dma_writel(card, rxlen, AMCC_RXLEN);
+#ifdef CONFIG_B1DMA_DEBUG
+			} else {
+				printk(KERN_ERR "%s: rx not complete (%d).\n",
+					card->name, rxlen);
+#endif
+			}
 		} else {
+			spin_unlock(&card->lock);
 			b1dma_handle_rx(card);
 	   		dma->recvlen = 0;
+			spin_lock(&card->lock);
 			b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
 			b1dma_writel(card, 4, AMCC_RXLEN);
 		}
 	}
 
-	spin_lock(&card->lock);
-
 	if ((status & TX_TC_INT) != 0) {
 		if (skb_queue_empty(&card->dma->send_queue))
 			card->csr &= ~EN_TX_TC_INT;
@@ -736,18 +747,19 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
+	unsigned long flags;
 
+	spin_lock_irqsave(&card->lock, flags);
  	b1dma_reset(card);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	memset(cinfo->version, 0, sizeof(cinfo->version));
 	capilib_release(&cinfo->ncci_head);
 	capi_ctr_reseted(ctrl);
 }
 
-
 /* ------------------------------------------------------------- */
 
-
 void b1dma_register_appl(struct capi_ctr *ctrl,
 				u16 appl,
 				capi_register_params *rp)
@@ -844,6 +856,7 @@
 	int len = 0;
 	char *s;
 	u32 txoff, txlen, rxoff, rxlen, csr;
+	unsigned long flags;
 
 	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
 	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
@@ -896,6 +909,9 @@
 	}
 	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
 
+
+	spin_lock_irqsave(&card->lock, flags);
+
 	txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
 	txlen = b1dma_readl(card, AMCC_TXLEN);
 
@@ -904,6 +920,8 @@
 
 	csr  = b1dma_readl(card, AMCC_INTCSR);
 
+	spin_unlock_irqrestore(&card->lock, flags);
+
         len += sprintf(page+len, "%-16s 0x%lx\n",
 				"csr (cached)", (unsigned long)card->csr);
         len += sprintf(page+len, "%-16s 0x%lx\n",
--- diff/drivers/isdn/hardware/avm/b1isa.c	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/isdn/hardware/avm/b1isa.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: b1isa.c,v 1.10.6.6 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
@@ -27,6 +27,10 @@
 
 /* ------------------------------------------------------------- */
 
+static char *revision = "$Revision: 1.1.2.3 $";
+
+/* ------------------------------------------------------------- */
+
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
@@ -56,7 +60,7 @@
 
 static char *b1isa_procinfo(struct capi_ctr *ctrl);
 
-static int __init b1isa_probe(struct pci_dev *pdev)
+static int b1isa_probe(struct pci_dev *pdev)
 {
 	avmctrl_info *cinfo;
 	avmcard *card;
@@ -108,6 +112,7 @@
 	b1_reset(card->port);
 	b1_getrevision(card);
 
+	cinfo->capi_ctrl.owner = THIS_MODULE;
 	cinfo->capi_ctrl.driver_name   = "b1isa";
 	cinfo->capi_ctrl.driverdata    = cinfo;
 	cinfo->capi_ctrl.register_appl = b1_register_appl;
@@ -118,7 +123,6 @@
 	cinfo->capi_ctrl.procinfo      = b1isa_procinfo;
 	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
 	strcpy(cinfo->capi_ctrl.name, card->name);
-	cinfo->capi_ctrl.owner = THIS_MODULE;
 
 	retval = attach_capi_ctr(&cinfo->capi_ctrl);
 	if (retval) {
@@ -170,23 +174,56 @@
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 
+static int b1isa_add_card(struct capi_driver *driver, capicardparams *data)
+{
+	int i;
+
+	for (i = 0; i < MAX_CARDS; i++) {
+		if (isa_dev[i].resource[0].start)
+			continue;
+
+		isa_dev[i].resource[0].start = data->port;
+		isa_dev[i].irq = data->irq;
+
+		if (b1isa_probe(&isa_dev[i]) == 0)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+static struct capi_driver capi_driver_b1isa = {
+	.name		= "b1isa",
+	.revision	= "1.0",
+	.add_card       = b1isa_add_card,
+};
+
 static int __init b1isa_init(void)
 {
+	char *p;
+	char rev[32];
 	int i;
-	int found = 0;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
 
 	for (i = 0; i < MAX_CARDS; i++) {
 		if (!io[i])
 			break;
 
 		isa_dev[i].resource[0].start = io[i];
-		isa_dev[i].irq_resource[0].start = irq[i];
+		isa_dev[i].irq = irq[i];
 
-		if (b1isa_probe(&isa_dev[i]) == 0)
-			found++;
+		if (b1isa_probe(&isa_dev[i]) != 0)
+			return -ENODEV;
 	}
-	if (found == 0)
-		return -ENODEV;
+
+	strlcpy(capi_driver_b1isa.revision, rev, 32);
+	register_capi_driver(&capi_driver_b1isa);
+	printk(KERN_INFO "b1isa: revision %s\n", rev);
 
 	return 0;
 }
@@ -201,6 +238,7 @@
 
 		b1isa_remove(&isa_dev[i]);
 	}
+	unregister_capi_driver(&capi_driver_b1isa);
 }
 
 module_init(b1isa_init);
--- diff/drivers/isdn/hardware/avm/b1pci.c	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/isdn/hardware/avm/b1pci.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: b1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
+/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
@@ -28,6 +28,10 @@
 
 /* ------------------------------------------------------------- */
 
+static char *revision = "$Revision: 1.1.2.2 $";
+
+/* ------------------------------------------------------------- */
+
 static struct pci_device_id b1pci_pci_tbl[] = {
 	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
 	{ }				/* Terminating entry */
@@ -362,13 +366,50 @@
 	.remove		= __devexit_p(b1pci_pci_remove),
 };
 
+static struct capi_driver capi_driver_b1pci = {
+	.name		= "b1pci",
+	.revision	= "1.0",
+};
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+static struct capi_driver capi_driver_b1pciv4 = {
+	.name		= "b1pciv4",
+	.revision	= "1.0",
+};
+#endif
+
 static int __init b1pci_init(void)
 {
-	return pci_module_init(&b1pci_pci_driver);
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+
+	err = pci_module_init(&b1pci_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_b1pci.revision, rev, 32);
+		register_capi_driver(&capi_driver_b1pci);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+		strlcpy(capi_driver_b1pciv4.revision, rev, 32);
+		register_capi_driver(&capi_driver_b1pciv4);
+#endif
+		printk(KERN_INFO "b1pci: revision %s\n", rev);
+	}
+	return err;
 }
 
 static void __exit b1pci_exit(void)
 {
+	unregister_capi_driver(&capi_driver_b1pci);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+	unregister_capi_driver(&capi_driver_b1pciv4);
+#endif
 	pci_unregister_driver(&b1pci_pci_driver);
 }
 
--- diff/drivers/isdn/hardware/avm/b1pcmcia.c	2003-06-30 10:07:33.000000000 +0100
+++ source/drivers/isdn/hardware/avm/b1pcmcia.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: b1pcmcia.c,v 1.12.6.5 2001/09/23 22:24:33 kai Exp $
+/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
@@ -27,6 +27,10 @@
 
 /* ------------------------------------------------------------- */
 
+static char *revision = "$Revision: 1.1.2.2 $";
+
+/* ------------------------------------------------------------- */
+
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
@@ -186,3 +190,36 @@
 EXPORT_SYMBOL(b1pcmcia_addcard_m1);
 EXPORT_SYMBOL(b1pcmcia_addcard_m2);
 EXPORT_SYMBOL(b1pcmcia_delcard);
+
+static struct capi_driver capi_driver_b1pcmcia = {
+	.name		= "b1pcmcia",
+	.revision	= "1.0",
+};
+
+static int __init b1pcmcia_init(void)
+{
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	strlcpy(capi_driver_b1pcmcia.revision, rev, 32);
+	register_capi_driver(&capi_driver_b1pcmcia);
+	printk(KERN_INFO "b1pci: revision %s\n", rev);
+
+	return 0;
+}
+
+static void __exit b1pcmcia_exit(void)
+{
+	unregister_capi_driver(&capi_driver_b1pcmcia);
+}
+
+module_init(b1pcmcia_init);
+module_exit(b1pcmcia_exit);
--- diff/drivers/isdn/hardware/avm/c4.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hardware/avm/c4.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: c4.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
+/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Module for AVM C4 & C2 card.
  * 
@@ -34,6 +34,10 @@
 
 /* ------------------------------------------------------------- */
 
+static char *revision = "$Revision: 1.1.2.2 $";
+
+/* ------------------------------------------------------------- */
+
 static int suppress_pollack;
 
 static struct pci_device_id c4_pci_tbl[] = {
@@ -404,18 +408,14 @@
 static void c4_dispatch_tx(avmcard *card)
 {
 	avmcard_dmainfo *dma = card->dma;
-	unsigned long flags;
 	struct sk_buff *skb;
 	u8 cmd, subcmd;
 	u16 len;
 	u32 txlen;
 	void *p;
-	
-	save_flags(flags);
-	cli();
+
 
 	if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
-	        restore_flags(flags);
 		return;
 	}
 
@@ -424,7 +424,6 @@
 #ifdef CONFIG_C4_DEBUG
 		printk(KERN_DEBUG "%s: tx underrun\n", card->name);
 #endif
-	        restore_flags(flags);
 		return;
 	}
 
@@ -470,7 +469,6 @@
 
 	c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
 
-	restore_flags(flags);
 	dev_kfree_skb_any(skb);
 }
 
@@ -664,11 +662,15 @@
 
 static irqreturn_t c4_handle_interrupt(avmcard *card)
 {
-	u32 status = c4inmeml(card->mbase+DOORBELL);
+	u32 status;
+
+	spin_lock(&card->lock);
+	status = c4inmeml(card->mbase+DOORBELL);
 
 	if (status & DBELL_RESET_HOST) {
 		u_int i;
 		c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+		spin_unlock(&card->lock);
 		if (card->nlogcontr == 0)
 			return IRQ_HANDLED;
 		printk(KERN_ERR "%s: unexpected reset\n", card->name);
@@ -683,8 +685,10 @@
 	}
 
 	status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
-	if (!status)
+	if (!status) {
+		spin_unlock(&card->lock);
 		return IRQ_HANDLED;
+	}
 	c4outmeml(card->mbase+DOORBELL, status);
 
 	if ((status & DBELL_UP_HOST) != 0) {
@@ -705,6 +709,7 @@
 			c4_dispatch_tx(card);
 		}
 	}
+	spin_unlock(&card->lock);
 	return IRQ_HANDLED;
 }
 
@@ -767,6 +772,7 @@
 static int queue_sendconfig(avmcard *card, char cval[4])
 {
 	struct sk_buff *skb;
+	unsigned long flags;
 	void *p;
 
 	skb = alloc_skb(3+4, GFP_ATOMIC);
@@ -786,7 +792,10 @@
 	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
+	
+	spin_lock_irqsave(&card->lock, flags);
 	c4_dispatch_tx(card);
+	spin_unlock_irqrestore(&card->lock, flags);
 	return 0;
 }
 
@@ -835,7 +844,6 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	unsigned long flags;
 	int retval;
 
 	if ((retval = c4_load_t4file(card, &data->firmware))) {
@@ -845,9 +853,6 @@
 		return retval;
 	}
 
-	save_flags(flags);
-	cli();
-
 	card->csr = 0;
 	c4outmeml(card->mbase+MBOX_UP_LEN, 0);
 	c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
@@ -862,7 +867,6 @@
 	c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
 	c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
 	c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
-	restore_flags(flags);
 
 	if (data->configuration.len > 0 && data->configuration.data) {
 		retval = c4_send_config(card, &data->configuration);
@@ -885,9 +889,14 @@
 	avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
 	avmctrl_info *cinfo;
 	u_int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
 
  	c4_reset(card);
 
+	spin_unlock_irqrestore(&card->lock, flags);
+
         for (i=0; i < card->nr_controllers; i++) {
 		cinfo = &card->ctrlinfo[i];
 		memset(cinfo->version, 0, sizeof(cinfo->version));
@@ -931,6 +940,7 @@
 	avmcard *card = cinfo->card;
 	struct sk_buff *skb;
 	int want = rp->level3cnt;
+	unsigned long flags;
 	int nconn;
 	void *p;
 
@@ -958,7 +968,10 @@
 		skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 		skb_queue_tail(&card->dma->send_queue, skb);
+	
+		spin_lock_irqsave(&card->lock, flags);
 		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
 }
 
@@ -968,6 +981,7 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
+	unsigned long flags;
 	struct sk_buff *skb;
 	void *p;
 
@@ -988,7 +1002,9 @@
 
 		skb_put(skb, (u8 *)p - (u8 *)skb->data);
 		skb_queue_tail(&card->dma->send_queue, skb);
+		spin_lock_irqsave(&card->lock, flags);
 		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
 }
 
@@ -1000,6 +1016,7 @@
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
 	u16 retval = CAPI_NOERROR;
+	unsigned long flags;
 
  	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
 		retval = capilib_data_b3_req(&cinfo->ncci_head,
@@ -1009,7 +1026,9 @@
 	}
 	if (retval == CAPI_NOERROR) {
 		skb_queue_tail(&card->dma->send_queue, skb);
+		spin_lock_irqsave(&card->lock, flags);
 		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
 	} else {
 		dev_kfree_skb_any(skb);
 	}
@@ -1164,6 +1183,7 @@
 
 	for (i=0; i < nr_controllers ; i++) {
 		cinfo = &card->ctrlinfo[i];
+		cinfo->capi_ctrl.owner = THIS_MODULE;
 		cinfo->capi_ctrl.driver_name   = "c4";
 		cinfo->capi_ctrl.driverdata    = cinfo;
 		cinfo->capi_ctrl.register_appl = c4_register_appl;
@@ -1174,7 +1194,6 @@
 		cinfo->capi_ctrl.procinfo      = c4_procinfo;
 		cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
 		strcpy(cinfo->capi_ctrl.name, card->name);
-		cinfo->capi_ctrl.owner = THIS_MODULE;
 
 		retval = attach_capi_ctr(&cinfo->capi_ctrl);
 		if (retval) {
@@ -1247,13 +1266,44 @@
        .remove         = c4_remove,
 };
 
+static struct capi_driver capi_driver_c2 = {
+	.name		= "c2",
+	.revision	= "1.0",
+};
+
+static struct capi_driver capi_driver_c4 = {
+	.name		= "c4",
+	.revision	= "1.0",
+};
+
 static int __init c4_init(void)
 {
-	return pci_module_init(&c4_pci_driver);
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	err = pci_module_init(&c4_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_c2.revision, rev, 32);
+		register_capi_driver(&capi_driver_c2);
+		strlcpy(capi_driver_c4.revision, rev, 32);
+		register_capi_driver(&capi_driver_c4);
+		printk(KERN_INFO "c4: revision %s\n", rev);
+	}
+	return err;
 }
 
 static void __exit c4_exit(void)
 {
+	unregister_capi_driver(&capi_driver_c2);
+	unregister_capi_driver(&capi_driver_c4);
 	pci_unregister_driver(&c4_pci_driver);
 }
 
--- diff/drivers/isdn/hardware/avm/t1isa.c	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/isdn/hardware/avm/t1isa.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: t1isa.c,v 1.16.6.7 2001/09/23 22:24:34 kai Exp $
+/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
@@ -29,6 +29,10 @@
 
 /* ------------------------------------------------------------- */
 
+static char *revision = "$Revision: 1.1.2.3 $";
+
+/* ------------------------------------------------------------- */
+
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
@@ -58,7 +62,6 @@
 {
 	unsigned char cregs[8];
 	unsigned char reverse_cardnr;
-	unsigned long flags;
 	unsigned char dummy;
 	int i;
 
@@ -73,8 +76,12 @@
 	cregs[6] = 0;
 	cregs[7] = 0;
 
-	save_flags(flags);
-	cli();
+	/*
+	 * no one else should use the ISA bus in this moment,
+	 * but no function there to prevent this :-(
+	 * save_flags(flags); cli();
+	 */
+
 	/* board reset */
 	t1outp(base, T1_RESETBOARD, 0xf);
 	mdelay(100);
@@ -87,7 +94,7 @@
 	t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
 	for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
 	t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
-	restore_flags(flags);
+	/* restore_flags(flags); */
 
 	mdelay(100);
 	t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
@@ -137,6 +144,9 @@
 	unsigned DataB3Len;
 	unsigned NCCI;
 	unsigned WindowSize;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
 
 	while (b1_rx_full(card->port)) {
 
@@ -149,6 +159,7 @@
 			ApplId = (unsigned) b1_get_word(card->port);
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
 			DataB3Len = t1_get_slice(card->port, card->databuf);
+			spin_unlock_irqrestore(&card->lock, flags);
 
 			if (MsgLen < 30) { /* not CAPI 64Bit */
 				memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
@@ -169,6 +180,7 @@
 
 			ApplId = (unsigned) b1_get_word(card->port);
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
+			spin_unlock_irqrestore(&card->lock, flags);
 			if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
 				printk(KERN_ERR "%s: incoming packet dropped\n",
 						card->name);
@@ -188,6 +200,7 @@
 			ApplId = b1_get_word(card->port);
 			NCCI = b1_get_word(card->port);
 			WindowSize = b1_get_word(card->port);
+			spin_unlock_irqrestore(&card->lock, flags);
 
 			capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
 
@@ -197,6 +210,7 @@
 
 			ApplId = b1_get_word(card->port);
 			NCCI = b1_get_word(card->port);
+			spin_unlock_irqrestore(&card->lock, flags);
 
 			if (NCCI != 0xffffffff)
 				capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
@@ -205,16 +219,19 @@
 
 		case RECEIVE_START:
 			b1_put_byte(card->port, SEND_POLLACK);
+			spin_unlock_irqrestore(&card->lock, flags);
 			capi_ctr_resume_output(ctrl);
 			break;
 
 		case RECEIVE_STOP:
+			spin_unlock_irqrestore(&card->lock, flags);
 			capi_ctr_suspend_output(ctrl);
 			break;
 
 		case RECEIVE_INIT:
 
 			cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
+			spin_unlock_irqrestore(&card->lock, flags);
 			b1_parse_version(cinfo);
 			printk(KERN_INFO "%s: %s-card (%s) now active\n",
 			       card->name,
@@ -226,6 +243,7 @@
 		case RECEIVE_TASK_READY:
 			ApplId = (unsigned) b1_get_word(card->port);
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
+			spin_unlock_irqrestore(&card->lock, flags);
 			card->msgbuf[MsgLen] = 0;
 			while (    MsgLen > 0
 			       && (   card->msgbuf[MsgLen-1] == '\n'
@@ -239,6 +257,7 @@
 
 		case RECEIVE_DEBUGMSG:
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
+			spin_unlock_irqrestore(&card->lock, flags);
 			card->msgbuf[MsgLen] = 0;
 			while (    MsgLen > 0
 			       && (   card->msgbuf[MsgLen-1] == '\n'
@@ -251,9 +270,11 @@
 
 
 		case 0xff:
+			spin_unlock_irqrestore(&card->lock, flags);
 			printk(KERN_ERR "%s: card reseted ?\n", card->name);
 			return IRQ_HANDLED;
 		default:
+			spin_unlock_irqrestore(&card->lock, flags);
 			printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
 					card->name, b1cmd);
 			return IRQ_NONE;
@@ -296,14 +317,13 @@
 		return -EIO;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&card->lock, flags);
 	b1_setinterrupt(port, card->irq, card->cardtype);
 	b1_put_byte(port, SEND_INIT);
 	b1_put_word(port, CAPI_MAXAPPL);
 	b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
 	b1_put_word(port, ctrl->cnr - 1);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return 0;
 }
@@ -349,7 +369,7 @@
 static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
 static char *t1isa_procinfo(struct capi_ctr *ctrl);
 
-static int __init t1isa_probe(struct pci_dev *pdev, int cardnr)
+static int t1isa_probe(struct pci_dev *pdev, int cardnr)
 {
 	avmctrl_info *cinfo;
 	avmcard *card;
@@ -401,6 +421,7 @@
 	t1_disable_irq(card->port);
 	b1_reset(card->port);
 
+	cinfo->capi_ctrl.owner = THIS_MODULE;
 	cinfo->capi_ctrl.driver_name   = "t1isa";
 	cinfo->capi_ctrl.driverdata    = cinfo;
 	cinfo->capi_ctrl.register_appl = b1_register_appl;
@@ -411,7 +432,6 @@
 	cinfo->capi_ctrl.procinfo      = t1isa_procinfo;
 	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
 	strcpy(cinfo->capi_ctrl.name, card->name);
-	cinfo->capi_ctrl.owner = THIS_MODULE;
 
 	retval = attach_capi_ctr(&cinfo->capi_ctrl);
 	if (retval) {
@@ -456,20 +476,18 @@
 
 		dlen = CAPIMSG_DATALEN(skb->data);
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&card->lock, flags);
 		b1_put_byte(port, SEND_DATA_B3_REQ);
 		t1_put_slice(port, skb->data, len);
 		t1_put_slice(port, skb->data + len, dlen);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&card->lock, flags);
 	} else {
 		retval = CAPI_NOERROR;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&card->lock, flags);
 		b1_put_byte(port, SEND_MESSAGE);
 		t1_put_slice(port, skb->data, len);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
  out:
 	dev_kfree_skb_any(skb);
@@ -509,23 +527,56 @@
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
 
+static int t1isa_add_card(struct capi_driver *driver, capicardparams *data)
+{
+	int i;
+
+	for (i = 0; i < MAX_CARDS; i++) {
+		if (isa_dev[i].resource[0].start)
+			continue;
+
+		isa_dev[i].resource[0].start = data->port;
+		isa_dev[i].irq = data->irq;
+
+		if (t1isa_probe(&isa_dev[i], data->cardnr) == 0)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+static struct capi_driver capi_driver_t1isa = {
+	.name		= "t1isa",
+	.revision	= "1.0",
+	.add_card       = t1isa_add_card,
+};
+
 static int __init t1isa_init(void)
 {
+	char rev[32];
+	char *p;
 	int i;
-	int found = 0;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
 
 	for (i = 0; i < MAX_CARDS; i++) {
 		if (!io[i])
 			break;
 
 		isa_dev[i].resource[0].start = io[i];
-		isa_dev[i].irq_resource[0].start = irq[i];
+		isa_dev[i].irq = irq[i];
 
-		if (t1isa_probe(&isa_dev[i], cardnr[i]) == 0)
-			found++;
+		if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0)
+			return -ENODEV;
 	}
-	if (found == 0)
-		return -ENODEV;
+
+	strlcpy(capi_driver_t1isa.revision, rev, 32);
+	register_capi_driver(&capi_driver_t1isa);
+	printk(KERN_INFO "t1isa: revision %s\n", rev);
 
 	return 0;
 }
--- diff/drivers/isdn/hardware/avm/t1pci.c	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/isdn/hardware/avm/t1pci.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: t1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
+/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
@@ -30,6 +30,8 @@
 #undef CONFIG_T1PCI_POLLDEBUG
 
 /* ------------------------------------------------------------- */
+static char *revision = "$Revision: 1.1.2.2 $";
+/* ------------------------------------------------------------- */
 
 static struct pci_device_id t1pci_pci_tbl[] = {
 	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
@@ -221,13 +223,36 @@
        .remove         = t1pci_remove,
 };
 
+static struct capi_driver capi_driver_t1pci = {
+	.name		= "t1pci",
+	.revision	= "1.0",
+};
+
 static int __init t1pci_init(void)
 {
-	return pci_module_init(&t1pci_pci_driver);
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	err = pci_module_init(&t1pci_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_t1pci.revision, rev, 32);
+		register_capi_driver(&capi_driver_t1pci);
+		printk(KERN_INFO "t1pci: revision %s\n", rev);
+	}
+	return err;
 }
 
 static void __exit t1pci_exit(void)
 {
+	unregister_capi_driver(&capi_driver_t1pci);
 	pci_unregister_driver(&t1pci_pci_driver);
 }
 
--- diff/drivers/isdn/hardware/eicon/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/isdn/hardware/eicon/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 
 menu "Active Eicon DIVA Server cards"
-	depends on NET && ISDN_BOOL && ISDN_CAPI!=n
+	depends on NET && ISDN && ISDN_CAPI!=n
 
 config CAPI_EICON
 	bool "Support Eicon cards"
--- diff/drivers/isdn/hisax/Kconfig	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/isdn/hisax/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -1,6 +1,6 @@
 
 menu "Passive cards"
-	depends on ISDN
+	depends on ISDN_I4L
 
 config ISDN_DRV_HISAX
 	tristate "HiSax SiemensChipSet driver support"
@@ -341,8 +341,8 @@
 #      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
 
 config HISAX_ENTERNOW_PCI
-	bool "Formula-n enter:now PCI card (EXPERIMENTAL)"
-	depends on PCI && EXPERIMENTAL
+	bool "Formula-n enter:now PCI card"
+	depends on PCI
 	help
 	  This enables HiSax support for the Formula-n enter:now PCI
 	  ISDN card.
@@ -365,6 +365,8 @@
 	  the ST5481 USB driver currently. 
 	  If in doubt, say yes.
 
+comment "HiSax PCMCIA card service modules"
+
 config HISAX_SEDLBAUER_CS
 	tristate "Sedlbauer PCMCIA cards"
 	depends on PCMCIA && HISAX_SEDLBAUER
@@ -374,18 +376,26 @@
 
 config HISAX_ELSA_CS
 	tristate "ELSA PCMCIA MicroLink cards"
-	depends on PCMCIA
+	depends on PCMCIA && HISAX_ELSA
 	help
 	  This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
 	  card.
 
 config HISAX_AVM_A1_CS
 	tristate "AVM A1 PCMCIA cards"
-	depends on PCMCIA
+	depends on PCMCIA && ISDN_DRV_HISAX
 	help
 	  This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
 	  PCMCIA cards.
 
+config HISAX_TELES_CS
+	tristate "TELES PCMCIA cards"
+	depends on PCMCIA && HISAX_16_3
+	help
+	  This enables the PCMCIA client driver for the Teles PCMCIA cards.
+
+comment "HiSax sub driver modules"
+
 config HISAX_ST5481
 	tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
 	depends on USB && EXPERIMENTAL
@@ -393,6 +403,12 @@
 	  This enables the driver for ST5481 based USB ISDN adapters,
 	  e.g. the BeWan Gazel 128 USB
 
+config HISAX_HFCUSB
+	tristate "HFC USB based ISDN modems (EXPERIMENTAL)"
+	depends on USB && EXPERIMENTAL
+	help
+	  This enables the driver for HFC USB based ISDN modems.
+
 config HISAX_FRITZ_PCIPNP
 	tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
@@ -402,18 +418,15 @@
 	  (the latter also needs you to select "ISA Plug and Play support"
 	  from the menu "Plug and Play configuration")
 
-config HISAX_FRITZ_CLASSIC
-	tristate "AVM Fritz!Card classic support (EXPERIMENTAL)"
-	depends on ISA && EXPERIMENTAL
-	help
-	  This enables the driver for the AVM Fritz!Card classic, formerly
-	  known as AVM A1.
-
-config HISAX_HFCPCI
-	tristate "HFC PCI support (EXPERIMENTAL)"
-	depends on PCI && EXPERIMENTAL
-	help
-	  This enables the driver for CCD HFC PCI based cards.
+config HISAX_HDLC
+	bool
+	depends on HISAX_ST5481
+	default y
+
+config HISAX_AVM_A1_PCMCIA
+	bool
+	depends on HISAX_AVM_A1_CS
+	default y
 
 endif
 
--- diff/drivers/isdn/hisax/Makefile	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -1,19 +1,23 @@
 # Makefile for the hisax ISDN device driver
 
+# The target object and module list name.
+
 # Define maximum number of cards
 
 EXTRA_CFLAGS      += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
 
-# Each configuration option enables a list of files.
-
 obj-$(CONFIG_ISDN_DRV_HISAX)		+= hisax.o
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
 obj-$(CONFIG_HISAX_ELSA_CS)		+= elsa_cs.o
 obj-$(CONFIG_HISAX_AVM_A1_CS)		+= avma1_cs.o
+obj-$(CONFIG_HISAX_TELES_CS)		+= teles_cs.o
 obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o
+obj-$(CONFIG_HISAX_HFCUSB)		+= hfc_usb.o
 obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_isac.o hisax_fcpcipnp.o
-obj-$(CONFIG_HISAX_FRITZ_CLASSIC)       += hisax_isac.o hisax_hscx.o hisax_fcclassic.o
-obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_hfcpci.o
+
+ifdef CONFIG_HISAX_HDLC
+obj-$(CONFIG_ISDN_DRV_HISAX)		+= isdnhdlc.o
+endif
 
 # Multipart objects.
 
@@ -21,7 +25,7 @@
 					   st5481_b.o st5481_hdlc.o
 
 hisax-y	  				:= config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
-		     			   lmgr.o q931.o callc.o fsm.o cert.o
+		     			   lmgr.o q931.o callc.o fsm.o
 hisax-$(CONFIG_HISAX_EURO)		+= l3dss1.o
 hisax-$(CONFIG_HISAX_NI1)		+= l3ni1.o
 hisax-$(CONFIG_HISAX_1TR6)		+= l3_1tr6.o
@@ -33,12 +37,12 @@
 hisax-$(CONFIG_HISAX_AVM_A1)		+= avm_a1.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA)	+= avm_a1p.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_FRITZPCI)		+= avm_pci.o isac.o arcofi.o
-hisax-$(CONFIG_HISAX_ELSA)		+= elsa.o isac.o arcofi.o hscx.o ipac.o
+hisax-$(CONFIG_HISAX_ELSA)		+= elsa.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_IX1MICROR2)	+= ix1_micro.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_DIEHLDIVA)		+= diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o 
-hisax-$(CONFIG_HISAX_ASUSCOM)		+= asuscom.o isac.o arcofi.o hscx.o ipac.o
+hisax-$(CONFIG_HISAX_DIEHLDIVA)		+= diva.o isac.o arcofi.o hscx.o ipacx.o 
+hisax-$(CONFIG_HISAX_ASUSCOM)		+= asuscom.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_TELEINT)		+= teleint.o isac.o arcofi.o hfc_2bs0.o
-hisax-$(CONFIG_HISAX_SEDLBAUER)		+= sedlbauer.o isac.o arcofi.o hscx.o ipac.o \
+hisax-$(CONFIG_HISAX_SEDLBAUER)		+= sedlbauer.o isac.o arcofi.o hscx.o \
 					   isar.o
 hisax-$(CONFIG_HISAX_SPORTSTER)		+= sportster.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_MIC)		+= mic.o isac.o arcofi.o hscx.o
@@ -51,11 +55,9 @@
 hisax-$(CONFIG_HISAX_ISURF)		+= isurf.o isac.o arcofi.o isar.o
 hisax-$(CONFIG_HISAX_HSTSAPHIR)		+= saphir.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_BKM_A4T)		+= bkm_a4t.o isac.o arcofi.o jade.o
-hisax-$(CONFIG_HISAX_SCT_QUADRO)	+= bkm_a8.o isac.o arcofi.o hscx.o ipac.o
-hisax-$(CONFIG_HISAX_GAZEL)		+= gazel.o isac.o arcofi.o hscx.o ipac.o
+hisax-$(CONFIG_HISAX_SCT_QUADRO)	+= bkm_a8.o isac.o arcofi.o hscx.o
+hisax-$(CONFIG_HISAX_GAZEL)		+= gazel.o isac.o arcofi.o hscx.o
 hisax-$(CONFIG_HISAX_W6692)		+= w6692.o
 hisax-$(CONFIG_HISAX_ENTERNOW_PCI)	+= enternow_pci.o amd7930_fn.o
 #hisax-$(CONFIG_HISAX_TESTEMU)		+= testemu.o
 
-CERT = $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?)
-CFLAGS_cert.o = -DCERTIFICATION=$(CERT)
--- diff/drivers/isdn/hisax/amd7930_fn.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/amd7930_fn.c	2004-02-18 09:03:59.000000000 +0000
@@ -62,42 +62,53 @@
 
 static void Amd7930_new_ph(struct IsdnCardState *cs);
 
-static inline u8
-HIBYTE(u16 w)
-{
-	return (w >> 8) & 0xff;
-}
+static WORD initAMD[] = {
+	0x0100,
 
-static inline u8
-LOBYTE(u16 w)
-{
-	return w & 0xff;
-}
+	0x00A5, 3, 0x01, 0x40, 0x58,				// LPR, LMR1, LMR2
+	0x0086, 1, 0x0B,					// DMR1 (D-Buffer TH-Interrupts on)
+	0x0087, 1, 0xFF,					// DMR2
+	0x0092, 1, 0x03,					// EFCR (extended mode d-channel-fifo on)
+	0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,			// FRAR4, SRAR4, DMR3, DMR4 (address recognition )
+	0x0084, 2, 0x80, 0x00,					// DRLR
+	0x00C0, 1, 0x47,					// PPCR1
+	0x00C8, 1, 0x01,					// PPCR2
 
-static inline u8
-rByteAMD(struct IsdnCardState *cs, u8 reg)
-{
-	return cs->dc_hw_ops->read_reg(cs, reg);
-}
+	0x0102,
+	0x0107,
+	0x01A1, 1,
+	0x0121, 1,
+	0x0189, 2,
 
-static inline void
-wByteAMD(struct IsdnCardState *cs, u8 reg, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, reg, val);
-}
+	0x0045, 4, 0x61, 0x72, 0x00, 0x00,			// MCR1, MCR2, MCR3, MCR4
+	0x0063, 2, 0x08, 0x08,					// GX
+	0x0064, 2, 0x08, 0x08,					// GR
+	0x0065, 2, 0x99, 0x00,					// GER
+	0x0066, 2, 0x7C, 0x8B,					// STG
+	0x0067, 2, 0x00, 0x00,					// FTGR1, FTGR2
+	0x0068, 2, 0x20, 0x20,					// ATGR1, ATGR2
+	0x0069, 1, 0x4F,					// MMR1
+	0x006A, 1, 0x00,					// MMR2
+	0x006C, 1, 0x40,					// MMR3
+	0x0021, 1, 0x02,					// INIT
+	0x00A3, 1, 0x40,					// LMR1
 
-static void
-wWordAMD(struct IsdnCardState *cs, u8 reg, u16 val)
+	0xFFFF
+};
+
+
+void /* macro wWordAMD */
+WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
 {
         wByteAMD(cs, 0x00, reg);
         wByteAMD(cs, 0x01, LOBYTE(val));
         wByteAMD(cs, 0x01, HIBYTE(val));
 }
 
-static u16
-rWordAMD(struct IsdnCardState *cs, u8 reg)
+WORD /* macro rWordAMD */
+ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
 {
-        u16 res;
+        WORD res;
         /* direct access register */
         if(reg < 8) {
         	res = rByteAMD(cs, reg);
@@ -112,20 +123,9 @@
 	return (res);
 }
 
-static inline void
-AmdIrqOff(struct IsdnCardState *cs)
-{
-	cs->dc.amd7930.setIrqMask(cs, 0);
-}
-
-static inline void
-AmdIrqOn(struct IsdnCardState *cs)
-{
-	cs->dc.amd7930.setIrqMask(cs, 1);
-}
 
 static void
-Amd7930_ph_command(struct IsdnCardState *cs, u8 command, char *s)
+Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
 {
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
@@ -136,7 +136,7 @@
 
 
 
-static u8 i430States[] = {
+static BYTE i430States[] = {
 // to   reset  F3    F4    F5    F6    F7    F8    AR     from
         0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
         0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
@@ -150,14 +150,14 @@
 
 
 /*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
-static u8 stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
 
 
 
 
 static void
 Amd7930_get_state(struct IsdnCardState *cs) {
-        u8 lsr = rByteAMD(cs, 0xA1);
+        BYTE lsr = rByteAMD(cs, 0xA1);
         cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
         Amd7930_new_ph(cs);
 }
@@ -167,8 +167,8 @@
 static void
 Amd7930_new_ph(struct IsdnCardState *cs)
 {
-        u8 index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
-        u8 message = i430States[index];
+        u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
+        u_char message = i430States[index];
 
         if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
@@ -176,7 +176,7 @@
 
         cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
 
-        /* abort transmit if necessary */
+        /* abort transmit if nessesary */
         if ((message & 0xf0) && (cs->tx_skb)) {
                 wByteAMD(cs, 0x21, 0xC2);
                 wByteAMD(cs, 0x21, 0x02);
@@ -232,9 +232,9 @@
 
 
 static void
-Amd7930_bh(void *data)
+Amd7930_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
+
         struct PStack *stptr;
 
 	if (!cs)
@@ -244,7 +244,7 @@
 			debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			stptr->l2.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -267,13 +267,12 @@
         }
 }
 
-
 static void
 Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
 {
 
-        u8 stat, der;
-	u8 *ptr;
+        BYTE stat, der;
+	BYTE *ptr;
 	struct sk_buff *skb;
 
 
@@ -317,7 +316,7 @@
 								QuickHex(t, cs->rcvbuf, cs->rcvidx);
 								debugl1(cs, cs->dlog);
 							}
-                                                        /* moves received data in sk-buffer */
+                                                        /* moves recieved data in sk-buffer */
 							memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
 							skb_queue_tail(&cs->rq, skb);
 						}
@@ -327,10 +326,10 @@
                                 /* throw damaged packets away, reset recieve-buffer, indicate RX */
 				ptr = cs->rcvbuf;
 				cs->rcvidx = 0;
-				sched_d_event(cs, D_RCVBUFREADY);
+				schedule_event(cs, D_RCVBUFREADY);
 			}
                 }
-		/* Packet too long, overflow */
+		/* Packet to long, overflow */
 		if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
 			if (cs->debug & L1_DEB_WARN)
 			        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
@@ -346,9 +345,9 @@
 Amd7930_fill_Dfifo(struct IsdnCardState *cs)
 {
 
-        u16 dtcrr, dtcrw, len, count;
-        u8 txstat, dmr3;
-        u8 *ptr, *deb_ptr;
+        WORD dtcrr, dtcrw, len, count;
+        BYTE txstat, dmr3;
+        BYTE *ptr, *deb_ptr;
 
 	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 		debugl1(cs, "Amd7930: fill_Dfifo");
@@ -414,10 +413,10 @@
 }
 
 
-void Amd7930_interrupt(struct IsdnCardState *cs, u8 irflags)
+void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
 {
-	u8 dsr1, dsr2, lsr;
-        u16 der;
+	BYTE dsr1, dsr2, lsr;
+        WORD der;
 
  while (irflags)
  {
@@ -443,7 +442,7 @@
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-				sched_d_event(cs, D_CLEARBUSY);
+				schedule_event(cs, D_CLEARBUSY);
                         /* restart frame */
                         if (cs->tx_skb) {
 				skb_push(cs->tx_skb, cs->tx_cnt);
@@ -461,7 +460,7 @@
 		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 			del_timer(&cs->dbusytimer);
 		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			sched_d_event(cs, D_CLEARBUSY);
+			schedule_event(cs, D_CLEARBUSY);
                 /* restart TX-Frame */
                 if (cs->tx_skb) {
 			skb_push(cs->tx_skb, cs->tx_cnt);
@@ -482,7 +481,7 @@
                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 			del_timer(&cs->dbusytimer);
 		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			sched_d_event(cs, D_CLEARBUSY);
+			schedule_event(cs, D_CLEARBUSY);
 		if (cs->tx_skb) {
 			if (cs->tx_skb->len)
 				Amd7930_fill_Dfifo(cs);
@@ -511,7 +510,7 @@
                 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 			del_timer(&cs->dbusytimer);
 		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			sched_d_event(cs, D_CLEARBUSY);
+			schedule_event(cs, D_CLEARBUSY);
 
                 if (cs->tx_skb) {
         		if (cs->debug & L1_DEB_ISAC)
@@ -529,7 +528,7 @@
 			Amd7930_fill_Dfifo(cs);
 		}
                 else
-			sched_d_event(cs, D_XMTBUFREADY);
+			schedule_event(cs, D_XMTBUFREADY);
 		/* AMD interrupts on */
                 AmdIrqOn(cs);
         }
@@ -544,7 +543,7 @@
 
 		cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
 
-		sched_d_event(cs, D_L1STATECHANGE);
+		schedule_event(cs, D_L1STATECHANGE);
 		/* AMD interrupts on */
                 AmdIrqOn(cs);
 	}
@@ -560,6 +559,7 @@
 {
         struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
         if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
@@ -570,6 +570,7 @@
 				LogFrame(cs, skb->data, skb->len);
 			if (cs->debug & DEB_DLOG_VERBOSE)
 				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
 			if (cs->tx_skb) {
 				skb_queue_tail(&cs->sq, skb);
 #ifdef L2FRAME_DEBUG		/* psa */
@@ -586,8 +587,10 @@
 #endif
 				Amd7930_fill_Dfifo(cs);
 			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
+			spin_lock_irqsave(&cs->lock, flags);
 			if (cs->tx_skb) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
@@ -606,6 +609,7 @@
 				Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
 #endif
 			Amd7930_fill_Dfifo(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
 #ifdef L2FRAME_DEBUG		/* psa */
@@ -614,21 +618,23 @@
 #endif
 			if (!cs->tx_skb) {
 				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l2.l1l2(st, PH_PULL | CONFIRM, NULL);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 			} else
 				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
-
-                        if ((cs->dc.amd7930.ph_state == 8))
-                                /* b-channels off, PH-AR cleared
-                                 * change to F3 */
-                                Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
-			else {
-                                Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
-                                cs->dc.amd7930.ph_state = 2;
-                                Amd7930_new_ph(cs);
-                        }
+			spin_lock_irqsave(&cs->lock, flags);
+			if ((cs->dc.amd7930.ph_state == 8)) {
+				/* b-channels off, PH-AR cleared
+				 * change to F3 */
+				Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
+				spin_unlock_irqrestore(&cs->lock, flags);
+			} else {
+				Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
+				cs->dc.amd7930.ph_state = 2;
+				spin_unlock_irqrestore(&cs->lock, flags);
+				Amd7930_new_ph(cs);
+			}
 			break;
 		case (HW_ENABLE | REQUEST):
                         cs->dc.amd7930.ph_state = 9;
@@ -650,7 +656,7 @@
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-				sched_d_event(cs, D_CLEARBUSY);
+				schedule_event(cs, D_CLEARBUSY);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -659,7 +665,7 @@
 	}
 }
 
-static int
+void
 setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
 {
 
@@ -667,21 +673,30 @@
 		debugl1(cs, "Amd7930: setstack called");
 
         st->l1.l1hw = Amd7930_l1hw;
-	return 0;
 }
 
+
+void
+DC_Close_Amd7930(struct IsdnCardState *cs) {
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: DC_Close called");
+}
+
+
 static void
 dbusy_timer_handler(struct IsdnCardState *cs)
 {
+	u_long flags;
 	struct PStack *stptr;
-        u16 dtcr, der;
-        u8 dsr1, dsr2;
+        WORD dtcr, der;
+        BYTE dsr1, dsr2;
 
 
         if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "Amd7930: dbusy_timer expired!");
 
 	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		spin_lock_irqsave(&cs->lock, flags);
                 /* D Transmit Byte Count Register:
                  * Counts down packet's number of Bytes, 0 if packet ready */
                 dtcr = rWordAMD(cs, 0x85);
@@ -689,14 +704,15 @@
                 dsr2 = rByteAMD(cs, 0x07);
                 der  = rWordAMD(cs, 0x03);
 
-        if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
+	        if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
 
-		if ((int)(cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {	/* D-Channel Busy */
+		if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {	/* D-Channel Busy */
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
+			spin_unlock_irqrestore(&cs->lock, flags);
 			while (stptr != NULL) {
-				stptr->l2.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 
@@ -716,7 +732,8 @@
 			/* Transmitter reset, abort transmit */
 			wByteAMD(cs, 0x21, 0x82);
 			wByteAMD(cs, 0x21, 0x02);
-			cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */
+			spin_unlock_irqrestore(&cs->lock, flags);
+			cs->irq_func(cs->irq, cs, NULL);
 
                         if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
@@ -724,59 +741,23 @@
 	}
 }
 
-static u16 initAMD[] = {
-	0x0100,
 
-	0x00A5, 3, 0x01, 0x40, 0x58,				// LPR, LMR1, LMR2
-	0x0086, 1, 0x0B,					// DMR1 (D-Buffer TH-Interrupts on)
-	0x0087, 1, 0xFF,					// DMR2
-	0x0092, 1, 0x03,					// EFCR (extended mode d-channel-fifo on)
-	0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,			// FRAR4, SRAR4, DMR3, DMR4 (address recognition )
-	0x0084, 2, 0x80, 0x00,					// DRLR
-	0x00C0, 1, 0x47,					// PPCR1
-	0x00C8, 1, 0x01,					// PPCR2
-
-	0x0102,
-	0x0107,
-	0x01A1, 1,
-	0x0121, 1,
-	0x0189, 2,
-
-	0x0045, 4, 0x61, 0x72, 0x00, 0x00,			// MCR1, MCR2, MCR3, MCR4
-	0x0063, 2, 0x08, 0x08,					// GX
-	0x0064, 2, 0x08, 0x08,					// GR
-	0x0065, 2, 0x99, 0x00,					// GER
-	0x0066, 2, 0x7C, 0x8B,					// STG
-	0x0067, 2, 0x00, 0x00,					// FTGR1, FTGR2
-	0x0068, 2, 0x20, 0x20,					// ATGR1, ATGR2
-	0x0069, 1, 0x4F,					// MMR1
-	0x006A, 1, 0x00,					// MMR2
-	0x006C, 1, 0x40,					// MMR3
-	0x0021, 1, 0x02,					// INIT
-	0x00A3, 1, 0x40,					// LMR1
-
-	0xFFFF};
-
-static struct dc_l1_ops amd7930_l1_ops = {
-	.open       = setstack_Amd7930,
-	.bh_func    = Amd7930_bh,
-	.dbusy_func = dbusy_timer_handler,
-};
 
 void __devinit
 Amd7930_init(struct IsdnCardState *cs)
 {
-	u16 *ptr;
-	u8 cmd, cnt;
+    WORD *ptr;
+    BYTE cmd, cnt;
 
         if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "Amd7930: initamd called");
 
-	dc_l1_init(cs, &amd7930_l1_ops);
         cs->dc.amd7930.tx_xmtlen = 0;
         cs->dc.amd7930.old_state = 0;
         cs->dc.amd7930.lmr1 = 0x40;
         cs->dc.amd7930.ph_command = Amd7930_ph_command;
+	cs->setstack_d = setstack_Amd7930;
+	cs->DC_Close = DC_Close_Amd7930;
 
 	/* AMD Initialisation */
 	for (ptr = initAMD; *ptr != 0xFFFF; ) {
@@ -805,11 +786,11 @@
 	}
 }
 
-int
-amd7930_setup(struct IsdnCardState *cs, struct dc_hw_ops *amd7930_ops,
-	      void (*set_irq_mask)(struct IsdnCardState *, u8 val))
-{
-	cs->dc_hw_ops = amd7930_ops;
-        cs->dc.amd7930.setIrqMask = set_irq_mask;
-	return 0;
+void __devinit
+setup_Amd7930(struct IsdnCardState *cs)
+{
+        INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs);
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 }
--- diff/drivers/isdn/hisax/amd7930_fn.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/amd7930_fn.h	2004-02-18 09:03:59.000000000 +0000
@@ -12,13 +12,26 @@
  */
 
 
+
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define rByteAMD(cs, reg)					cs->readisac(cs, reg)
+#define wByteAMD(cs, reg, val)					cs->writeisac(cs, reg, val)
+#define rWordAMD(cs, reg)					ReadWordAmd7930(cs, reg)
+#define wWordAMD(cs, reg, val)					WriteWordAmd7930(cs, reg, val)
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+
+#define AmdIrqOff(cs)						cs->dc.amd7930.setIrqMask(cs, 0)
+#define AmdIrqOn(cs)						cs->dc.amd7930.setIrqMask(cs, 1)
+
 #define AMD_CR		0x00
 #define AMD_DR		0x01
 
 
 #define DBUSY_TIMER_VALUE 80
 
-void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags);
-void Amd7930_init(struct IsdnCardState *cs);
-int  amd7930_setup(struct IsdnCardState *cs, struct dc_hw_ops *amd7930_ops,
-		   void (*set_irq_mask)(struct IsdnCardState *, u8 val));
+extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char);
+extern void Amd7930_init(struct IsdnCardState *);
+extern void setup_Amd7930(struct IsdnCardState *);
--- diff/drivers/isdn/hisax/arcofi.c	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/arcofi.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: arcofi.c,v 1.12.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
  *
  * Ansteuerung ARCOFI 2165
  *
@@ -17,19 +17,6 @@
 
 #define ARCOFI_TIMER_VALUE	20
 
-
-static inline u8
-isac_read(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-isac_write(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
 static void
 add_arcofi_timer(struct IsdnCardState *cs) {
 	if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
@@ -42,7 +29,7 @@
 
 static void
 send_arcofi(struct IsdnCardState *cs) {
-	u8 val;
+	u_char val;
 	
 	add_arcofi_timer(cs);
 	cs->dc.isac.mon_txp = 0;
@@ -56,11 +43,11 @@
 	}
 	cs->dc.isac.mocr &= 0x0f;
 	cs->dc.isac.mocr |= 0xa0;
-	isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
-	val = isac_read(cs, ISAC_MOSR);
-	isac_write(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
+	cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+	val = cs->readisac(cs, ISAC_MOSR);
+	cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 	cs->dc.isac.mocr |= 0x10;
-	isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+	cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 }
 
 int
--- diff/drivers/isdn/hisax/asuscom.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/asuscom.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.11.6.3 2001/09/23 22:24:46 kai Exp $
+/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
  *
@@ -22,9 +22,8 @@
 
 extern const char *CardType[];
 
-const char *Asuscom_revision = "$Revision: 1.11.6.3 $";
+const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
 
-static spinlock_t asuscom_lock = SPIN_LOCK_UNLOCKED;
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
@@ -43,237 +42,258 @@
 /* CARD_ADR (Write) */
 #define ASUS_RESET      0x80	/* Bit 7 Reset-Leitung */
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&asuscom_lock, flags);
-	byteout(cs->hw.asus.adr, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&asuscom_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&asuscom_lock, flags);
-	byteout(cs->hw.asus.adr, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&asuscom_lock, flags);
+	byteout(ale, off);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.asus.adr, off);
-	insb(adr, data, size);
+	byteout(ale, off);
+	byteout(adr, data);
 }
 
-
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.asus.adr, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.asus.isac, offset);
+	return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.asus.isac, offset, value);
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.asus.isac, 0, data, size);
+	readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.asus.isac, 0, data, size);
+	writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value);
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.asus.hscx, hscx ? 0x40 : 0, data, size);
+	readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.asus.hscx, hscx ? 0x40 : 0, data, size);
+	writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 off)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	u8 ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&asuscom_lock, flags);
-	byteout(cs->hw.asus.adr, off);
-	ret = bytein(cs->hw.asus.isac);
-	spin_unlock_irqrestore(&asuscom_lock, flags);
-	return ret;
+	return (readreg(cs->hw.asus.adr,
+			cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-static inline void
-ipac_write(struct IsdnCardState *cs, u8 off, u8 data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&asuscom_lock, flags);
-	byteout(cs->hw.asus.adr, off);
-	byteout(cs->hw.asus.isac, data);
-	spin_unlock_irqrestore(&asuscom_lock, flags);
-}
-
-static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 * data, int size)
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	byteout(cs->hw.asus.adr, off);
-	insb(cs->hw.asus.isac, data, size);
+	writereg(cs->hw.asus.adr,
+		 cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size)
-{
-	byteout(cs->hw.asus.adr, off);
-	outsb(cs->hw.asus.isac, data, size);
+#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
+		cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
+		cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
+		cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
+		cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
+	writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char ista, val, icnt = 5;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
+Start_IPAC:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val)
+			hscx_int_main(cs, val);
+	}
+	if (ista & 0x20) {
+		val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista  = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPAC;
+	}
+	if (!icnt)
+		printk(KERN_WARNING "ASUS IRQ LOOP\n");
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
+	writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
+void
+release_io_asuscom(struct IsdnCardState *cs)
+{
+	int bytecnt = 8;
 
-BUILD_IPAC_OPS(ipac);
+	if (cs->hw.asus.cfg_reg)
+		release_region(cs->hw.asus.cfg_reg, bytecnt);
+}
 
-static int
-asuscom_reset(struct IsdnCardState *cs)
+static void
+reset_asuscom(struct IsdnCardState *cs)
 {
-	byteout(cs->hw.asus.adr, ASUS_RESET);	/* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	byteout(cs->hw.asus.adr, 0);	/* Reset Off */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	return 0;
+	if (cs->subtyp == ASUS_IPAC)
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
+	else
+		byteout(cs->hw.asus.adr, ASUS_RESET);	/* Reset On */
+	mdelay(10);
+	if (cs->subtyp == ASUS_IPAC)
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
+	else
+		byteout(cs->hw.asus.adr, 0);	/* Reset Off */
+	mdelay(10);
+	if (cs->subtyp == ASUS_IPAC) {
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
+		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
+	}
 }
 
 static int
-asuscom_ipac_reset(struct IsdnCardState *cs)
+Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	writereg(cs, cs->hw.asus.isac, IPAC_POTA2, 0x20);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs, cs->hw.asus.isac, IPAC_POTA2, 0x0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs, cs->hw.asus.isac, IPAC_CONF, 0x0);
-	writereg(cs, cs->hw.asus.isac, IPAC_ACFG, 0xff);
-	writereg(cs, cs->hw.asus.isac, IPAC_AOE, 0x0);
-	writereg(cs, cs->hw.asus.isac, IPAC_MASK, 0xc0);
-	writereg(cs, cs->hw.asus.isac, IPAC_PCFG, 0x12);
-	return 0;
-}
-
-static struct card_ops asuscom_ops = {
-	.init     = inithscxisac,
-	.reset    = asuscom_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static struct card_ops asuscom_ipac_ops = {
-	.init     = ipac_init,
-	.reset    = asuscom_ipac_reset,
-	.release  = hisax_release_resources,
-	.irq_func = ipac_irq,
-};
+	u_long flags;
 
-static int __init
-asuscom_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	int rc;
-	u8 val;
-
-	printk(KERN_INFO "ISDNLink: defined at %#lx IRQ %lu\n",
-	       card->para[1], card->para[0]);
-
-	cs->hw.asus.cfg_reg = card->para[1];
-	cs->irq = card->para[0];
-
-	rc = -EBUSY;
-	if (!request_io(&cs->rs, cs->hw.asus.cfg_reg, 8, "asuscom isdn"))
-		goto err;
-
-	rc = -ENODEV;
-	cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
-	val = readreg(cs, cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
-	if ((val == 1) || (val == 2)) {
-		cs->subtyp = ASUS_IPAC;
-		cs->card_ops = &asuscom_ipac_ops;
-		cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
-		if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-			goto err;
-	} else {
-		cs->subtyp = ASUS_ISACHSCX;
-		cs->card_ops = &asuscom_ops;
-		cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
-		cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
-		cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
-		cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
-		cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
-		if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-			goto err;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_asuscom(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_asuscom(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->debug |= L1_DEB_IPAC;
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	printk(KERN_INFO "ISDNLink: resetting card\n");
-	cs->card_ops->reset(cs);
-	return 0;
-
- err:
-	hisax_release_resources(cs);
-	return rc;
+	return(0);
 }
 
 #ifdef __ISAPNP__
@@ -293,66 +313,115 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *adev = &asus_ids[0];
+static struct isapnp_device_id *ipid __initdata = &asus_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __init
 setup_asuscom(struct IsdnCard *card)
 {
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
 	char tmp[64];
 
 	strcpy(tmp, Asuscom_revision);
 	printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_ASUSCOM)
+		return (0);
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-		while(adev->card_vendor) {
-			if ((pb = pnp_find_card(adev->card_vendor,
-						adev->card_device,
-						pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       adev->vendor,
-						       adev->function,
-						       pd))) {
 					printk(KERN_INFO "HiSax: %s detected\n",
-						(char *)adev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "AsusPnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "AsusPnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) {
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+					if (!card->para[0] || !card->para[1]) {
 						printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
-							pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
 						return(0);
 					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
 					break;
 				} else {
 					printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
 				}
 			}
-			adev++;
-			pnp_c=NULL;
+			ipid++;
+			pnp_c = NULL;
 		} 
-		if (!adev->card_vendor) {
+		if (!ipid->card_vendor) {
 			printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
 			return(0);
 		}
 	}
 #endif
-	if (asuscom_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	bytecnt = 8;
+	cs->hw.asus.cfg_reg = card->para[1];
+	cs->irq = card->para[0];
+	if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.asus.cfg_reg,
+		       cs->hw.asus.cfg_reg + bytecnt);
+		return (0);
+	}
+	printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
+		cs->hw.asus.cfg_reg, cs->irq);
+	setup_isac(cs);
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Asus_card_msg;
+	val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, 
+		cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
+	if ((val == 1) || (val == 2)) {
+		cs->subtyp = ASUS_IPAC;
+		cs->hw.asus.adr  = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
+		cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
+		cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+		cs->readisac = &ReadISAC_IPAC;
+		cs->writeisac = &WriteISAC_IPAC;
+		cs->readisacfifo = &ReadISACfifo_IPAC;
+		cs->writeisacfifo = &WriteISACfifo_IPAC;
+		cs->irq_func = &asuscom_interrupt_ipac;
+		printk(KERN_INFO "Asus: IPAC version %x\n", val);
+	} else {
+		cs->subtyp = ASUS_ISACHSCX;
+		cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
+		cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
+		cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
+		cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
+		cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
+		cs->readisac = &ReadISAC;
+		cs->writeisac = &WriteISAC;
+		cs->readisacfifo = &ReadISACfifo;
+		cs->writeisacfifo = &WriteISACfifo;
+		cs->irq_func = &asuscom_interrupt;
+		ISACVersion(cs, "ISDNLink:");
+		if (HscxVersion(cs, "ISDNLink:")) {
+			printk(KERN_WARNING
+		     	"ISDNLink: wrong HSCX versions check IO address\n");
+			release_io_asuscom(cs);
+			return (0);
+		}
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/avm_a1.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/avm_a1.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: avm_a1.c,v 2.13.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
  *
  * low level stuff for AVM A1 (Fritz) isdn cards
  *
@@ -17,7 +17,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static const char *avm_revision = "$Revision: 2.13.6.2 $";
+static const char *avm_revision = "$Revision: 2.15.2.4 $";
 
 #define	 AVM_A1_STAT_ISAC	0x01
 #define	 AVM_A1_STAT_HSCX	0x02
@@ -26,172 +26,237 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static inline u8
-readreg(unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int adr, u_char off)
 {
 	return (bytein(adr + off));
 }
 
 static inline void
-writereg(unsigned int adr, u8 off, u8 data)
+writereg(unsigned int adr, u_char off, u_char data)
 {
 	byteout(adr + off, data);
 }
 
 
 static inline void
-read_fifo(unsigned int adr, u8 * data, int size)
+read_fifo(unsigned int adr, u_char * data, int size)
 {
 	insb(adr, data, size);
 }
 
 static void
-write_fifo(unsigned int adr, u8 * data, int size)
+write_fifo(unsigned int adr, u_char * data, int size)
 {
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.avm.isac, offset);
+	return (readreg(cs->hw.avm.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.avm.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	read_fifo(cs->hw.avm.isacfifo, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	write_fifo(cs->hw.avm.isacfifo, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
 	return (readreg(cs->hw.avm.hscx[hscx], offset));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
 	writereg(cs->hw.avm.hscx[hscx], offset, value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	read_fifo(cs->hw.avm.hscxfifo[hscx], data, size);
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	write_fifo(cs->hw.avm.hscxfifo[hscx], data, size);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+#include "hscx_irq.c"
 
 static irqreturn_t
 avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val, sval;
-	int handled = 0;
+	u_char val, sval;
+	u_long flags;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
-		handled = 1;
 		if (!(sval & AVM_A1_STAT_TIMER)) {
 			byteout(cs->hw.avm.cfg_reg, 0x1E);
 			sval = bytein(cs->hw.avm.cfg_reg);
 		} else if (cs->debug & L1_DEB_INTSTAT)
 			debugl1(cs, "avm IntStatus %x", sval);
 		if (!(sval & AVM_A1_STAT_HSCX)) {
-			val = hscx_read(cs, 1, HSCX_ISTA);
+			val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
 			if (val)
 				hscx_int_main(cs, val);
 		}
 		if (!(sval & AVM_A1_STAT_ISAC)) {
-			val = isac_read(cs, ISAC_ISTA);
+			val = readreg(cs->hw.avm.isac, ISAC_ISTA);
 			if (val)
 				isac_interrupt(cs, val);
 		}
 	}
-	hscx_write(cs, 0, HSCX_MASK, 0xFF);
-	hscx_write(cs, 1, HSCX_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0x0);
-	hscx_write(cs, 0, HSCX_MASK, 0x0);
-	hscx_write(cs, 1, HSCX_MASK, 0x0);
-	spin_unlock(&cs->lock);
-	return IRQ_RETVAL(handled);
+	writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
+	writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
+	writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
+	writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+inline static void
+release_ioregs(struct IsdnCardState *cs, int mask)
+{
+	release_region(cs->hw.avm.cfg_reg, 8);
+	if (mask & 1)
+		release_region(cs->hw.avm.isac + 32, 32);
+	if (mask & 2)
+		release_region(cs->hw.avm.isacfifo, 1);
+	if (mask & 4)
+		release_region(cs->hw.avm.hscx[0] + 32, 32);
+	if (mask & 8)
+		release_region(cs->hw.avm.hscxfifo[0], 1);
+	if (mask & 0x10)
+		release_region(cs->hw.avm.hscx[1] + 32, 32);
+	if (mask & 0x20)
+		release_region(cs->hw.avm.hscxfifo[1], 1);
+}
+
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			return(0);
+		case CARD_RELEASE:
+			release_ioregs(cs, 0x3f);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 1);
+			byteout(cs->hw.avm.cfg_reg, 0x16);
+			byteout(cs->hw.avm.cfg_reg, 0x1E);
+			inithscxisac(cs, 2);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
-static void
-avm_a1_init(struct IsdnCardState *cs)
+int __init
+setup_avm_a1(struct IsdnCard *card)
 {
-	byteout(cs->hw.avm.cfg_reg, 0x16);
-	byteout(cs->hw.avm.cfg_reg, 0x1E);
-	inithscxisac(cs);
-}
-
-static struct card_ops avm_a1_ops = {
-	.init     = avm_a1_init,
-	.release  = hisax_release_resources,
-	.irq_func = avm_a1_interrupt,
-};
-
-static int __init
-avm_a1_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	int rc;
-	u8 val;
-
-	printk(KERN_INFO "AVM A1: defined at %#lx IRQ %lu\n",
-	       card->para[1], card->para[0]);
-
-	rc = -EBUSY;
-	cs->hw.avm.cfg_reg     = request_io(&cs->rs, card->para[1] + 0x1800,  8, "avm cfg");
-	if (!cs->hw.avm.cfg_reg) goto err;
-	cs->hw.avm.isac        = request_io(&cs->rs, card->para[1] + 0x1400, 32, "HiSax isac");
-	if (!cs->hw.avm.isac) goto err;
-	cs->hw.avm.isacfifo    = request_io(&cs->rs, card->para[1] + 0x1000,  1, "HiSax isac fifo");
-	if (!cs->hw.avm.isacfifo) goto err;
-	cs->hw.avm.hscx[0]     = request_io(&cs->rs, card->para[1] + 0x400,  32, "HiSax hscx A");
-	if (!cs->hw.avm.hscx[0]) goto err;
-	cs->hw.avm.hscxfifo[0] = request_io(&cs->rs, card->para[1],           1, "HiSax hscx A fifo");
-	if (!cs->hw.avm.hscxfifo[0]) goto err;
-	cs->hw.avm.hscx[1]     = request_io(&cs->rs, card->para[1] + 0xc00,  32, "HiSax hscx B");
-	if (!cs->hw.avm.hscx[1]) goto err;
-	cs->hw.avm.hscxfifo[1] = request_io(&cs->rs, card->para[1] + 0x800,   1, "HiSax hscx B fifo");
-	if (!cs->hw.avm.hscxfifo[1]) goto err;
-	cs->hw.avm.isac    -= 0x20;
-	cs->hw.avm.hscx[0] -= 0x20;
-	cs->hw.avm.hscx[1] -= 0x20;
-	cs->irq = card->para[0];
+	u_char val;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, avm_revision);
+	printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_A1)
+		return (0);
 
+	cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
+	cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
+	cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
+	cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
+	cs->hw.avm.isacfifo = card->para[1] + 0x1000;
+	cs->hw.avm.hscxfifo[0] = card->para[1];
+	cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
+	cs->irq = card->para[0];
+	if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.avm.cfg_reg,
+		       cs->hw.avm.cfg_reg + 8);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
+		printk(KERN_WARNING
+		       "HiSax: %s isac ports %x-%x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.isac + 32,
+		       cs->hw.avm.isac + 64);
+		release_ioregs(cs, 0);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
+		printk(KERN_WARNING
+		       "HiSax: %s isac fifo port %x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.isacfifo);
+		release_ioregs(cs, 1);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx A ports %x-%x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.hscx[0] + 32,
+		       cs->hw.avm.hscx[0] + 64);
+		release_ioregs(cs, 3);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx A fifo port %x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.hscxfifo[0]);
+		release_ioregs(cs, 7);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx B ports %x-%x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.hscx[1] + 32,
+		       cs->hw.avm.hscx[1] + 64);
+		release_ioregs(cs, 0xf);
+		return (0);
+	}
+	if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx B fifo port %x already in use\n",
+		       CardType[cs->typ],
+		       cs->hw.avm.hscxfifo[1]);
+		release_ioregs(cs, 0x1f);
+		return (0);
+	}
 	byteout(cs->hw.avm.cfg_reg, 0x0);
 	HZDELAY(HZ / 5 + 1);
 	byteout(cs->hw.avm.cfg_reg, 0x1);
@@ -219,24 +284,34 @@
 	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 	       cs->hw.avm.cfg_reg, val);
 
-	cs->card_ops = &avm_a1_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
-}
-
-int __init
-setup_avm_a1(struct IsdnCard *card)
-{
-	char tmp[64];
-
-	strcpy(tmp, avm_revision);
-	printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
-
-	if (avm_a1_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	printk(KERN_INFO
+	       "HiSax: %s config irq:%d cfg:0x%X\n",
+	       CardType[cs->typ], cs->irq,
+	       cs->hw.avm.cfg_reg);
+	printk(KERN_INFO
+	       "HiSax: isac:0x%X/0x%X\n",
+	       cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
+	printk(KERN_INFO
+	       "HiSax: hscx A:0x%X/0x%X  hscx B:0x%X/0x%X\n",
+	       cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
+	       cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
+
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	setup_isac(cs);
+	cs->cardmsg = &AVM_card_msg;
+	cs->irq_func = &avm_a1_interrupt;
+	ISACVersion(cs, "AVM A1:");
+	if (HscxVersion(cs, "AVM A1:")) {
+		printk(KERN_WARNING
+		       "AVM A1: wrong HSCX versions check IO address\n");
+		release_ioregs(cs, 0x3f);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/avm_a1p.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/avm_a1p.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: avm_a1p.c,v 2.7.6.2 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $
  *
  * low level stuff for the following AVM cards:
  * A1 PCMCIA
@@ -56,176 +56,182 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static const char *avm_revision = "$Revision: 2.7.6.2 $";
-static spinlock_t avm_a1p_lock = SPIN_LOCK_UNLOCKED;
+static const char *avm_revision = "$Revision: 2.9.2.5 $";
 
-static inline u8
-readreg(struct IsdnCardState *cs, int offset, u8 adr)
+static inline u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	unsigned long flags;
-        u8 ret;
+        u_char ret;
 
-	spin_lock_irqsave(&avm_a1p_lock, flags);
-        byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset + adr - 0x20);
-	ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
-	spin_unlock_irqrestore(&avm_a1p_lock, flags);
+        offset -= 0x20;
+        byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
+	ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
 	return ret;
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, int offset, u8 adr, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&avm_a1p_lock, flags);
-        byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset + adr - 0x20);
+        offset -= 0x20;
+        byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
 	byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
-	spin_unlock_irqrestore(&avm_a1p_lock, flags);
 }
 
 static inline void
-readfifo(struct IsdnCardState *cs, int offset, u8 *data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-        byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, offset);
-	insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
+	insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, int offset, u8 *data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, offset);
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
 	outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 adr)
-{
-	return readreg(cs, ISAC_REG_OFFSET, adr);
-}
-
-static void
-isac_write(struct IsdnCardState *cs, u8 adr, u8 value)
+static inline u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	writereg(cs, ISAC_REG_OFFSET, adr, value);
-}
+	u_char ret;
 
-static void
-isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
-{
-	readfifo(cs, ISAC_FIFO_OFFSET, data, size);
+        offset -= 0x20;
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+			HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
+	ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
+	return ret;
 }
 
-static void
-isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+static inline void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writefifo(cs, ISAC_FIFO_OFFSET, data, size);
+        offset -= 0x20;
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+			HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
+	byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 adr)
+static inline void
+ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
 {
-	return readreg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr);
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+			HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
+	insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
 }
 
-static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 adr, u8 value)
+static inline void
+WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
 {
-	writereg(cs, HSCX_REG_OFFSET + hscx*HSCX_CH_DIFF, adr, value);
+	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+			HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
+	outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	return readfifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size);
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	writefifo(cs, HSCX_FIFO_OFFSET + hscx*HSCX_CH_DIFF, data, size);
-}
+#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) 
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+#include "hscx_irq.c"
 
 static irqreturn_t
 avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val, sval;
+	u_char val, sval;
+	u_long flags;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
 		if (cs->debug & L1_DEB_INTSTAT)
 			debugl1(cs, "avm IntStatus %x", sval);
 		if (sval & ASL0_R_HSCX) {
-                        val = hscx_read(cs, 1, HSCX_ISTA);
+                        val = ReadHSCX(cs, 1, HSCX_ISTA);
 			if (val)
 				hscx_int_main(cs, val);
 		}
 		if (sval & ASL0_R_ISAC) {
-			val = isac_read(cs, ISAC_ISTA);
+			val = ReadISAC(cs, ISAC_ISTA);
 			if (val)
 				isac_interrupt(cs, val);
 		}
 	}
-	hscx_write(cs, 0, HSCX_MASK, 0xFF);
-	hscx_write(cs, 1, HSCX_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0x0);
-	hscx_write(cs, 0, HSCX_MASK, 0x0);
-	hscx_write(cs, 1, HSCX_MASK, 0x0);
-	spin_unlock(&cs->lock);
+	WriteHSCX(cs, 0, HSCX_MASK, 0xff);
+	WriteHSCX(cs, 1, HSCX_MASK, 0xff);
+	WriteISAC(cs, ISAC_MASK, 0xff);
+	WriteISAC(cs, ISAC_MASK, 0x00);
+	WriteHSCX(cs, 0, HSCX_MASK, 0x00);
+	WriteHSCX(cs, 1, HSCX_MASK, 0x00);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static void
-avm_a1p_init(struct IsdnCardState *cs)
-{
-	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,
-		ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
-	inithscxisac(cs);
-}
-
 static int
-avm_a1p_reset(struct IsdnCardState *cs)
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
-	HZDELAY(HZ / 5 + 1);
-	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
-	HZDELAY(HZ / 5 + 1);
-	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+	u_long flags;
 
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+			HZDELAY(HZ / 5 + 1);
+			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
+			HZDELAY(HZ / 5 + 1);
+			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return 0;
+
+		case CARD_RELEASE:
+			/* free_irq is done in HiSax_closecard(). */
+		        /* free_irq(cs->irq, cs); */
+			return 0;
+
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
+			clear_pending_isac_ints(cs);
+			clear_pending_hscx_ints(cs);
+			inithscxisac(cs, 1);
+			inithscxisac(cs, 2);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return 0;
+
+		case CARD_TEST:
+			/* we really don't need it for the PCMCIA Version */
+			return 0;
+
+		default:
+			/* all card drivers ignore others, so we do the same */
+			return 0;
+	}
 	return 0;
 }
 
-static struct card_ops avm_a1p_ops = {
-	.init     = avm_a1p_init,
-	.reset    = avm_a1p_reset,
-	.irq_func = avm_a1p_interrupt,
-};
-
-static int __init
-avm_a1p_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+int
+setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
-	u8 model, vers;
+	u_char model, vers;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+
+	strcpy(tmp, avm_revision);
+	printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
+						 HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
+		return (0);
 
-	cs->irq = card->para[0];
 	cs->hw.avm.cfg_reg = card->para[1];
+	cs->irq = card->para[0];
 
-	outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
 
+	outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
 	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
 	HZDELAY(HZ / 5 + 1);
 	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
@@ -238,26 +244,25 @@
 	vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
 
 	printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
-	       cs->hw.avm.cfg_reg, cs->irq, model, vers);
-
-	cs->card_ops = &avm_a1p_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-int __devinit
-setup_avm_a1_pcmcia(struct IsdnCard *card)
-{
-	char tmp[64];
+				cs->hw.avm.cfg_reg, cs->irq, model, vers);
 
-	strcpy(tmp, avm_revision);
-	printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-	if (avm_a1p_probe(card->cs, card))
-		return 0;
-	return 1;
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &AVM_card_msg;
+	cs->irq_flags = SA_SHIRQ;
+	cs->irq_func = &avm_a1p_interrupt;
+
+	ISACVersion(cs, "AVM A1 PCMCIA:");
+	if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
+		printk(KERN_WARNING
+		       "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/avm_pci.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/isdn/hisax/avm_pci.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.22.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $
  *
  * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
  *
@@ -22,8 +22,7 @@
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.22.6.6 $";
-static spinlock_t avm_pci_lock = SPIN_LOCK_UNLOCKED;
+static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
 
 #define  AVM_FRITZ_PCI		1
 #define  AVM_FRITZ_PNP		2
@@ -76,137 +75,91 @@
 
 /* Interface functions */
 
-static u8
-ReadISAC(struct IsdnCardState *cs, u8 offset)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
-	u8 val;
-	unsigned long flags;
+	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+	register u_char val;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outb(idx, cs->hw.avm.cfg_reg + 4);
 	val = inb(cs->hw.avm.isac + (offset & 0xf));
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 	return (val);
 }
 
 static void
-WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
-	unsigned long flags;
+	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outb(idx, cs->hw.avm.cfg_reg + 4);
 	outb(value, cs->hw.avm.isac + (offset & 0xf));
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 }
 
 static void
-ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
 	insb(cs->hw.avm.isac, data, size);
 }
 
 static void
-WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
 	outsb(cs->hw.avm.isac, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = ReadISAC,
-	.write_reg  = WriteISAC,
-	.read_fifo  = ReadISACfifo,
-	.write_fifo = WriteISACfifo,
-};
-
 static inline u_int
-ReadHDLCPCI(struct IsdnCardState *cs, int chan, u8 offset)
+ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
 {
-	u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-	u_int val;
-	unsigned long flags;
+	register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+	register u_int val;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outl(idx, cs->hw.avm.cfg_reg + 4);
 	val = inl(cs->hw.avm.isac + offset);
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 	return (val);
 }
 
 static inline void
-WriteHDLCPCI(struct IsdnCardState *cs, int chan, u8 offset, u_int value)
+WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
 {
-	u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-	unsigned long flags;
+	register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outl(idx, cs->hw.avm.cfg_reg + 4);
 	outl(value, cs->hw.avm.isac + offset);
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 }
 
-static inline u8
-ReadHDLCPnP(struct IsdnCardState *cs, int chan, u8 offset)
+static inline u_char
+ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
 {
-	u8 idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-	u8 val;
-	unsigned long flags;
+	register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+	register u_char val;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outb(idx, cs->hw.avm.cfg_reg + 4);
 	val = inb(cs->hw.avm.isac + offset);
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 	return (val);
 }
 
 static inline void
-WriteHDLCPnP(struct IsdnCardState *cs, int chan, u8 offset, u8 value)
+WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
 {
-	u8 idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-	unsigned long flags;
+	register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
 
-	spin_lock_irqsave(&avm_pci_lock, flags);
 	outb(idx, cs->hw.avm.cfg_reg + 4);
 	outb(value, cs->hw.avm.isac + offset);
-	spin_unlock_irqrestore(&avm_pci_lock, flags);
 }
 
-static void
-hdlc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int len)
+static u_char
+ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
 {
-	u8 idx = hscx ? AVM_HDLC_2 : AVM_HDLC_1;
-	int i;
-
-	if (cs->subtyp == AVM_FRITZ_PCI) {
-		u32 *ptr = (u32 *) data;
-
-		outl(idx, cs->hw.avm.cfg_reg + 4);
-		for (i = 0; i < len; i += 4) {
-#ifdef __powerpc__
-#ifdef CONFIG_APUS
-			*ptr++ = in_le32((u32 *)(cs->hw.avm.isac +_IO_BASE));
-#else
-			*ptr++ = in_be32((u32 *)(cs->hw.avm.isac +_IO_BASE));
-#endif /* CONFIG_APUS */
-#else
-			*ptr++ = inl(cs->hw.avm.isac);
-#endif /* __powerpc__ */
-		}
-	} else {
-		outb(idx, cs->hw.avm.cfg_reg + 4);
-		for (i = 0; i < len; i++) {
-			*data++ = inb(cs->hw.avm.isac);
-		}
-	}
+	return(0xff & ReadHDLCPCI(cs, chan, offset));
 }
 
-static struct bc_hw_ops hdlc_hw_ops = {
-	.read_fifo  = hdlc_read_fifo,
-};
+static void
+WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
+{
+	WriteHDLCPCI(cs, chan, offset, value);
+}
 
 static inline
 struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
@@ -273,7 +226,7 @@
 			bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
 			write_ctrl(bcs, 1);
 			bcs->hw.hdlc.ctrl.sr.cmd = 0;
-			sched_b_event(bcs, B_XMTBUFREADY);
+			schedule_event(bcs, B_XMTBUFREADY);
 			break;
 		case (L1_MODE_HDLC):
 			bcs->mode = mode;
@@ -284,7 +237,7 @@
 			bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
 			write_ctrl(bcs, 1);
 			bcs->hw.hdlc.ctrl.sr.cmd = 0;
-			sched_b_event(bcs, B_XMTBUFREADY);
+			schedule_event(bcs, B_XMTBUFREADY);
 			break;
 	}
 }
@@ -292,31 +245,89 @@
 static inline void
 hdlc_empty_fifo(struct BCState *bcs, int count)
 {
-	recv_empty_fifo_b(bcs, count);
+	register u_int *ptr;
+	u_char *p;
+	u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
+	int cnt=0;
+	struct IsdnCardState *cs = bcs->cs;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hdlc_empty_fifo %d", count);
+	if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
+		return;
+	}
+	p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+	ptr = (u_int *)p;
+	bcs->hw.hdlc.rcvidx += count;
+	if (cs->subtyp == AVM_FRITZ_PCI) {
+		outl(idx, cs->hw.avm.cfg_reg + 4);
+		while (cnt < count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			*ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#else
+			*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#endif /* CONFIG_APUS */
+#else
+			*ptr++ = inl(cs->hw.avm.isac);
+#endif /* __powerpc__ */
+			cnt += 4;
+		}
+	} else {
+		outb(idx, cs->hw.avm.cfg_reg + 4);
+		while (cnt < count) {
+			*p++ = inb(cs->hw.avm.isac);
+			cnt++;
+		}
+	}
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		if (cs->subtyp == AVM_FRITZ_PNP)
+			p = (u_char *) ptr;
+		t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
+			     bcs->channel ? 'B' : 'A', count);
+		QuickHex(t, p, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
-static void
+static inline void
 hdlc_fill_fifo(struct BCState *bcs)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int count, more, cnt =0;
+	int count, cnt =0;
 	int fifo_size = 32;
-	unsigned char *p;
-	unsigned int *ptr;
+	u_char *p;
+	u_int *ptr;
 
-	p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more);
-	if (!p)
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hdlc_fill_fifo");
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
 		return;
 
-	if (more)
-		bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
-	else
-		bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
-
+	bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
+	if (bcs->tx_skb->len > fifo_size) {
+		count = fifo_size;
+	} else {
+		count = bcs->tx_skb->len;
+		if (bcs->mode != L1_MODE_TRANS)
+			bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
+	}
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
+	p = bcs->tx_skb->data;
+	ptr = (u_int *)p;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hdlc.count += count;
 	bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
 	write_ctrl(bcs, 3);  /* sets the correct index too */
 	if (cs->subtyp == AVM_FRITZ_PCI) {
-		ptr = (unsigned int *) p;
 		while (cnt<count) {
 #ifdef __powerpc__
 #ifdef CONFIG_APUS
@@ -335,27 +346,25 @@
 			cnt++;
 		}
 	}
-}
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
 
-static void
-reset_xmit(struct BCState *bcs)
-{
-	bcs->hw.hdlc.ctrl.sr.xml = 0;
-	bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
-	write_ctrl(bcs, 1);
-	bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
-	write_ctrl(bcs, 1);
-	hdlc_fill_fifo(bcs);
+		if (cs->subtyp == AVM_FRITZ_PNP)
+			p = (u_char *) ptr;
+		t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
+			     bcs->channel ? 'B' : 'A', count);
+		QuickHex(t, p, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static inline void
-HDLC_irq(struct BCState *bcs, u_int stat)
-{
+HDLC_irq(struct BCState *bcs, u_int stat) {
 	int len;
+	struct sk_buff *skb;
 
 	if (bcs->cs->debug & L1_DEB_HSCX)
 		debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
-
 	if (stat & HDLC_INT_RPR) {
 		if (stat & HDLC_STAT_RDO) {
 			if (bcs->cs->debug & L1_DEB_HSCX)
@@ -367,7 +376,7 @@
 			write_ctrl(bcs, 1);
 			bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
 			write_ctrl(bcs, 1);
-			bcs->rcvidx = 0;
+			bcs->hw.hdlc.rcvidx = 0;
 		} else {
 			if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
 				len = 32;
@@ -375,21 +384,70 @@
 			if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
 				if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
 					(bcs->mode == L1_MODE_TRANS)) {
-					recv_rme_b(bcs);
+					if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
+						printk(KERN_WARNING "HDLC: receive out of memory\n");
+					else {
+						memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx),
+							bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx);
+						skb_queue_tail(&bcs->rqueue, skb);
+					}
+					bcs->hw.hdlc.rcvidx = 0;
+					schedule_event(bcs, B_RCVBUFREADY);
 				} else {
 					if (bcs->cs->debug & L1_DEB_HSCX)
 						debugl1(bcs->cs, "invalid frame");
 					else
 						debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
-					bcs->rcvidx = 0;
+					bcs->hw.hdlc.rcvidx = 0;
 				}
 			}
 		}
 	}
 	if (stat & HDLC_INT_XDU) {
-		xmit_xdu_b(bcs, reset_xmit);
+		/* Here we lost an TX interrupt, so
+		 * restart transmitting the whole frame.
+		 */
+		if (bcs->tx_skb) {
+			skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
+			bcs->tx_cnt += bcs->hw.hdlc.count;
+			bcs->hw.hdlc.count = 0;
+			if (bcs->cs->debug & L1_DEB_WARN)
+				debugl1(bcs->cs, "ch%d XDU", bcs->channel);
+		} else if (bcs->cs->debug & L1_DEB_WARN)
+			debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
+		bcs->hw.hdlc.ctrl.sr.xml = 0;
+		bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
+		write_ctrl(bcs, 1);
+		bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+		write_ctrl(bcs, 1);
+		hdlc_fill_fifo(bcs);
 	} else if (stat & HDLC_INT_XPR) {
-		xmit_xpr_b(bcs);
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				hdlc_fill_fifo(bcs);
+				return;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.hdlc.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_irq(bcs->tx_skb);
+				bcs->hw.hdlc.count = 0;
+				bcs->tx_skb = NULL;
+			}
+		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.hdlc.count = 0;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			hdlc_fill_fifo(bcs);
+		} else {
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
 	}
 }
 
@@ -399,7 +457,6 @@
 	u_int stat;
 	struct BCState *bcs;
 
-	spin_lock(&cs->lock);
 	if (cs->subtyp == AVM_FRITZ_PCI) {
 		stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
 	} else {
@@ -428,37 +485,64 @@
 		} else
 			HDLC_irq(bcs, stat);
 	}
-	spin_unlock(&cs->lock);
 }
 
 void
 hdlc_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->hw.hdlc.count = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
+			} else {
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->hw.hdlc.count = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			modehdlc(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			modehdlc(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			modehdlc(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			modehdlc(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -467,38 +551,69 @@
 close_hdlcstate(struct BCState *bcs)
 {
 	modehdlc(bcs, 0, 0);
-	bc_close(bcs);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hdlc.rcvbuf) {
+			kfree(bcs->hw.hdlc.rcvbuf);
+			bcs->hw.hdlc.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
 }
 
 int
 open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	return bc_open(bcs);
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+			       "HiSax: No memory for hdlc.rcvbuf\n");
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax: No memory for bcs->blog\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hdlc.rcvbuf);
+			bcs->hw.hdlc.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hdlc.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
 }
 
 int
 setstack_hdlc(struct PStack *st, struct BCState *bcs)
 {
 	bcs->channel = st->l1.bc;
-	bcs->unit = bcs->channel;
 	if (open_hdlcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hdlc_l2l1;
+	st->l2.l2l1 = hdlc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
 	return (0);
 }
 
-static struct bc_l1_ops hdlc_l1_ops = {
-	.fill_fifo = hdlc_fill_fifo,
-	.open      = setstack_hdlc,
-	.close     = close_hdlcstate,
-};
-
-static void __init
-inithdlc(struct IsdnCardState *cs)
+void __init
+clear_pending_hdlc_ints(struct IsdnCardState *cs)
 {
 	u_int val;
 
@@ -525,7 +640,15 @@
 		val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
 		debugl1(cs, "HDLC 2 VIN %x", val);
 	}
+}
 
+void __init
+inithdlc(struct IsdnCardState *cs)
+{
+	cs->bcs[0].BC_SetStack = setstack_hdlc;
+	cs->bcs[1].BC_SetStack = setstack_hdlc;
+	cs->bcs[0].BC_Close = close_hdlcstate;
+	cs->bcs[1].BC_Close = close_hdlcstate;
 	modehdlc(cs->bcs, -1, 0);
 	modehdlc(cs->bcs + 1, -1, 1);
 }
@@ -534,13 +657,17 @@
 avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
-	u8 sval;
+	u_long flags;
+	u_char val;
+	u_char sval;
 
+	spin_lock_irqsave(&cs->lock, flags);
 	sval = inb(cs->hw.avm.cfg_reg + 2);
-	if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
+	if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
 		/* possible a shared  IRQ reqest */
+		spin_unlock_irqrestore(&cs->lock, flags);
 		return IRQ_NONE;
+	}
 	if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
 		val = ReadISAC(cs, ISAC_ISTA);
 		isac_interrupt(cs, val);
@@ -550,192 +677,187 @@
 	}
 	WriteISAC(cs, ISAC_MASK, 0xFF);
 	WriteISAC(cs, ISAC_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static int
-avm_pcipnp_reset(struct IsdnCardState *cs)
+static void
+reset_avmpcipnp(struct IsdnCardState *cs)
 {
 	printk(KERN_INFO "AVM PCI/PnP: reset\n");
 	outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+	mdelay(10);
 	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
 	outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+	mdelay(10);
 	printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
-	return 0;
-}
-
-static void
-avm_pcipnp_init(struct IsdnCardState *cs)
-{
-	initisac(cs);
-	inithdlc(cs);
-	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
-	     cs->hw.avm.cfg_reg + 2);
-	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
-	     AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
-}
-
-static void
-avm_pcipnp_release(struct IsdnCardState *cs)
-{
-	outb(0, cs->hw.avm.cfg_reg + 2);
-	hisax_release_resources(cs);
 }
 
-static struct card_ops avm_pci_ops = {
-	.init     = avm_pcipnp_init,
-	.reset    = avm_pcipnp_reset,
-	.release  = avm_pcipnp_release,
-	.irq_func = avm_pcipnp_interrupt,
-};
-
-static int __init
-avm_pcipnp_hw_init(struct IsdnCardState *cs)
-{
-	cs->bc_hw_ops = &hdlc_hw_ops;
-	cs->bc_l1_ops = &hdlc_l1_ops;
-	cs->card_ops = &avm_pci_ops;
-	avm_pcipnp_reset(cs);
-	return isac_setup(cs, &isac_ops);
-}
-
-static int __init
-avm_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	int rc;
-	u32 val;
-
-	printk(KERN_INFO "AVM PCI: defined at %#lx IRQ %u\n",
-	       pci_resource_start(pdev, 1), pdev->irq);
-	
-	rc = -EBUSY;
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->subtyp = AVM_FRITZ_PCI;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.avm.cfg_reg = pci_resource_start(pdev, 1);
-	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
-	if (!request_io(&cs->rs, cs->hw.avm.cfg_reg, 32, "avm PCI"))
-		goto err;
-
-	val = inl(cs->hw.avm.cfg_reg);
-	printk(KERN_INFO "AVM PCI: stat %#x\n", val);
-	printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
-	       val & 0xff, (val>>8) & 0xff);
-
-	if (avm_pcipnp_hw_init(cs))
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
-}
-
-static int __init
-avm_pnp_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	int rc;
-	u8 val, ver;
+	u_long flags;
 
-	printk(KERN_INFO "AVM PnP: defined at %#lx IRQ %lu\n",
-	       card->para[1], card->para[0]);
-
-	cs->subtyp = AVM_FRITZ_PNP;
-	cs->irq = card->para[0];
-	cs->hw.avm.cfg_reg = card->para[1];
-	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
-
-	rc = -EBUSY;
-	if (!request_io(&cs->rs, cs->hw.avm.cfg_reg, 32, "avm PnP"))
-		goto err;
-	
-	val = inb(cs->hw.avm.cfg_reg);
-	ver = inb(cs->hw.avm.cfg_reg + 1);
-	printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
-
-	if (avm_pcipnp_hw_init(cs))
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_avmpcipnp(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			outb(0, cs->hw.avm.cfg_reg + 2);
+			release_region(cs->hw.avm.cfg_reg, 32);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_avmpcipnp(cs);
+			clear_pending_isac_ints(cs);
+			initisac(cs);
+			inithdlc(cs);
+			outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
+				cs->hw.avm.cfg_reg + 2);
+			WriteISAC(cs, ISAC_MASK, 0);
+			outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
+				AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
+			/* RESET Receiver and Transmitter */
+			WriteISAC(cs, ISAC_CMDR, 0x41);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 static struct pci_dev *dev_avm __initdata = NULL;
 #ifdef __ISAPNP__
-static struct pnp_card *card_avm __initdata = NULL;
-static struct pnp_dev *pnp_avm __initdata = NULL;
+static struct pnp_card *pnp_avm_c __initdata = NULL;
 #endif
 
 int __init
 setup_avm_pcipnp(struct IsdnCard *card)
 {
+	u_int val, ver;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, avm_pci_rev);
 	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_FRITZPCI)
+		return (0);
 	if (card->para[1]) {
 		/* old manual method */
-		if (avm_pnp_probe(card->cs, card))
-			return 0;
-		return 1;
+		cs->hw.avm.cfg_reg = card->para[1];
+		cs->irq = card->para[0];
+		cs->subtyp = AVM_FRITZ_PNP;
 	} else {
 #ifdef __ISAPNP__
 		if (isapnp_present()) {
-			struct pnp_card *ba;
-			if ((ba = pnp_find_card(
+			struct pnp_dev *pnp_avm_d = NULL;
+			if ((pnp_avm_c = pnp_find_card(
 				ISAPNP_VENDOR('A', 'V', 'M'),
-				ISAPNP_FUNCTION(0x0900), card_avm))) {
-				card_avm = ba;
-				pnp_avm = NULL;
-				if ((pnp_avm = pnp_find_dev(card_avm,
+				ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+				if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
 					ISAPNP_VENDOR('A', 'V', 'M'),
-					ISAPNP_FUNCTION(0x0900), pnp_avm))) {
-					if (pnp_device_attach(pnp_avm) < 0) {
-						printk(KERN_ERR "FritzPnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pnp_avm) < 0) {
-						printk(KERN_ERR "FritzPnP: activate failed\n");
-						pnp_device_detach(pnp_avm);
-						return 0;
+					ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+					int err;
+
+					pnp_disable_dev(pnp_avm_d);
+					err = pnp_activate_dev(pnp_avm_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_irq_valid(pnp_avm, 0)) {
+					cs->hw.avm.cfg_reg =
+						pnp_port_start(pnp_avm_d, 0);
+					cs->irq = pnp_irq(pnp_avm_d, 0);
+					if (!cs->irq) {
 						printk(KERN_ERR "FritzPnP:No IRQ\n");
-						pnp_device_detach(pnp_avm);
 						return(0);
 					}
-					if (!pnp_port_valid(pnp_avm, 0)) {
+					if (!cs->hw.avm.cfg_reg) {
 						printk(KERN_ERR "FritzPnP:No IO address\n");
-						pnp_device_detach(pnp_avm);
 						return(0);
 					}
-					card->para[1] = pnp_port_start(pnp_avm, 0);
-					card->para[0] = pnp_irq(pnp_avm, 0);
-					if (avm_pnp_probe(card->cs, card))
-						return 0;
-					return 1;
+					cs->subtyp = AVM_FRITZ_PNP;
+					goto ready;
 				}
 			}
+		} else {
+			printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
 		}
 #endif
-#ifdef CONFIG_PCI
+#if CONFIG_PCI
 		if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
 			PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
-			if (avm_pci_probe(card->cs, dev_avm))
-				return 0;
-			return 1;
+			cs->irq = dev_avm->irq;
+			if (!cs->irq) {
+				printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+				return(0);
+			}
+			if (pci_enable_device(dev_avm))
+				return(0);
+			cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+			if (!cs->hw.avm.cfg_reg) {
+				printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+			cs->subtyp = AVM_FRITZ_PCI;
+		} else {
+			printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+			return(0);
 		}
+		cs->irq_flags |= SA_SHIRQ;
+#else
+		printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
+		return (0);
 #endif /* CONFIG_PCI */
 	}
-	printk(KERN_WARNING "FritzPCI: No card found\n");
-	return 0;
+ready:
+	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
+	if (!request_region(cs->hw.avm.cfg_reg, 32,
+		(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.avm.cfg_reg,
+		       cs->hw.avm.cfg_reg + 31);
+		return (0);
+	}
+	switch (cs->subtyp) {
+	  case AVM_FRITZ_PCI:
+		val = inl(cs->hw.avm.cfg_reg);
+		printk(KERN_INFO "AVM PCI: stat %#x\n", val);
+		printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
+			val & 0xff, (val>>8) & 0xff);
+		cs->BC_Read_Reg = &ReadHDLC_s;
+		cs->BC_Write_Reg = &WriteHDLC_s;
+		break;
+	  case AVM_FRITZ_PNP:
+		val = inb(cs->hw.avm.cfg_reg);
+		ver = inb(cs->hw.avm.cfg_reg + 1);
+		printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
+		cs->BC_Read_Reg = &ReadHDLCPnP;
+		cs->BC_Write_Reg = &WriteHDLCPnP;
+		break;
+	  default:
+	  	printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
+	  	return(0);
+	}
+	printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
+		(cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
+		cs->irq, cs->hw.avm.cfg_reg);
+
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Send_Data = &hdlc_fill_fifo;
+	cs->cardmsg = &AVM_card_msg;
+	cs->irq_func = &avm_pcipnp_interrupt;
+	cs->writeisac(cs, ISAC_MASK, 0xFF);
+	ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
+	return (1);
 }
--- diff/drivers/isdn/hisax/avma1_cs.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/hisax/avma1_cs.c	2004-02-18 09:03:59.000000000 +0000
@@ -26,15 +26,12 @@
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
+#include "hisax_cfg.h"
 
 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
-int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot);
-void HiSax_closecard(int cardnr);
-
-
 /*
    All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
    you do not define PCMCIA_DEBUG at all, all the debug code will be
@@ -156,6 +153,15 @@
 	return NULL;
     memset(link, 0, sizeof(struct dev_link_t));
 
+    /* Allocate space for private device-specific data */
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local) {
+	kfree(link);
+	return NULL;
+    }
+    memset(local, 0, sizeof(local_info_t));
+    link->priv = local;
+
     /* The io structure describes IO port mapping */
     link->io.NumPorts1 = 16;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -183,15 +189,6 @@
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
 
-    /* Allocate space for private device-specific data */
-    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
-    if (!local) {
-	kfree(link);
-	return NULL;
-    }
-    memset(local, 0, sizeof(local_info_t));
-    link->priv = local;
-    
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -252,7 +249,7 @@
 
     /* Break the link with Card Services */
     if (link->handle)
-	pcmcia_deregister_client(link->handle);
+    	pcmcia_deregister_client(link->handle);
     
     /* Unlink device structure, free pieces */
     *linkp = link->next;
@@ -303,8 +300,9 @@
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
     local_info_t *dev;
     int i;
-    u8 buf[64];
+    u_char buf[64];
     char devname[128];
+    IsdnCard_t	icard;
     int busy = 0;
     
     handle = link->handle;
@@ -365,9 +363,9 @@
 		link->io.BasePort1 = cf->io.win[0].base;
 		link->io.NumPorts1 = cf->io.win[0].len;
 		link->io.NumPorts2 = 0;
-                printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
+		printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
 			link->io.BasePort1,
-		        link->io.BasePort1+link->io.NumPorts1 - 1);
+			link->io.BasePort1+link->io.NumPorts1 - 1);
 		i = pcmcia_request_io(link->handle, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
@@ -391,8 +389,8 @@
 	}
 	
 	/*
-         * configure the PCMCIA socket
-	  */
+	 * configure the PCMCIA socket
+	 */
 	i = pcmcia_request_configuration(link->handle, &link->conf);
 	if (i != CS_SUCCESS) {
 	    cs_error(link->handle, RequestConfiguration, i);
@@ -421,15 +419,17 @@
     printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
 				link->io.BasePort1, link->irq.AssignedIRQ);
 
-    if (avm_a1_init_pcmcia((void *)(int)link->io.BasePort1,
-                           link->irq.AssignedIRQ,
-                           &busy, isdnprot) != 0) {
-       printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
-       return;
+    icard.para[0] = link->irq.AssignedIRQ;
+    icard.para[1] = link->io.BasePort1;
+    icard.protocol = isdnprot;
+    icard.typ = ISDN_CTYPE_A1_PCMCIA;
+    
+    i = hisax_init_pcmcia(link, &busy, &icard);
+    if (i < 0) {
+    	printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
+	avma1cs_release(link);
+	return;
     }
-
-    i = 0; /* no returncode for cardnr :-( */
-
     dev->node.minor = i;
 
 } /* avma1cs_config */
@@ -486,29 +486,28 @@
     DEBUG(1, "avma1cs_event(0x%06x)\n", event);
     
     switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
+	case CS_EVENT_CARD_REMOVAL:
+	    if (link->state & DEV_CONFIG)
 		avma1cs_release(link);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	avma1cs_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG)
-	    pcmcia_release_configuration(link->handle);
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (link->state & DEV_CONFIG)
-	    pcmcia_request_configuration(link->handle, &link->conf);
-	break;
+	    break;
+	case CS_EVENT_CARD_INSERTION:
+	    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	    avma1cs_config(link);
+	    break;
+	case CS_EVENT_PM_SUSPEND:
+	    link->state |= DEV_SUSPEND;
+	    /* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+	    if (link->state & DEV_CONFIG)
+		pcmcia_release_configuration(link->handle);
+	    break;
+	case CS_EVENT_PM_RESUME:
+	    link->state &= ~DEV_SUSPEND;
+	    /* Fall through... */
+	case CS_EVENT_CARD_RESET:
+ 	    if (link->state & DEV_CONFIG)
+		pcmcia_request_configuration(link->handle, &link->conf);
+	    break;
     }
     return 0;
 } /* avma1cs_event */
@@ -521,10 +520,12 @@
 	.attach		= avma1cs_attach,
 	.detach		= avma1cs_detach,
 };
+ 
+/*====================================================================*/
 
 static int __init init_avma1_cs(void)
 {
-	return pcmcia_register_driver(&avma1cs_driver);
+	return(pcmcia_register_driver(&avma1cs_driver));
 }
 
 static void __exit exit_avma1_cs(void)
--- diff/drivers/isdn/hisax/bkm_a4t.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/bkm_a4t.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.13.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
  *
  * low level stuff for T-Berkom A4T
  *
@@ -10,6 +10,7 @@
  *
  */
 
+
 #include <linux/config.h>
 #include <linux/init.h>
 #include "hisax.h"
@@ -21,51 +22,47 @@
 #include "bkm_ax.h"
 
 extern const char *CardType[];
-// FIXME needs per card lock
-static spinlock_t bkm_a4t_lock = SPIN_LOCK_UNLOCKED;
 
-const char *bkm_a4t_revision = "$Revision: 1.13.6.6 $";
+const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
+
 
-static inline u8
-readreg(unsigned int ale, unsigned long adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned long adr, u_char off)
 {
-	u_int ret;
-	unsigned long flags;
+	register u_int ret;
 	unsigned int *po = (unsigned int *) adr;	/* Postoffice */
-	spin_lock_irqsave(&bkm_a4t_lock, flags);
+
 	*po = (GCS_2 | PO_WRITE | off);
 	__WAITI20__(po);
 	*po = (ale | PO_READ);
 	__WAITI20__(po);
 	ret = *po;
-	spin_unlock_irqrestore(&bkm_a4t_lock, flags);
 	return ((unsigned char) ret);
 }
 
+
 static inline void
-writereg(unsigned int ale, unsigned long adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
+{
+	int i;
+	for (i = 0; i < size; i++)
+		*data++ = readreg(ale, adr, off);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
 {
-	unsigned long flags;
 	unsigned int *po = (unsigned int *) adr;	/* Postoffice */
-	spin_lock_irqsave(&bkm_a4t_lock, flags);
 	*po = (GCS_2 | PO_WRITE | off);
 	__WAITI20__(po);
 	*po = (ale | PO_WRITE | data);
 	__WAITI20__(po);
-	spin_unlock_irqrestore(&bkm_a4t_lock, flags);
 }
 
-static inline void
-readfifo(unsigned int ale, unsigned long adr, u8 off, u8 * data, int size)
-{
-	int i;
-
-	for (i = 0; i < size; i++)
-		*data++ = readreg(ale, adr, off);
-}
 
 static inline void
-writefifo(unsigned int ale, unsigned long adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
 {
 	int i;
 
@@ -73,84 +70,74 @@
 		writereg(ale, adr, off, *data++);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
 	return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-jade_read(struct IsdnCardState *cs, int jade, u8 offset)
+static u_char
+ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
 {
-	return readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)));
+	return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
 }
 
 static void
-jade_write(struct IsdnCardState *cs, int jade, u8 offset, u8 value)
+WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
 {
 	writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
 }
 
-static void
-jade_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	readfifo(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr,
-		 (hscx == -1 ? 0 : (hscx ? 0xc0 : 0x80)), data, size);
-}
+/*
+ * fast interrupt JADE stuff goes here
+ */
 
-static void
-jade_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	writefifo(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr,
-		  (hscx == -1 ? 0 : (hscx ? 0xc0 : 0x80)), data, size);
-}
+#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
+ 		cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
+#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
+ 		cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
+
+#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
+		cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
+#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
+		cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
 
-static struct bc_hw_ops jade_ops = {
-	.read_reg   = jade_read,
-	.write_reg  = jade_write,
-	.read_fifo  = jade_read_fifo,
-	.write_fifo = jade_write_fifo,
-};
+#include "jade_irq.c"
 
 static irqreturn_t
 bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val = 0;
+	u_char val = 0;
+	u_long flags;
 	I20_REGISTER_FILE *pI20_Regs;
-	int handled = 0;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
 
 	/* ISDN interrupt pending? */
 	if (pI20_Regs->i20IntStatus & intISDN) {
-		handled = 1;
 		/* Reset the ISDN interrupt     */
 		pI20_Regs->i20IntStatus = intISDN;
 		/* Disable ISDN interrupt */
@@ -172,129 +159,101 @@
 		}
 		/* Reenable ISDN interrupt */
 		pI20_Regs->i20IntCtrl |= intISDN;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_HANDLED;
+	} else {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
 	}
-	spin_unlock(&cs->lock);
-	return IRQ_RETVAL(handled);
 }
 
-static void
-enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
+void
+release_io_bkm(struct IsdnCardState *cs)
 {
-	I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
-	if (bEnable)
-		pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
-	else
-		/* CAUTION: This disables the video capture driver too */
-		pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
+	if (cs->hw.ax.base) {
+		iounmap((void *) cs->hw.ax.base);
+		cs->hw.ax.base = 0;
+	}
 }
 
 static void
-reset_bkm(struct IsdnCardState *cs)
+enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
 {
-	I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
-	/* Issue the I20 soft reset     */
-	pI20_Regs->i20SysControl = 0xFF;	/* all in */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10 * HZ) / 1000);
-	/* Remove the soft reset */
-	pI20_Regs->i20SysControl = sysRESET | 0xFF;
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10 * HZ) / 1000);
-	/* Set our configuration */
-	pI20_Regs->i20SysControl = sysRESET | sysCFG;
-	/* Issue ISDN reset     */
-	pI20_Regs->i20GuestControl = guestWAIT_CFG |
-		g_A4T_JADE_RES |
-		g_A4T_ISAR_RES |
-		g_A4T_ISAC_RES |
-		g_A4T_JADE_BOOTR |
-		g_A4T_ISAR_BOOTR;
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10 * HZ) / 1000);
-
-	/* Remove RESET state from ISDN */
-	pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
-					g_A4T_JADE_RES |
-					g_A4T_ISAR_RES);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10 * HZ) / 1000);
+	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+		I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+		if (bEnable)
+			pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
+		else
+			/* CAUTION: This disables the video capture driver too */
+			pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
+	}
 }
 
 static void
-bkm_a4t_init(struct IsdnCardState *cs)
+reset_bkm(struct IsdnCardState *cs)
 {
-	initisac(cs);
-	initjade(cs);
-	/* Enable ints */
-	enable_bkm_int(cs, 1);
+	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+		I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+		/* Issue the I20 soft reset     */
+		pI20_Regs->i20SysControl = 0xFF;	/* all in */
+		mdelay(10);
+		/* Remove the soft reset */
+		pI20_Regs->i20SysControl = sysRESET | 0xFF;
+		mdelay(10);
+		/* Set our configuration */
+		pI20_Regs->i20SysControl = sysRESET | sysCFG;
+		/* Issue ISDN reset     */
+		pI20_Regs->i20GuestControl = guestWAIT_CFG |
+		    g_A4T_JADE_RES |
+		    g_A4T_ISAR_RES |
+		    g_A4T_ISAC_RES |
+		    g_A4T_JADE_BOOTR |
+		    g_A4T_ISAR_BOOTR;
+		mdelay(10);
+
+		/* Remove RESET state from ISDN */
+		pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
+						g_A4T_JADE_RES |
+						g_A4T_ISAR_RES);
+		mdelay(10);
+	}
 }
 
 static int
-bkm_a4t_reset(struct IsdnCardState *cs)
+BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	/* Disable ints */
-	enable_bkm_int(cs, 0);
-	reset_bkm(cs);
-	return 0;
-}
-
-static void
-bkm_a4t_release(struct IsdnCardState *cs)
-{
-	reset_bkm(cs);
-	hisax_release_resources(cs);
-}
-
-static struct card_ops bkm_a4t_ops = {
-	.init     = bkm_a4t_init,
-	.reset    = bkm_a4t_reset,
-	.release  = bkm_a4t_release,
-	.irq_func = bkm_interrupt,
-};
+	u_long flags;
 
-static int __init
-bkm_a4t_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	I20_REGISTER_FILE *pI20_Regs;
-	int rc;
-
-	printk(KERN_INFO "BKM A4T: defined at %#lx IRQ %u\n",
-	       pci_resource_start(pdev, 0), pdev->irq);
-	
-	rc = -EBUSY;
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.avm.cfg_reg = pci_resource_start(pdev, 1);
-
-	cs->hw.ax.base = (unsigned long)request_mmio(&cs->rs, pci_resource_start(pdev, 0), 4096, "Telekom A4T");
-	if (!cs->hw.ax.base)
-		goto err;
-	
-	/* Check suspicious address */
-	// FIXME needs to use read[bl]
-	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
-	if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
-		printk(KERN_WARNING "HiSax: address %lx suspicious\n",
-		       cs->hw.ax.base);
-		goto err;
+	switch (mt) {
+		case CARD_RESET:
+			/* Disable ints */
+			spin_lock_irqsave(&cs->lock, flags);
+			enable_bkm_int(cs, 0);
+			reset_bkm(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_RELEASE:
+			/* Sanity */
+			spin_lock_irqsave(&cs->lock, flags);
+			enable_bkm_int(cs, 0);
+			reset_bkm(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			release_io_bkm(cs);
+			return (0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			clear_pending_isac_ints(cs);
+			clear_pending_jade_ints(cs);
+			initisac(cs);
+			initjade(cs);
+			/* Enable ints */
+			enable_bkm_int(cs, 1);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
 	}
-	cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
-	cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
-	cs->hw.ax.isac_ale = GCS_1;
-	cs->hw.ax.jade_ale = GCS_3;
-
-	reset_bkm(cs);
-	cs->card_ops = &bkm_a4t_ops;
-	isac_setup(cs, &isac_ops);
-	jade_setup(cs, &jade_ops);
-	return 0;
-
- err:
-	hisax_release_resources(cs);
-	return rc;
+	return (0);
 }
 
 static struct pci_dev *dev_a4t __initdata = NULL;
@@ -302,10 +261,21 @@
 int __init
 setup_bkm_a4t(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
+	u_int pci_memaddr = 0, found = 0;
+	I20_REGISTER_FILE *pI20_Regs;
+#if CONFIG_PCI
+#endif
 
 	strcpy(tmp, bkm_a4t_revision);
 	printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+		cs->subtyp = BKM_A4T;
+	} else
+		return (0);
+
+#if CONFIG_PCI
 	while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
 		PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
 		u16 sub_sys;
@@ -313,13 +283,62 @@
 
 		sub_vendor = dev_a4t->subsystem_vendor;
 		sub_sys = dev_a4t->subsystem_device;
-		if (sub_sys == PCI_DEVICE_ID_BERKOM_A4T && 
-		    sub_vendor == PCI_VENDOR_ID_BERKOM) {
-			if (bkm_a4t_probe(card->cs, dev_a4t))
-				return 0;
-			return 1;
+		if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
+			if (pci_enable_device(dev_a4t))
+				return(0);
+			found = 1;
+			pci_memaddr = pci_resource_start(dev_a4t, 0);
+			cs->irq = dev_a4t->irq;
+			break;
 		}
 	}
-	printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
-	return 0;
+	if (!found) {
+		printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
+		return (0);
+	}
+	if (!cs->irq) {		/* IRQ range check ?? */
+		printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
+		return (0);
+	}
+	if (!pci_memaddr) {
+		printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
+		return (0);
+	}
+	cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
+	/* Check suspecious address */
+	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+	if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
+		printk(KERN_WARNING "HiSax: %s address %lx-%lx suspecious\n",
+		       CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096);
+		iounmap((void *) cs->hw.ax.base);
+		cs->hw.ax.base = 0;
+		return (0);
+	}
+	cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
+	cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
+	cs->hw.ax.isac_ale = GCS_1;
+	cs->hw.ax.jade_ale = GCS_3;
+#else
+	printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
+	printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
+	return (0);
+#endif				/* CONFIG_PCI */
+	printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n",
+	       CardType[card->typ], cs->hw.ax.base, cs->irq);
+
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadJADE;
+	cs->BC_Write_Reg = &WriteJADE;
+	cs->BC_Send_Data = &jade_fill_fifo;
+	cs->cardmsg = &BKM_card_msg;
+	cs->irq_func = &bkm_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ISACVersion(cs, "Telekom A4T:");
+	/* Jade version */
+	JadeVersion(cs, "Telekom A4T:");
+	return (1);
 }
--- diff/drivers/isdn/hisax/bkm_a8.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/bkm_a8.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.14.6.7 2001/09/23 22:24:46 kai Exp $
+/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
  *
  * low level stuff for Scitel Quadro (4*S0, passive)
  *
@@ -10,6 +10,7 @@
  *
  */
 
+
 #include <linux/config.h>
 #include <linux/init.h>
 #include "hisax.h"
@@ -20,11 +21,13 @@
 #include <linux/pci.h>
 #include "bkm_ax.h"
 
+#if CONFIG_PCI
+
 #define	ATTEMPT_PCI_REMAPPING	/* Required for PLX rev 1 */
 
 extern const char *CardType[];
-static spinlock_t bkm_a8_lock = SPIN_LOCK_UNLOCKED;
-const char sct_quadro_revision[] = "$Revision: 1.14.6.7 $";
+
+const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
 
 static const char *sct_quadro_subtypes[] =
 {
@@ -39,70 +42,174 @@
 #define wordout(addr,val) outw(val,addr)
 #define wordin(addr) inw(addr)
 
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&bkm_a8_lock, flags);
-	wordout(cs->hw.ax.base, off);
-	ret = wordin(cs->hw.ax.data_adr) & 0xFF;
-	spin_unlock_irqrestore(&bkm_a8_lock, flags);
-	return ret;
+	register u_char ret;
+	wordout(ale, off);
+	ret = wordin(adr) & 0xFF;
+	return (ret);
 }
 
 static inline void
-ipac_write(struct IsdnCardState *cs, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
+	int i;
+	wordout(ale, off);
+	for (i = 0; i < size; i++)
+		data[i] = wordin(adr) & 0xFF;
+}
 
-	spin_lock_irqsave(&bkm_a8_lock, flags);
-	wordout(cs->hw.ax.base, off);
-	wordout(cs->hw.ax.data_adr, data);
-	spin_unlock_irqrestore(&bkm_a8_lock, flags);
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+	wordout(ale, off);
+	wordout(adr, data);
 }
 
 static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 *data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
 	int i;
-
-	wordout(cs->hw.ax.base, off);
+	wordout(ale, off);
 	for (i = 0; i < size; i++)
-		data[i] = wordin(cs->hw.ax.data_adr) & 0xFF;
+		wordout(adr, data[i]);
 }
 
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 *data, int size)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	int i;
+	return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
+}
 
-	wordout(cs->hw.ax.base, off);
-	for (i = 0; i < size; i++)
-		wordout(cs->hw.ax.data_adr, data[i]);
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
 }
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
 
-BUILD_IPAC_OPS(ipac);
-  
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
+}
+
 /* Set the specific ipac to active */
 static void
 set_ipac_active(struct IsdnCardState *cs, u_int active)
 {
 	/* set irq mask */
-	ipac_write(cs, IPAC_MASK, active ? 0xc0 : 0xff);
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
+		active ? 0xc0 : 0xff);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
+	cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
+	cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
+	cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
+	cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char ista, val, icnt = 5;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
+	if (!(ista & 0x3f)) { /* not this IPAC */
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
+	}
+      Start_IPAC:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val) {
+			hscx_int_main(cs, val);
+		}
+	}
+	if (ista & 0x20) {
+		val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPAC;
+	}
+	if (!icnt)
+		printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n",
+		       CardType[cs->typ],
+		       sct_quadro_subtypes[cs->subtyp]);
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+void
+release_io_sct_quadro(struct IsdnCardState *cs)
+{
+	release_region(cs->hw.ax.base & 0xffffffc0, 128);
+	if (cs->subtyp == SCT_1)
+		release_region(cs->hw.ax.plx_adr, 64);
 }
 
 static void
 enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
 {
-	if (bEnable)
-		wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
-	else
-		wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
+	if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
+		if (bEnable)
+			wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
+		else
+			wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
+	}
 }
 
 static void
@@ -110,66 +217,88 @@
 {
 	if (cs->subtyp == SCT_1) {
 		wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((10 * HZ) / 1000);
+		mdelay(10);
 		/* Remove the soft reset */
 		wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((10 * HZ) / 1000);
+		mdelay(10);
 	}
 }
 
-static void
-bkm_a8_init(struct IsdnCardState *cs)
-{
-	cs->debug |= L1_DEB_IPAC;
-	set_ipac_active(cs, 1);
-	ipac_init(cs);
-	/* Enable ints */
-	enable_bkm_int(cs, 1);
-}
-
 static int
-bkm_a8_reset(struct IsdnCardState *cs)
+BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	/* Disable ints */
-	set_ipac_active(cs, 0);
-	enable_bkm_int(cs, 0);
-	reset_bkm(cs);
-	return 0;
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			/* Disable ints */
+			set_ipac_active(cs, 0);
+			enable_bkm_int(cs, 0);
+			reset_bkm(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_RELEASE:
+			/* Sanity */
+			spin_lock_irqsave(&cs->lock, flags);
+			set_ipac_active(cs, 0);
+			enable_bkm_int(cs, 0);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			release_io_sct_quadro(cs);
+			return (0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->debug |= L1_DEB_IPAC;
+			set_ipac_active(cs, 1);
+			inithscxisac(cs, 3);
+			/* Enable ints */
+			enable_bkm_int(cs, 1);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
+	}
+	return (0);
 }
 
-static void
-bkm_a8_release(struct IsdnCardState *cs)
+int __init
+sct_alloc_io(u_int adr, u_int len)
 {
-	set_ipac_active(cs, 0);
-	enable_bkm_int(cs, 0);
-	hisax_release_resources(cs);
+	if (!request_region(adr, len, "scitel")) {
+		printk(KERN_WARNING
+			"HiSax: Scitel port %#x-%#x already in use\n",
+			adr, adr + len);
+		return (1);
+	}
+	return(0);
 }
 
-static struct card_ops bkm_a8_ops = {
-	.init     = bkm_a8_init,
-	.reset    = bkm_a8_reset,
-	.release  = bkm_a8_release,
-	.irq_func = ipac_irq,
-};
-
 static struct pci_dev *dev_a8 __initdata = NULL;
 static u16  sub_vendor_id __initdata = 0;
 static u16  sub_sys_id __initdata = 0;
-static u8 pci_irq __initdata = 0;
+static u_char pci_bus __initdata = 0;
+static u_char pci_device_fn __initdata = 0;
+static u_char pci_irq __initdata = 0;
+
+#endif /* CONFIG_PCI */
 
 int __init
 setup_sct_quadro(struct IsdnCard *card)
 {
+#if CONFIG_PCI
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
-	u8 pci_rev_id;
+	u_char pci_rev_id;
 	u_int found = 0;
 	u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
 
 	strcpy(tmp, sct_quadro_revision);
 	printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
+		cs->subtyp = SCT_1;	/* Preset */
+	} else
+		return (0);
+
 	/* Identify subtype by para[0] */
 	if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
 		cs->subtyp = card->para[0];
@@ -193,6 +322,8 @@
 					return(0);
 				pci_ioaddr1 = pci_resource_start(dev_a8, 1);
 				pci_irq = dev_a8->irq;
+				pci_bus = dev_a8->bus->number;
+				pci_device_fn = dev_a8->devfn;
 				found = 1;
 				break;
 			}
@@ -253,31 +384,40 @@
 	cs->hw.ax.plx_adr = pci_ioaddr1;
 	/* Enter all ipac_base addresses */
 	switch(cs->subtyp) {
-	case 1:
-		cs->hw.ax.base = pci_ioaddr5 + 0x00;
-		if (!request_io(&cs->rs, pci_ioaddr1, 128, "scitel"))
-			goto err;
-		if (!request_io(&cs->rs, pci_ioaddr5, 64, "scitel"))
-			goto err;
-		break;
-	case 2:
-		cs->hw.ax.base = pci_ioaddr4 + 0x08;
-		if (!request_io(&cs->rs, pci_ioaddr4, 64, "scitel"))
-			goto err;
-		break;
-	case 3:
-		cs->hw.ax.base = pci_ioaddr3 + 0x10;
-		if (!request_io(&cs->rs, pci_ioaddr3, 64, "scitel"))
-			goto err;
-		break;
-	case 4:
-		cs->hw.ax.base = pci_ioaddr2 + 0x20;
-		if (!request_io(&cs->rs, pci_ioaddr2, 64, "scitel"))
-			goto err;
-		break;
+		case 1:
+			cs->hw.ax.base = pci_ioaddr5 + 0x00;
+			if (sct_alloc_io(pci_ioaddr1, 128))
+				return(0);
+			if (sct_alloc_io(pci_ioaddr5, 64))
+				return(0);
+			/* disable all IPAC */
+			writereg(pci_ioaddr5, pci_ioaddr5 + 4,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
+				IPAC_MASK, 0xFF);
+			break;
+		case 2:
+			cs->hw.ax.base = pci_ioaddr4 + 0x08;
+			if (sct_alloc_io(pci_ioaddr4, 64))
+				return(0);
+			break;
+		case 3:
+			cs->hw.ax.base = pci_ioaddr3 + 0x10;
+			if (sct_alloc_io(pci_ioaddr3, 64))
+				return(0);
+			break;
+		case 4:
+			cs->hw.ax.base = pci_ioaddr2 + 0x20;
+			if (sct_alloc_io(pci_ioaddr2, 64))
+				return(0);
+			break;
 	}	
+	/* For isac and hscx data path */
 	cs->hw.ax.data_adr = cs->hw.ax.base + 4;
-	ipac_write(cs, IPAC_MASK, 0xFF);
 
 	printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
 	       CardType[card->typ],
@@ -287,12 +427,25 @@
 	       cs->hw.ax.data_adr,
 	       cs->irq);
 
-	cs->card_ops = &bkm_a8_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		goto err;
-
-	return 1;
- err:
-	hisax_release_resources(cs);
-	return 0;
+	test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &BKM_card_msg;
+	cs->irq_func = &bkm_interrupt_ipac;
+
+	printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n",
+		CardType[card->typ],
+		sct_quadro_subtypes[cs->subtyp],
+		readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
+	return (1);
+#else
+	printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
+#endif /* CONFIG_PCI */
 }
--- diff/drivers/isdn/hisax/callc.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/callc.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.51.6.6 2001/09/23 22:24:46 kai Exp $
+/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
@@ -21,8 +21,7 @@
 #include "hisax.h"
 #include <linux/isdn/capicmd.h>
 
-
-const char *lli_revision = "$Revision: 2.51.6.6 $";
+const char *lli_revision = "$Revision: 2.59.2.4 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -32,7 +31,6 @@
 
 static struct Fsm callcfsm;
 static int chancount;
-static spinlock_t callc_lock = SPIN_LOCK_UNLOCKED;
 
 /* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
 #define ALERT_REJECT 0
@@ -205,49 +203,13 @@
 }
 
 static inline void
-mdl_info_setup(struct Channel *chanp)
-{
-	if (chanp->chan)
-		chanp->cs->status |=  0x0200;
-	else
-		chanp->cs->status |=  0x0100;
-
-	if (chanp->cs->card_ops->led_handler)
-		chanp->cs->card_ops->led_handler(chanp->cs);
-}
-
-static inline void
-mdl_info_connect(struct Channel *chanp)
-{
-	if (chanp->chan)
-		chanp->cs->status |=  0x2000;
-	else
-		chanp->cs->status |=  0x1000;
-
-	if (chanp->cs->card_ops->led_handler)
-		chanp->cs->card_ops->led_handler(chanp->cs);
-}
-
-static inline void
-mdl_info_release(struct Channel *chanp)
-{
-	if (chanp->chan)
-		chanp->cs->status &=  ~0x2200;
-	else
-		chanp->cs->status &=  ~0x1100;
-
-	if (chanp->cs->card_ops->led_handler)
-		chanp->cs->card_ops->led_handler(chanp->cs);
-}
-
-static void
 lli_close(struct FsmInst *fi)
 {
 	struct Channel *chanp = fi->userdata;
 
 	FsmChangeState(fi, ST_NULL);
 	chanp->Flags = 0;
-	mdl_info_release(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 }
 
 static void
@@ -259,8 +221,7 @@
 
 	if (!chanp->leased)
 		return;
-
-	mdl_info_setup(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
 	FsmChangeState(fi, ST_IN_WAIT_LL);
 	if (chanp->debug & 1)
 		link_debug(chanp, 0, "STAT_ICALL_LEASED");
@@ -277,11 +238,12 @@
 	if (chanp->debug & 1)
 		link_debug(chanp, 1, "statcallb ret=%d", ret);
 	if (!ret) {
-		mdl_info_release(chanp);
+		chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 		FsmChangeState(fi, ST_NULL);
 	}
 }
 
+
 /*
  * Dial out
  */
@@ -295,7 +257,7 @@
 		link_debug(chanp, 0, "STAT_DCONN");
 	HL_LL(chanp, ISDN_STAT_DCONN);
 	init_b_st(chanp, 0);
-	L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -307,12 +269,12 @@
 	FsmDelTimer(&chanp->dial_timer, 73);
 	chanp->l2_active_protocol = chanp->l2_protocol;
 	chanp->incoming = 0;
-	mdl_info_setup(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
 	if (chanp->leased) {
 		lli_init_bchan_out(fi, event, arg);
 	} else {
 		FsmChangeState(fi, ST_OUT_DIAL);
-		L4L3(chanp->d_st, CC_SETUP | REQUEST, chanp);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
 	}
 }
 
@@ -325,12 +287,12 @@
 	FsmDelTimer(&chanp->dial_timer, 73);
 	chanp->l2_active_protocol = chanp->l2_protocol;
 	chanp->incoming = 0;
-	mdl_info_setup(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
 	if (chanp->leased) {
 		lli_init_bchan_out(fi, event, arg);
 	} else {
 		FsmChangeState(fi, ST_OUT_DIAL);
-		L4L3(chanp->d_st, CC_RESUME | REQUEST, chanp);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
 	}
 }
 
@@ -353,7 +315,7 @@
 	ic.command = ISDN_STAT_BCONN;
 	ic.arg = chanp->chan;
 	chanp->cs->iif.statcallb(&ic);
-	mdl_info_connect(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);
 }
 
 
@@ -370,7 +332,7 @@
 	isdn_ctrl ic;
 	int ret;
 
-	mdl_info_setup(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
 	/*
 	 * Report incoming calls only once to linklevel, use CallFlags
 	 * which is set to 3 with each broadcast message in isdnl1.c
@@ -397,34 +359,34 @@
 			case 1:	/* OK, someone likes this call */
 				FsmDelTimer(&chanp->drel_timer, 61);
 				FsmChangeState(fi, ST_IN_ALERT_SENT);
-				L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+				chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 				break;
 			case 5: /* direct redirect */
 			case 4: /* Proceeding desired */
 				FsmDelTimer(&chanp->drel_timer, 61);
 				FsmChangeState(fi, ST_IN_PROCEED_SEND);
-				L4L3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
+				chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
 				if (ret == 5) {
 					memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
-					L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+					chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
 				}
 				break;
 			case 2:	/* Rejecting Call */
 				break;
 			case 3:	/* incomplete number */
 				FsmDelTimer(&chanp->drel_timer, 61);
-				L4L3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
+				chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
 				break;
 			case 0:	/* OK, nobody likes this call */
 			default:	/* statcallb problems */
-				L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
-				mdl_info_release(chanp);
+				chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+				chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 				FsmChangeState(fi, ST_NULL);
 				break;
 		}
 	} else {
-		L4L3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
-		mdl_info_release(chanp);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+		chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 	}
 }
 
@@ -434,7 +396,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
-	L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
 }
 
 static void
@@ -443,7 +405,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	FsmChangeState(fi, ST_IN_ALERT_SENT);
-	L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 }
 
 static void
@@ -451,7 +413,7 @@
 {
 	struct Channel *chanp = fi->userdata;
 
-	L4L3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
 }
 
 static void
@@ -466,7 +428,7 @@
 	chanp->l2_active_protocol = chanp->l2_protocol;
 	chanp->incoming = !0;
 	init_b_st(chanp, !0);
-	L4L3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -479,9 +441,9 @@
 	} else {
 		FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
 #ifdef WANT_ALERT
-		L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 #endif
-		L4L3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
 	}
 }
 
@@ -492,7 +454,7 @@
 {
 	struct Channel *chanp = fi->userdata;
 
-	L4L3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
 }
 
 /* Call clearing */
@@ -524,7 +486,8 @@
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
 		if (chanp->proc)
 			chanp->proc->para.cause = 0x10;	/* Normal Call Clearing */
-		L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
+			chanp->proc);
 	}
 }
 
@@ -539,7 +502,8 @@
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
 		if (chanp->proc)
 			chanp->proc->para.cause = 0x15;	/* Call Rejected */
-		L4L3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
+			chanp->proc);
 	}
 }
 
@@ -571,12 +535,12 @@
 #ifndef ALERT_REJECT
 	if (chanp->proc)
 		chanp->proc->para.cause = 0x15;	/* Call Rejected */
-	L4L3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
 	lli_dhup_close(fi, event, arg);
 #else
 	FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
 	FsmChangeState(fi, ST_IN_ALERT_SENT);
-	L4L3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+	chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
 #endif
 }
 
@@ -587,7 +551,7 @@
 
 	chanp->data_open = 0;
 	FsmChangeState(fi, ST_WAIT_BRELEASE);
-	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 static void
@@ -642,7 +606,7 @@
 
 	chanp->data_open = 0;
 	FsmChangeState(fi, ST_WAIT_BREL_DISC);
-	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 
@@ -672,7 +636,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	chanp->data_open = 0;
-	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 	lli_bhup_dhup(fi, event, arg);
 }
  
@@ -685,7 +649,8 @@
 		lli_leased_hup(fi, chanp);
 	} else {
 		FsmChangeState(fi, ST_WAIT_D_REL_CNF);
-		L4L3(chanp->d_st, CC_RELEASE | REQUEST,	chanp->proc);
+		chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
+			chanp->proc);
 	}
 }
 
@@ -767,7 +732,7 @@
 	chanp->cs->iif.statcallb(&ic);
 	HL_LL(chanp, ISDN_STAT_DHUP);
 	chanp->Flags = 0;
-	mdl_info_release(chanp);
+	chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 }
 
 static void
@@ -796,7 +761,7 @@
 	struct Channel *chanp = fi->userdata;
 
 	chanp->data_open = 0;
-	L4L3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+	chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 	lli_bhup_fail(fi, event, arg);
 }
 
@@ -890,11 +855,10 @@
 static void
 release_b_st(struct Channel *chanp)
 {
-	struct IsdnCardState *cs = chanp->cs;
 	struct PStack *st = chanp->b_st;
 
 	if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
-		cs->bc_l1_ops->close(chanp->bcs);
+		chanp->bcs->BC_Close(chanp->bcs);
 		switch (chanp->l2_active_protocol) {
 			case (ISDN_PROTO_L2_X75I):
 				releasestack_isdnl2(st);
@@ -954,7 +918,7 @@
 	ic.driver = cs->myid;
 	ic.command = ISDN_STAT_REDIR;
 	ic.arg = chan; 
-	(ulong)(ic.parm.num[0]) = result;
+	ic.parm.num[0] = result;
 	cs->iif.statcallb(&ic);
 } /* stat_redir_result */
 
@@ -971,7 +935,7 @@
 	if (pr == (CC_SETUP | INDICATION)) {
 		if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
 			pc->para.cause = 0x11;	/* User busy */
-			L4L3(pc->st, CC_REJECT | REQUEST, pc);
+			pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
 		} else {
 			chanp->proc = pc;
 			pc->chan = chanp;
@@ -1054,16 +1018,16 @@
 	if (!*stp)
 		return -ENOMEM;
 	(*stp)->next = NULL;
+	(*stp)->l1.l1l2 = dummy_pstack;
 	(*stp)->l1.l1hw = dummy_pstack;
 	(*stp)->l1.l1tei = dummy_pstack;
-	(*stp)->l1.l2l1 = dummy_pstack;
-	(*stp)->l2.l1l2 = dummy_pstack;
 	(*stp)->l2.l2tei = dummy_pstack;
-	(*stp)->l2.l3l2 = dummy_pstack;
-	(*stp)->l3.l2l3 = dummy_pstack;
+	(*stp)->l2.l2l1 = dummy_pstack;
+	(*stp)->l2.l2l3 = dummy_pstack;
+	(*stp)->l3.l3l2 = dummy_pstack;
 	(*stp)->l3.l3ml3 = dummy_pstack;
-	(*stp)->l3.l4l3 = dummy_pstack;
-	(*stp)->lli.l3l4 = dummy_pstack;
+	(*stp)->l3.l3l4 = dummy_pstack;
+	(*stp)->lli.l4l3 = dummy_pstack;
 	(*stp)->ma.layer = dummy_pstack;
 	return 0;
 }
@@ -1101,7 +1065,7 @@
 	setstack_isdnl2(st, tmp);
 	setstack_l3dc(st, chanp);
 	st->lli.userdata = chanp;
-	st->lli.l3l4 = dchan_l3l4;
+	st->l3.l3l4 = dchan_l3l4;
 
 	return 0;
 }
@@ -1175,7 +1139,8 @@
 	printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
 	if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
 		printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
-		L4L3(csta->channel->d_st, DL_ESTABLISH | REQUEST, NULL);
+		csta->channel->d_st->lli.l4l3(csta->channel->d_st,
+			DL_ESTABLISH | REQUEST, NULL);
 	}
 	return (0);
 }
@@ -1209,7 +1174,7 @@
 			kfree(csta->channel[i].b_st);
 			csta->channel[i].b_st = NULL;
 		} else
-			printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i);
+			printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
 		if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
 			release_d_st(csta->channel + i);
 		} else
@@ -1218,30 +1183,13 @@
 }
 
 static void
-ll_writewakeup(struct Channel *chanp, struct sk_buff *skb)
-{
-	isdn_ctrl ic;
-
-	if (skb->pkt_type != PACKET_NOACK) {
-		if (chanp->debug & 0x800)
-			link_debug(chanp, 0, "llwakeup: %d", skb->truesize);
-		ic.driver = chanp->cs->myid;
-		ic.command = ISDN_STAT_BSENT;
-		ic.arg = chanp->chan;
-		ic.parm.length = skb->truesize;
-		chanp->cs->iif.statcallb(&ic);
-	}
-	dev_kfree_skb(skb);
-}
-
-static void
 lldata_handler(struct PStack *st, int pr, void *arg)
 {
 	struct Channel *chanp = (struct Channel *) st->lli.userdata;
 	struct sk_buff *skb = arg;
 
 	switch (pr) {
-		case (DL_DATA | INDICATION):
+		case (DL_DATA  | INDICATION):
 			if (chanp->data_open) {
 				if (chanp->debug & 0x800)
 					link_debug(chanp, 0, "lldata: %d", skb->len);
@@ -1251,9 +1199,6 @@
 				dev_kfree_skb(skb);
 			}
 			break;
-		case (DL_DATA | CONFIRM):
-			ll_writewakeup(chanp, skb);
-			break;
 		case (DL_ESTABLISH | INDICATION):
 		case (DL_ESTABLISH | CONFIRM):
 			FsmEvent(&chanp->fi, EV_BC_EST, NULL);
@@ -1286,9 +1231,6 @@
 				dev_kfree_skb(skb);
 			}
 			break;
-		case (PH_DATA | CONFIRM):
-			ll_writewakeup(chanp, skb);
-			break;
 		case (PH_ACTIVATE | INDICATION):
 		case (PH_ACTIVATE | CONFIRM):
 			FsmEvent(&chanp->fi, EV_BC_EST, NULL);
@@ -1304,6 +1246,21 @@
 	}
 }
 
+void
+lli_writewakeup(struct PStack *st, int len)
+{
+	struct Channel *chanp = st->lli.userdata;
+	isdn_ctrl ic;
+
+	if (chanp->debug & 0x800)
+		link_debug(chanp, 0, "llwakeup: %d", len);
+	ic.driver = chanp->cs->myid;
+	ic.command = ISDN_STAT_BSENT;
+	ic.arg = chanp->chan;
+	ic.parm.length = len;
+	chanp->cs->iif.statcallb(&ic);
+}
+
 static int
 init_b_st(struct Channel *chanp, int incoming)
 {
@@ -1335,7 +1292,7 @@
 			break;
 	}
 	chanp->bcs->conmsg = NULL;
-	if (cs->bc_l1_ops->open(st, chanp->bcs))
+	if (chanp->bcs->BC_SetStack(st, chanp->bcs))
 		return (-1);
 	st->l2.flag = 0;
 	test_and_set_bit(FLG_LAPB, &st->l2.flag);
@@ -1352,8 +1309,10 @@
 			sprintf(tmp, "Ch%d X.75", chanp->chan);
 			setstack_isdnl2(st, tmp);
 			setstack_l3bc(st, chanp);
-			st->l3.l2l3 = lldata_handler;
+			st->l2.l2l3 = lldata_handler;
 			st->lli.userdata = chanp;
+			test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
+			test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
 			st->l2.l2m.debug = chanp->debug & 16;
 			st->l2.debug = chanp->debug & 64;
 			break;
@@ -1362,8 +1321,10 @@
 		case (ISDN_PROTO_L2_TRANS):
 		case (ISDN_PROTO_L2_MODEM):
 		case (ISDN_PROTO_L2_FAX):
-			st->l2.l1l2 = lltrans_handler;
+			st->l1.l1l2 = lltrans_handler;
 			st->lli.userdata = chanp;
+			test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
+			test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
 			setstack_transl2(st);
 			setstack_l3bc(st, chanp);
 			break;
@@ -1384,7 +1345,7 @@
 			dev_kfree_skb(skb);
 			break;
 		case (DL_ESTABLISH | REQUEST):
-			L2L1(st, PH_ACTIVATE | REQUEST, NULL);
+			st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
 			break;
 		case (DL_RELEASE | REQUEST):
 			break;
@@ -1462,7 +1423,7 @@
 {
 	char *t = tmpbuf;
 
-	t += QuickHex(t, (u8 *)cm, (cm->Length>50)? 50: cm->Length);
+	t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
 	t--;
 	*t= 0;
 	HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
@@ -1478,11 +1439,11 @@
 		return;
 	switch(cm->para[3]) {
 		case 4: /* Suspend */
-			strlcpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+			strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
 			FsmEvent(&chanp->fi, EV_SUSPEND, cm);
 			break;
 		case 5: /* Resume */
-			strlcpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+			strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
 			if (chanp->fi.state == ST_NULL) {
 				FsmEvent(&chanp->fi, EV_RESUME, cm);
 			} else {
@@ -1495,8 +1456,12 @@
 
 void
 lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
-	if (cs->card_ops->aux_ind)
-		cs->card_ops->aux_ind(cs, cm->para);
+	if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
+		(cs->typ == ISDN_CTYPE_ELSA_PCI)) {
+		if (cs->hw.elsa.MFlag) {
+			cs->cardmsg(cs, CARD_AUX_IND, cm->para);
+		}
+	}
 }
 
 
@@ -1654,15 +1619,16 @@
 						HiSax_putstatus(csta, "Card",
 							"%d channel %d set leased mode\n",
 							csta->cardnr + 1, num + 1);
-						chanp->d_st->l2.l1l2 = leased_l1l2;
-						chanp->d_st->l3.l4l3 = leased_l4l3;
-						L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
+						chanp->d_st->l1.l1l2 = leased_l1l2;
+						chanp->d_st->lli.l4l3 = leased_l4l3;
+						chanp->d_st->lli.l4l3(chanp->d_st,
+							DL_ESTABLISH | REQUEST, NULL);
 					}
 					break;
 				case (6):	/* set B-channel test loop */
 					num = *(unsigned int *) ic->parm.num;
 					if (csta->stlist)
-						csta->stlist->l1.l2l1(csta->stlist,
+						csta->stlist->l2.l2l1(csta->stlist,
 							PH_TESTLOOP | REQUEST, (void *) (long)num);
 					break;
 				case (7):	/* set card in PTP mode */
@@ -1676,7 +1642,8 @@
 						HiSax_putstatus(csta, "set card ", "in PTP mode");
 						printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
 						printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
-						L4L3(csta->channel[0].d_st, DL_ESTABLISH | REQUEST, NULL);
+						csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
+							DL_ESTABLISH | REQUEST, NULL);
 					} else {
 						test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
 						test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
@@ -1700,7 +1667,8 @@
 						printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
 							num);
 					}
-					L4L3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
+					chanp->d_st->lli.l4l3(chanp->d_st,
+						DL_ESTABLISH | REQUEST, NULL);
 					break;
 				case (11):
 					num = csta->debug & DEB_DLOG_HEX;
@@ -1758,8 +1726,8 @@
 		/* protocol specific io commands */
 		case (ISDN_CMD_PROT_IO):
 			for (st = csta->stlist; st; st = st->next)
-				if ((u_int)st->protocol == (ic->arg & 0xFF))
-					return(st->l3.l4l3_proto(st, ic));
+				if (st->protocol == (ic->arg & 0xFF))
+					return(st->lli.l4l3_proto(st, ic));
 			return(-EINVAL);
 			break;
 		default:
@@ -1777,7 +1745,6 @@
 	struct Channel *chanp;
 	struct PStack *st;
 	int len = skb->len;
-	unsigned long flags;
 	struct sk_buff *nskb;
 
 	if (!csta) {
@@ -1807,22 +1774,20 @@
 			return 0;
 		} else if (chanp->debug & 0x800)
 			link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM);
-		spin_lock_irqsave(&callc_lock, flags);
 		nskb = skb_clone(skb, GFP_ATOMIC);
 		if (nskb) {
 			nskb->truesize = nskb->len;
 			if (!ack)
 				nskb->pkt_type = PACKET_NOACK;
 			if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
-				L3L2(st, DL_DATA | REQUEST, nskb);
+				st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
 			else {
 				chanp->bcs->tx_cnt += len;
-				st->l1.l2l1(st, PH_DATA | REQUEST, nskb);
+				st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
 			}
 			dev_kfree_skb(skb);
 		} else
 			len = 0;
-		spin_unlock_irqrestore(&callc_lock, flags);
 	}
 	return (len);
 }
--- diff/drivers/isdn/hisax/config.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/isdn/hisax/config.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 1.1.4.2.2.1 2001/12/09 20:18:40 kai Exp $
+/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $
  *
  * Author       Karsten Keil
  * Copyright    by Karsten Keil      <keil@isdn4linux.de>
@@ -24,7 +24,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include "isdnl1.h"
 #define HISAX_STATUS_BUFSIZE 4096
 #define INCLUDE_INLINE_FUNCS
 
@@ -99,14 +98,9 @@
 	"Hotplug", "Formula-n enter:now PCI a/b", 
 };
 
-void HiSax_closecard(int cardnr);
-static spinlock_t hisax_config_lock = SPIN_LOCK_UNLOCKED;
-
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
-int elsa_init_pcmcia(void *, int, int *, int);
-EXPORT_SYMBOL(elsa_init_pcmcia);
 #endif
 
 #ifdef CONFIG_HISAX_AVM_A1
@@ -121,8 +115,6 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
 #define DEFAULT_CFG {11,0x170,0,0}
-int avm_a1_init_pcmcia(void *, int, int *, int);
-EXPORT_SYMBOL(avm_a1_init_pcmcia);
 #endif
 
 #ifdef CONFIG_HISAX_FRITZPCI
@@ -193,8 +185,6 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
 #define DEFAULT_CFG {11,0x270,0,0}
-int sedl_init_pcmcia(void *, int, int *, int);
-EXPORT_SYMBOL(sedl_init_pcmcia);
 #endif
 
 #ifdef CONFIG_HISAX_SPORTSTER
@@ -237,8 +227,6 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_HFC_SX
 #define DEFAULT_CFG {5,0x2E0,0,0}
-int hfc_init_pcmcia(void *, int, int *, int);
-EXPORT_SYMBOL(hfc_init_pcmcia);
 #endif
 
 
@@ -330,10 +318,6 @@
 #define DEFAULT_CFG {0,0,0,0}
 #endif
 
-int hisax_init_pcmcia(void *, int *, struct IsdnCard *);
-EXPORT_SYMBOL(hisax_init_pcmcia);
-EXPORT_SYMBOL(HiSax_closecard);
-
 #define FIRST_CARD { \
 	DEFAULT_CARD, \
 	DEFAULT_PROTO, \
@@ -346,14 +330,14 @@
 };
 
 #define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
-static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, };
+static char HiSaxID[HISAX_IDSIZE] = { 0, };
 
-char *HiSax_id __devinitdata = HiSaxID;
+char *HiSax_id = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-static int type[HISAX_MAX_CARDS] __devinitdata = { 0, };
-static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, };
-static int io[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int type[HISAX_MAX_CARDS] = { 0, };
+static int protocol[HISAX_MAX_CARDS] = { 0, };
+static int io[HISAX_MAX_CARDS] = { 0, };
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -368,7 +352,7 @@
 #endif
 static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
 static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
-static char *id __devinitdata = HiSaxID;
+static char *id = HiSaxID;
 
 #define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i"
 
@@ -430,7 +414,6 @@
 	strcpy(tmp, lli_revision);
 	printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
 	       HiSax_getrev(tmp));
-	certification_check(1);
 }
 
 #ifndef MODULE
@@ -490,36 +473,125 @@
 __setup("hisax=", HiSax_setup);
 #endif /* MODULES */
 
+#if CARD_TELES0
 extern int setup_teles0(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3
 extern int setup_teles3(struct IsdnCard *card);
+#endif
+
+#if CARD_S0BOX
 extern int setup_s0box(struct IsdnCard *card);
+#endif
+
+#if CARD_TELESPCI
 extern int setup_telespci(struct IsdnCard *card);
+#endif
+
+#if CARD_AVM_A1
 extern int setup_avm_a1(struct IsdnCard *card);
+#endif
+
+#if CARD_AVM_A1_PCMCIA
 extern int setup_avm_a1_pcmcia(struct IsdnCard *card);
+#endif
+
+#if CARD_FRITZPCI
 extern int setup_avm_pcipnp(struct IsdnCard *card);
+#endif
+
+#if CARD_ELSA
 extern int setup_elsa(struct IsdnCard *card);
+#endif
+
+#if CARD_IX1MICROR2
 extern int setup_ix1micro(struct IsdnCard *card);
+#endif
+
+#if CARD_DIEHLDIVA
 extern int setup_diva(struct IsdnCard *card);
+#endif
+
+#if CARD_ASUSCOM
 extern int setup_asuscom(struct IsdnCard *card);
+#endif
+
+#if CARD_TELEINT
 extern int setup_TeleInt(struct IsdnCard *card);
+#endif
+
+#if CARD_SEDLBAUER
 extern int setup_sedlbauer(struct IsdnCard *card);
+#endif
+
+#if CARD_SPORTSTER
 extern int setup_sportster(struct IsdnCard *card);
+#endif
+
+#if CARD_MIC
 extern int setup_mic(struct IsdnCard *card);
+#endif
+
+#if CARD_NETJET_S
 extern int setup_netjet_s(struct IsdnCard *card);
+#endif
+
+#if CARD_HFCS
 extern int setup_hfcs(struct IsdnCard *card);
+#endif
+
+#if CARD_HFC_PCI
 extern int setup_hfcpci(struct IsdnCard *card);
+#endif
+
+#if CARD_HFC_SX
 extern int setup_hfcsx(struct IsdnCard *card);
+#endif
+
+#if CARD_AMD7930
 extern int setup_amd7930(struct IsdnCard *card);
+#endif
+
+#if CARD_NICCY
 extern int setup_niccy(struct IsdnCard *card);
+#endif
+
+#if CARD_ISURF
 extern int setup_isurf(struct IsdnCard *card);
+#endif
+
+#if CARD_HSTSAPHIR
 extern int setup_saphir(struct IsdnCard *card);
+#endif
+
+#if CARD_TESTEMU
 extern int setup_testemu(struct IsdnCard *card);
+#endif
+
+#if CARD_BKM_A4T
 extern int setup_bkm_a4t(struct IsdnCard *card);
+#endif
+
+#if CARD_SCT_QUADRO
 extern int setup_sct_quadro(struct IsdnCard *card);
+#endif
+
+#if CARD_GAZEL
 extern int setup_gazel(struct IsdnCard *card);
+#endif
+
+#if CARD_W6692
 extern int setup_w6692(struct IsdnCard *card);
+#endif
+
+#if CARD_NETJET_U
 extern int setup_netjet_u(struct IsdnCard *card);
+#endif
+
+#if CARD_FN_ENTERNOW_PCI
 extern int setup_enternow_pci(struct IsdnCard *card);
+#endif
 
 /*
  * Find card with given driverId
@@ -546,10 +618,10 @@
 	return NULL;
 }
 
-int HiSax_readstatus(u8 * buf, int len, int user, int id, int channel)
+int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
 	int count, cnt;
-	u8 *p = buf;
+	u_char *p = buf;
 	struct IsdnCardState *cs = hisax_findcard(id);
 
 	if (cs) {
@@ -561,10 +633,9 @@
 		count = cs->status_end - cs->status_read + 1;
 		if (count >= len)
 			count = len;
-		if (user) {
-			if (copy_to_user(p, cs->status_read, count))
-				return -EFAULT;
-		} else
+		if (user)
+			copy_to_user(p, cs->status_read, count);
+		else
 			memcpy(p, cs->status_read, count);
 		cs->status_read += count;
 		if (cs->status_read > cs->status_end)
@@ -576,10 +647,9 @@
 				cnt = HISAX_STATUS_BUFSIZE;
 			else
 				cnt = count;
-			if (user) {
-				if (copy_to_user(p, cs->status_read, cnt))
-					return -EFAULT;
-			} else
+			if (user)
+				copy_to_user(p, cs->status_read, cnt);
+			else
 				memcpy(p, cs->status_read, cnt);
 			p += cnt;
 			cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
@@ -614,20 +684,24 @@
 	return 8;
 }
 
-static char tmpbuf[HISAX_STATUS_BUFSIZE];
+static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
 
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt,
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
 		      va_list args)
 {
 	/* if head == NULL the fmt contains the full info */
 
-	unsigned long flags;
-	int count, i;
-	char *p;
-	isdn_ctrl ic;
-	int len;
+	u_long		flags;
+	int		count, i;
+	u_char		*p;
+	isdn_ctrl	ic;
+	int		len;
 
-	spin_lock_irqsave(&hisax_config_lock, flags);
+	if (!cs) {
+		printk(KERN_WARNING "HiSax: No CardStatus for message");
+		return;
+	}
+	spin_lock_irqsave(&cs->statlock, flags);
 	p = tmpbuf;
 	if (head) {
 		p += jiftime(p, jiffies);
@@ -638,19 +712,13 @@
 		len = p - tmpbuf;
 		p = tmpbuf;
 	} else {
-		p = (char *) fmt;
+		p = fmt;
 		len = strlen(fmt);
 	}
-	if (!cs) {
-		printk(KERN_WARNING "HiSax: No CardStatus for message %s",
-		       p);
-		spin_unlock_irqrestore(&hisax_config_lock, flags);
-		return;
-	}
 	if (len > HISAX_STATUS_BUFSIZE) {
+		spin_unlock_irqrestore(&cs->statlock, flags);
 		printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
 		       len, HISAX_STATUS_BUFSIZE);
-		spin_unlock_irqrestore(&hisax_config_lock, flags);
 		return;
 	}
 	count = len;
@@ -679,7 +747,7 @@
 		count++;
 	}
 #endif
-	spin_unlock_irqrestore(&hisax_config_lock, flags);
+	spin_unlock_irqrestore(&cs->statlock, flags);
 	if (count) {
 		ic.command = ISDN_STAT_STAVAIL;
 		ic.driver = cs->myid;
@@ -725,15 +793,22 @@
 	ic.command = ISDN_STAT_UNLOAD;
 	ic.driver = cs->myid;
 	cs->iif.statcallb(&ic);
+	if (cs->status_buf)
+		kfree(cs->status_buf);
+	cs->status_read = NULL;
+	cs->status_write = NULL;
+	cs->status_end = NULL;
+	kfree(cs->dlog);
+	cs->dlog = NULL;
 }
 
 static void closecard(int cardnr)
 {
 	struct IsdnCardState *csta = cards[cardnr].cs;
 
-	if (csta->bc_l1_ops->close) {
-		csta->bc_l1_ops->close(csta->bcs + 1);
-		csta->bc_l1_ops->close(csta->bcs);
+	if (csta->bcs->BC_Close != NULL) {
+		csta->bcs->BC_Close(csta->bcs + 1);
+		csta->bcs->BC_Close(csta->bcs);
 	}
 
 	skb_queue_purge(&csta->rq);
@@ -746,32 +821,34 @@
 		dev_kfree_skb(csta->tx_skb);
 		csta->tx_skb = NULL;
 	}
-	if (csta->dc_l1_ops->close)
-		csta->dc_l1_ops->close(csta);
-
-	if (csta->card_ops->release)
-		csta->card_ops->release(csta);
+	if (csta->DC_Close != NULL) {
+		csta->DC_Close(csta);
+	}
+	if (csta->cardmsg)
+		csta->cardmsg(csta, CARD_RELEASE, NULL);
 	if (csta->dbusytimer.function != NULL) // FIXME?
 		del_timer(&csta->dbusytimer);
 	ll_unload(csta);
 }
 
-static int __devinit init_card(struct IsdnCardState *cs)
+static int init_card(struct IsdnCardState *cs)
 {
-	int irq_cnt, cnt = 3;
-
-	cs->card_ops->init(cs);
+	int 	irq_cnt, cnt = 3, ret;
 
+	if (!cs->irq) {
+		ret = cs->cardmsg(cs, CARD_INIT, NULL);
+		return(ret);
+	}
 	irq_cnt = kstat_irqs(cs->irq);
 	printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
 	       cs->irq, irq_cnt);
-	if (request_irq(cs->irq, cs->card_ops->irq_func, cs->irq_flags, "HiSax", cs)) {
+	if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
 		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
 		       cs->irq);
 		return 1;
 	}
 	while (cnt) {
-		cs->card_ops->init(cs);
+		cs->cardmsg(cs, CARD_INIT, NULL);
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		/* Timeout 10ms */
 		schedule_timeout((10 * HZ) / 1000);
@@ -785,86 +862,74 @@
 				free_irq(cs->irq, cs);
 				return 2;
 			} else {
-				if (cs->card_ops->reset)
-					cs->card_ops->reset(cs);
+				cs->cardmsg(cs, CARD_RESET, NULL);
 				cnt--;
 			}
 		} else {
-			if (cs->card_ops->test)
-				cs->card_ops->test(cs);
+			cs->cardmsg(cs, CARD_TEST, NULL);
 			return 0;
 		}
 	}
 	return 3;
 }
 
-static struct IsdnCardState *
-alloc_IsdnCardState(void)
+static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
 {
+	int ret = 0;
+	struct IsdnCard *card = cards + cardnr;
 	struct IsdnCardState *cs;
 
-	cs = kmalloc(sizeof(*cs), GFP_ATOMIC); // FIXME
-	if (!cs)
-		goto err;
-
-	memset(cs, 0, sizeof(*cs));
-
-	cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC);
-	if (!cs->dlog)
-		goto err_cs;
-
-	cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC);
-	if (!cs->status_buf)
-		goto err_dlog;
-
-	cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC);
-	if (!cs->rcvbuf)
-		goto err_status_buf;
-
+	cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+	if (!cs) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for IsdnCardState(card %d)\n",
+		       cardnr + 1);
+		goto out;
+	}
+	memset(cs, 0, sizeof(struct IsdnCardState));
+	card->cs = cs;
+	spin_lock_init(&cs->statlock);
+	spin_lock_init(&cs->lock);
 	cs->chanlimit = 2;	/* maximum B-channel number */
+	cs->logecho = 0;	/* No echo logging */
+	cs->cardnr = cardnr;
 	cs->debug = L1_DEB_WARN;
+	cs->HW_Flags = 0;
+	cs->busy_flag = busy_flag;
 	cs->irq_flags = I4L_IRQ_FLAG;
+#if TEI_PER_CARD
+	if (card->protocol == ISDN_PTYPE_NI1)
+		test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#else
+	test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+	cs->protocol = card->protocol;
+
+	if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
+		printk(KERN_WARNING
+		       "HiSax: Card Type %d out of range\n", card->typ);
+		goto outf_cs;
+	}
+	if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
+		goto outf_cs;
+	}
+	if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for status_buf(card %d)\n",
+		       cardnr + 1);
+		goto outf_dlog;
+	}
 	cs->stlist = NULL;
 	cs->status_read = cs->status_buf;
 	cs->status_write = cs->status_buf;
 	cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
-	cs->rcvidx = 0;
-	cs->tx_skb = NULL;
-	cs->tx_cnt = 0;
-	cs->event = 0;
-
-	skb_queue_head_init(&cs->rq);
-	skb_queue_head_init(&cs->sq);
-
-	spin_lock_init(&cs->lock);
-	resources_init(&cs->rs);
-	return cs;
-
- err_status_buf:
-	kfree(cs->status_buf);
- err_dlog:
-	kfree(cs->dlog);
- err_cs:
-	kfree(cs);
- err:
-	return NULL;
-}
-
-static void
-free_IsdnCardState(struct IsdnCardState *cs)
-{
-	kfree(cs->rcvbuf);
-	kfree(cs->status_buf);
-	kfree(cs->dlog);
-	kfree(cs);
-}
-
-static void
-do_register_isdn(struct IsdnCardState *cs)
-{
-	if (!cs->iif.owner)
-		cs->iif.owner = THIS_MODULE;
-
+	cs->typ = card->typ;
+#ifdef MODULE
+	cs->iif.owner = lockowner;
+#endif
+	strcpy(cs->iif.id, id);
 	cs->iif.channels = 2;
 	cs->iif.maxbufsize = MAX_DATA_SIZE;
 	cs->iif.hl_hdrlen = MAX_HEADER_LEN;
@@ -892,72 +957,20 @@
 	register_isdn(&cs->iif);
 	cs->myid = cs->iif.channels;
 	printk(KERN_INFO
-	       "HiSax: Card %d Protocol %s Id=%s (%d)\n", cs->cardnr + 1,
-	       (cs->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
-	       (cs->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
-	       (cs->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
-	       (cs->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+	       "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+	       (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+	       (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+	       (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+	       (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
 	       "NONE", cs->iif.id, cs->myid);
-}
-
-static int
-do_init(struct IsdnCardState *cs)
-{
-	int ret;
-	
-	init_tei(cs, cs->protocol);
-	ret = CallcNewChan(cs);
-	if (ret)
-		return -EIO;
-	
-	/* ISAR needs firmware download first */
-	if (!test_bit(HW_ISAR, &cs->HW_Flags))
-		ll_run(cs, 0);
-	
-	return 0;
-}
-
-
-static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
-{
-	int ret = 0;
-	struct IsdnCard *card = cards + cardnr;
-	struct IsdnCardState *cs;
-
-	cs = alloc_IsdnCardState();
-	if (!cs) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for IsdnCardState(card %d)\n",
-		       cardnr + 1);
-		goto out;
-	}
-	card->cs = cs;
-#if TEI_PER_CARD
-	if (card->protocol == ISDN_PTYPE_NI1)
-		test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
-	test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
-	cs->cardnr = cardnr;
-	cs->protocol = card->protocol;
-	cs->typ = card->typ;
-	cs->busy_flag = busy_flag;
-
-	if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
-		printk(KERN_WARNING
-		       "HiSax: Card Type %d out of range\n", card->typ);
-		goto outf_cs;
-	}
-	strcpy(cs->iif.id, id);
-	do_register_isdn(cs);
 	switch (card->typ) {
-#ifdef CONFIG_HISAX_16_0
+#if CARD_TELES0
 	case ISDN_CTYPE_16_0:
 	case ISDN_CTYPE_8_0:
 		ret = setup_teles0(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_16_3
+#if CARD_TELES3
 	case ISDN_CTYPE_16_3:
 	case ISDN_CTYPE_PNP:
 	case ISDN_CTYPE_TELESPCMCIA:
@@ -965,32 +978,32 @@
 		ret = setup_teles3(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_S0BOX
+#if CARD_S0BOX
 	case ISDN_CTYPE_S0BOX:
 		ret = setup_s0box(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_TELESPCI
+#if CARD_TELESPCI
 	case ISDN_CTYPE_TELESPCI:
 		ret = setup_telespci(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_AVM_A1
+#if CARD_AVM_A1
 	case ISDN_CTYPE_A1:
 		ret = setup_avm_a1(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+#if CARD_AVM_A1_PCMCIA
 	case ISDN_CTYPE_A1_PCMCIA:
 		ret = setup_avm_a1_pcmcia(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_FRITZPCI
+#if CARD_FRITZPCI
 	case ISDN_CTYPE_FRITZPCI:
 		ret = setup_avm_pcipnp(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_ELSA
+#if CARD_ELSA
 	case ISDN_CTYPE_ELSA:
 	case ISDN_CTYPE_ELSA_PNP:
 	case ISDN_CTYPE_ELSA_PCMCIA:
@@ -998,115 +1011,115 @@
 		ret = setup_elsa(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_IX1MICROR2
+#if CARD_IX1MICROR2
 	case ISDN_CTYPE_IX1MICROR2:
 		ret = setup_ix1micro(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_DIEHLDIVA
+#if CARD_DIEHLDIVA
 	case ISDN_CTYPE_DIEHLDIVA:
 		ret = setup_diva(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_ASUSCOM
+#if CARD_ASUSCOM
 	case ISDN_CTYPE_ASUSCOM:
 		ret = setup_asuscom(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_TELEINT
+#if CARD_TELEINT
 	case ISDN_CTYPE_TELEINT:
 		ret = setup_TeleInt(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_SEDLBAUER
+#if CARD_SEDLBAUER
 	case ISDN_CTYPE_SEDLBAUER:
 	case ISDN_CTYPE_SEDLBAUER_PCMCIA:
 	case ISDN_CTYPE_SEDLBAUER_FAX:
 		ret = setup_sedlbauer(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_SPORTSTER
+#if CARD_SPORTSTER
 	case ISDN_CTYPE_SPORTSTER:
 		ret = setup_sportster(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_MIC
+#if CARD_MIC
 	case ISDN_CTYPE_MIC:
 		ret = setup_mic(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_NETJET
+#if CARD_NETJET_S
 	case ISDN_CTYPE_NETJET_S:
 		ret = setup_netjet_s(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_HFCS
+#if CARD_HFCS
 	case ISDN_CTYPE_TELES3C:
 	case ISDN_CTYPE_ACERP10:
 		ret = setup_hfcs(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_HFC_PCI
+#if CARD_HFC_PCI
 	case ISDN_CTYPE_HFC_PCI:
 		ret = setup_hfcpci(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_HFC_SX
+#if CARD_HFC_SX
 	case ISDN_CTYPE_HFC_SX:
 		ret = setup_hfcsx(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_NICCY
+#if CARD_NICCY
 	case ISDN_CTYPE_NICCY:
 		ret = setup_niccy(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_AMD7930
+#if CARD_AMD7930
 	case ISDN_CTYPE_AMD7930:
 		ret = setup_amd7930(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_ISURF
+#if CARD_ISURF
 	case ISDN_CTYPE_ISURF:
 		ret = setup_isurf(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_HSTSAPHIR
+#if CARD_HSTSAPHIR
 	case ISDN_CTYPE_HSTSAPHIR:
 		ret = setup_saphir(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_TESTEMU
+#if CARD_TESTEMU
 	case ISDN_CTYPE_TESTEMU:
 		ret = setup_testemu(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_BKM_A4T
+#if	CARD_BKM_A4T
 	case ISDN_CTYPE_BKM_A4T:
 		ret = setup_bkm_a4t(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_SCT_QUADRO
+#if	CARD_SCT_QUADRO
 	case ISDN_CTYPE_SCT_QUADRO:
 		ret = setup_sct_quadro(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_GAZEL
+#if CARD_GAZEL
 	case ISDN_CTYPE_GAZEL:
 		ret = setup_gazel(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_W6692
+#if CARD_W6692
 	case ISDN_CTYPE_W6692:
 		ret = setup_w6692(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_NETJET_U
+#if CARD_NETJET_U
 	case ISDN_CTYPE_NETJET_U:
 		ret = setup_netjet_u(card);
 		break;
 #endif
-#ifdef CONFIG_HISAX_ENTERNOW_PCI
+#if CARD_FN_ENTERNOW_PCI
 	case ISDN_CTYPE_ENTERNOW:
 		ret = setup_enternow_pci(card);
 		break;
@@ -1125,40 +1138,62 @@
 		ll_unload(cs);
 		goto outf_cs;
 	}
+	if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
+		printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
+		ll_unload(cs);
+		goto outf_cs;
+	}
+	cs->rcvidx = 0;
+	cs->tx_skb = NULL;
+	cs->tx_cnt = 0;
+	cs->event = 0;
+	cs->tqueue.data = cs;
+
+	skb_queue_head_init(&cs->rq);
+	skb_queue_head_init(&cs->sq);
+
 	init_bcstate(cs, 0);
 	init_bcstate(cs, 1);
 
 	/* init_card only handles interrupts which are not */
 	/* used here for the loadable driver */
 	switch (card->typ) {
-	case ISDN_CTYPE_DYNAMIC:
-		ret = 0;
-		break;
-	default:
-		ret = init_card(cs);
-		break;
+		case ISDN_CTYPE_DYNAMIC:
+			ret = 0;
+			break;
+		default:
+			ret = init_card(cs);
+			break;
 	}
 	if (ret) {
 		closecard(cardnr);
 		ret = 0;
 		goto outf_cs;
 	}
-	if (do_init(cs)) {
+	init_tei(cs, cs->protocol);
+	ret = CallcNewChan(cs);
+	if (ret) {
 		closecard(cardnr);
 		ret = 0;
 		goto outf_cs;
 	}
+	/* ISAR needs firmware download first */
+	if (!test_bit(HW_ISAR, &cs->HW_Flags))
+		ll_run(cs, 0);
+
 	ret = 1;
 	goto out;
 
+ outf_dlog:
+	kfree(cs->dlog);
  outf_cs:
-	free_IsdnCardState(cs);
+	kfree(cs);
 	card->cs = NULL;
  out:
 	return ret;
 }
 
-void __devinit HiSax_shiftcards(int idx)
+void HiSax_shiftcards(int idx)
 {
 	int i;
 
@@ -1166,7 +1201,7 @@
 		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-int __devinit HiSax_inithardware(int *busy_flag)
+int HiSax_inithardware(int *busy_flag)
 {
 	int foundcards = 0;
 	int i = 0;
@@ -1196,13 +1231,16 @@
 			else
 				sprintf(ids, "%s%d", id, i);
 		}
-		if (checkcard(i, ids, busy_flag)) {
+		if (checkcard(i, ids, busy_flag, THIS_MODULE)) {
 			foundcards++;
 			i++;
 		} else {
-			printk(KERN_WARNING
-			       "HiSax: Card type %d not installed !\n",
-			       cards[i].typ);
+			/* make sure we don't oops the module */
+			if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) {
+				printk(KERN_WARNING
+			       		"HiSax: Card %s not installed !\n",
+			       		CardType[cards[i].typ]);
+			}
 			HiSax_shiftcards(i);
 			nrcards--;
 		}
@@ -1214,7 +1252,7 @@
 {
 	int i, last = nrcards - 1;
 
-	if (cardnr > last)
+	if (cardnr > last || cardnr < 0)
 		return;
 	if (cards[cardnr].cs) {
 		ll_stop(cards[cardnr].cs);
@@ -1492,182 +1530,9 @@
 	printk(KERN_INFO "HiSax module removed\n");
 }
 
-#ifdef CONFIG_HISAX_ELSA
-int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
-{
-#ifdef MODULE
-	int i;
-
-	nrcards = 0;
-	/* Initialize all structs, even though we only accept
-	   two pcmcia cards
-	*/
-	for (i = 0; i < HISAX_MAX_CARDS; i++) {
-		cards[i].para[0] = irq[i];
-		cards[i].para[1] = io[i];
-		cards[i].typ = type[i];
-		if (protocol[i]) {
-			cards[i].protocol = protocol[i];
-		} else {
-			cards[i].protocol = DEFAULT_PROTO;
-		}
-	}
-	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int) pcm_iob;
-	cards[0].protocol = prot;
-	cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA;
-
-	if (!HiSax_id)
-		HiSax_id = HiSaxID;
-	if (!HiSaxID[0])
-		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < HISAX_MAX_CARDS; i++)
-		if (cards[i].typ > 0)
-			nrcards++;
-	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
-	       nrcards, (nrcards > 1) ? "s" : "");
-
-	if (!HiSax_inithardware(busy_flag))
-		return -ENODEV;
-	printk(KERN_NOTICE "HiSax: module installed\n");
-#endif
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_HISAX_HFC_SX
-int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
-{
-#ifdef MODULE
-	int i;
-
-	nrcards = 0;
-	/* Initialize all structs, even though we only accept
-	   two pcmcia cards
-	*/
-	for (i = 0; i < HISAX_MAX_CARDS; i++) {
-		cards[i].para[0] = irq[i];
-		cards[i].para[1] = io[i];
-		cards[i].typ = type[i];
-		if (protocol[i]) {
-			cards[i].protocol = protocol[i];
-		} else {
-			cards[i].protocol = DEFAULT_PROTO;
-		}
-	}
-	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int) pcm_iob;
-	cards[0].protocol = prot;
-	cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
-
-	if (!HiSax_id)
-		HiSax_id = HiSaxID;
-	if (!HiSaxID[0])
-		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < HISAX_MAX_CARDS; i++)
-		if (cards[i].typ > 0)
-			nrcards++;
-	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
-	       nrcards, (nrcards > 1) ? "s" : "");
-
-	if (!HiSax_inithardware(busy_flag))
-		return -ENODEV;
-	printk(KERN_NOTICE "HiSax: module installed\n");
-#endif
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_HISAX_SEDLBAUER
-int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
 {
-#ifdef MODULE
-	int i;
-
-	nrcards = 0;
-	/* Initialize all structs, even though we only accept
-	   two pcmcia cards
-	*/
-	for (i = 0; i < HISAX_MAX_CARDS; i++) {
-		cards[i].para[0] = irq[i];
-		cards[i].para[1] = io[i];
-		cards[i].typ = type[i];
-		if (protocol[i]) {
-			cards[i].protocol = protocol[i];
-		} else {
-			cards[i].protocol = DEFAULT_PROTO;
-		}
-	}
-	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int) pcm_iob;
-	cards[0].protocol = prot;
-	cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
-
-	if (!HiSax_id)
-		HiSax_id = HiSaxID;
-	if (!HiSaxID[0])
-		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < HISAX_MAX_CARDS; i++)
-		if (cards[i].typ > 0)
-			nrcards++;
-	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
-	       nrcards, (nrcards > 1) ? "s" : "");
-
-	if (!HiSax_inithardware(busy_flag))
-		return -ENODEV;
-	printk(KERN_NOTICE "HiSax: module installed\n");
-#endif
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
-int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
-{
-#ifdef MODULE
-	int i;
-
-	nrcards = 0;
-	/* Initialize all structs, even though we only accept
-	   two pcmcia cards
-	*/
-	for (i = 0; i < HISAX_MAX_CARDS; i++) {
-		cards[i].para[0] = irq[i];
-		cards[i].para[1] = io[i];
-		cards[i].typ = type[i];
-		if (protocol[i]) {
-			cards[i].protocol = protocol[i];
-		} else {
-			cards[i].protocol = DEFAULT_PROTO;
-		}
-	}
-	cards[0].para[0] = pcm_irq;
-	cards[0].para[1] = (int) pcm_iob;
-	cards[0].protocol = prot;
-	cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
-
-	if (!HiSax_id)
-		HiSax_id = HiSaxID;
-	if (!HiSaxID[0])
-		strcpy(HiSaxID, "HiSax");
-	for (i = 0; i < HISAX_MAX_CARDS; i++)
-		if (cards[i].typ > 0)
-			nrcards++;
-	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
-	       nrcards, (nrcards > 1) ? "s" : "");
-
-	if (!HiSax_inithardware(busy_flag))
-		return -ENODEV;
-	printk(KERN_NOTICE "HiSax: module installed\n");
-#endif
-	return 0;
-}
-#endif
-
-int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag,
-				struct IsdnCard *card)
-{
-	u8 ids[16];
+	u_char ids[16];
 	int ret = -1;
 
 	cards[nrcards] = *card;
@@ -1675,14 +1540,18 @@
 		sprintf(ids, "HiSax%d", nrcards);
 	else
 		sprintf(ids, "HiSax");
-	if (!checkcard(nrcards, ids, busy_flag)) {
-		return -1;
-	}
+	if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE))
+		goto error;
+
 	ret = nrcards;
 	nrcards++;
+error:
 	return ret;
 }
 
+EXPORT_SYMBOL(hisax_init_pcmcia);
+EXPORT_SYMBOL(HiSax_closecard);
+
 #include "hisax_if.h"
 
 EXPORT_SYMBOL(hisax_register);
@@ -1692,68 +1561,47 @@
 static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg);
 static void hisax_d_l2l1(struct PStack *st, int pr, void *arg);
 static void hisax_b_l2l1(struct PStack *st, int pr, void *arg);
+static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg);
 static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs);
 static void hisax_bc_close(struct BCState *bcs);
-static void hisax_bh(void *data);
+static void hisax_bh(struct IsdnCardState *cs);
 static void EChannel_proc_rcv(struct hisax_d_if *d_if);
 
-static int
-hisax_l1_open(struct PStack *st, struct IsdnCardState *cs)
-{
-	st->l1.l2l1 = hisax_d_l2l1;
-	return 0;
-}
-
-static struct dc_l1_ops hisax_l1_ops = {
-	.open    = hisax_l1_open,
-	.bh_func = hisax_bh,
-};
-
-static struct bc_l1_ops hisax_bc_l1_ops = {
-	.open    = hisax_bc_setstack,
-	.close   = hisax_bc_close,
-};
-
 int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
 		   char *name, int protocol)
 {
-	int i;
+	int i, retval;
+	char id[20];
 	struct IsdnCardState *cs;
-	
+
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		if (!cards[i].typ)
 			break;
 	}
-	
+
 	if (i >= HISAX_MAX_CARDS)
 		return -EBUSY;
-	
-	nrcards++;
-
-	cs = alloc_IsdnCardState();
-	if (!cs)
-		return -ENOMEM;
-
-#if TEI_PER_CARD
-	if (protocol == ISDN_PTYPE_NI1)
-		test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
-	test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
-	cs->cardnr = i;
-	cs->protocol = protocol;
-	cs->typ = ISDN_CTYPE_DYNAMIC;
-
-	sprintf(cs->iif.id, "%s%d", name, i);
-	do_register_isdn(cs);
 
+	cards[i].typ = ISDN_CTYPE_DYNAMIC;
+	cards[i].protocol = protocol;
+	sprintf(id, "%s%d", name, i);
+	nrcards++;
+	retval = checkcard(i, id, 0, hisax_d_if->owner);
+	if (retval == 0) { // yuck
+		cards[i].typ = 0;
+		nrcards--;
+		return retval;
+	}
+	cs = cards[i].cs;
 	hisax_d_if->cs = cs;
 	cs->hw.hisax_d_if = hisax_d_if;
-	cs->iif.owner = hisax_d_if->owner;
-	dc_l1_init(cs, &hisax_l1_ops);
-	cs->bc_l1_ops = &hisax_bc_l1_ops;
-
+	cs->cardmsg = hisax_cardmsg;
+	INIT_WORK(&cs->tqueue, (void *)(void *)hisax_bh, cs);
+	cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
 	for (i = 0; i < 2; i++) {
+		cs->bcs[i].BC_SetStack = hisax_bc_setstack;
+		cs->bcs[i].BC_Close = hisax_bc_close;
+
 		b_if[i]->ifc.l1l2 = hisax_b_l1l2;
 
 		hisax_d_if->b_if[i] = b_if[i];
@@ -1762,8 +1610,6 @@
 	skb_queue_head_init(&hisax_d_if->erq);
 	clear_bit(0, &hisax_d_if->ph_state);
 	
-	do_init(cs);
-
 	return 0;
 }
 
@@ -1776,9 +1622,14 @@
 
 #include "isdnl1.h"
 
-static void hisax_bh(void *data)
+static void hisax_sched_event(struct IsdnCardState *cs, int event)
+{
+	test_and_set_bit(event, &cs->event);
+	schedule_work(&cs->tqueue);
+}
+
+static void hisax_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
 	struct PStack *st;
 	int pr;
 
@@ -1792,11 +1643,17 @@
 		else
 			pr = PH_DEACTIVATE | INDICATION;
 		for (st = cs->stlist; st; st = st->next)
-			L1L2(st, pr, NULL);
+			st->l1.l1l2(st, pr, NULL);
 		
 	}
 }
 
+static void hisax_b_sched_event(struct BCState *bcs, int event)
+{
+	test_and_set_bit(event, &bcs->event);
+	schedule_work(&bcs->tqueue);
+}
+
 static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg)
 {
 	struct hisax_if *ifc = (struct hisax_if *) d_if;
@@ -1819,15 +1676,15 @@
 	switch (pr) {
 	case PH_ACTIVATE | INDICATION:
 		set_bit(0, &d_if->ph_state);
-		sched_d_event(cs, D_L1STATECHANGE);
+		hisax_sched_event(cs, D_L1STATECHANGE);
 		break;
 	case PH_DEACTIVATE | INDICATION:
 		clear_bit(0, &d_if->ph_state);
-		sched_d_event(cs, D_L1STATECHANGE);
+		hisax_sched_event(cs, D_L1STATECHANGE);
 		break;
 	case PH_DATA | INDICATION:
 		skb_queue_tail(&cs->rq, arg);
-		sched_d_event(cs, D_RCVBUFREADY);
+		hisax_sched_event(cs, D_RCVBUFREADY);
 		break;
 	case PH_DATA | CONFIRM:
 		skb = skb_dequeue(&cs->sq);
@@ -1838,14 +1695,14 @@
 		clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 		for (st = cs->stlist; st; st = st->next) {
 			if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
-				L1L2(st, PH_PULL | CONFIRM, NULL);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 				break;
 			}
 		}
 		break;
 	case PH_DATA_E | INDICATION:
 		skb_queue_tail(&d_if->erq, arg);
-		sched_d_event(cs, E_RCVBUFREADY);
+		hisax_sched_event(cs, E_RCVBUFREADY);
 		break;
 	default:
 		printk("pr %#x\n", pr);
@@ -1863,22 +1720,27 @@
 	// FIXME use isdnl1?
 	switch (pr) {
 	case PH_ACTIVATE | INDICATION:
-		L1L2(st, pr, NULL);
+		st->l1.l1l2(st, pr, NULL);
 		break;
 	case PH_DEACTIVATE | INDICATION:
-		L1L2(st, pr, NULL);
+		st->l1.l1l2(st, pr, NULL);
 		clear_bit(BC_FLG_BUSY, &bcs->Flag);
 		skb_queue_purge(&bcs->squeue);
 		bcs->hw.b_if = NULL;
 		break;
 	case PH_DATA | INDICATION:
 		skb_queue_tail(&bcs->rqueue, arg);
-		sched_b_event(bcs, B_RCVBUFREADY);
+		hisax_b_sched_event(bcs, B_RCVBUFREADY);
 		break;
 	case PH_DATA | CONFIRM:
-		skb = arg;
-		bcs->tx_cnt -= skb->truesize;
-		xmit_complete_b(bcs);
+		bcs->tx_cnt -= (int) arg;
+		if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) {
+			u_long	flags;
+			spin_lock_irqsave(&bcs->aclock, flags);
+			bcs->ackcnt += (int) arg;
+			spin_unlock_irqrestore(&bcs->aclock, flags);
+			schedule_event(bcs, B_ACKPENDING);
+		}
 		skb = skb_dequeue(&bcs->squeue);
 		if (skb) {
 			B_L2L1(b_if, PH_DATA | REQUEST, skb);
@@ -1886,7 +1748,7 @@
 		}
 		clear_bit(BC_FLG_BUSY, &bcs->Flag);
 		if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
-			L1L2(st, PH_PULL | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 		}
 		break;
 	default:
@@ -1917,7 +1779,7 @@
 		break;
 	case PH_PULL | REQUEST:
 		if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			L1L2(st, PH_PULL | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 		else
 			set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
@@ -1927,6 +1789,11 @@
 	}
 }
 
+static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	return 0;
+}
+
 static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
 {
 	struct BCState *bcs = st->l1.bcs;
@@ -1947,7 +1814,7 @@
 		break;
 	case PH_PULL | REQUEST:
 		if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
-			L1L2(st, PH_PULL | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 		else
 			set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
@@ -1971,7 +1838,7 @@
 	hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
 
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hisax_b_l2l1;
+	st->l2.l2l1 = hisax_b_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -1991,7 +1858,7 @@
 static void EChannel_proc_rcv(struct hisax_d_if *d_if)
 {
 	struct IsdnCardState *cs = d_if->cs;
-	u8 *ptr;
+	u_char *ptr;
 	struct sk_buff *skb;
 
 	while ((skb = skb_dequeue(&d_if->erq)) != NULL) {
@@ -2017,103 +1884,9 @@
 	}
 }
 
-void
-resources_init(struct resources *rs)
-{
-	INIT_LIST_HEAD(&rs->res_head);
-}
-
-void
-resources_release(struct resources *rs)
-{
-	struct res *r;
-
-	list_for_each_entry(r, &rs->res_head, node) {
-		if (r->flags & IORESOURCE_IO) {
-			release_region(r->start, r->end - r->start + 1);
-		}
-		if (r->flags & IORESOURCE_MEM) {
-			iounmap(r->r_u.ioremap_addr);
-			release_mem_region(r->start, r->end - r->start + 1);
-		}
-	}
-}
-
-unsigned long
-request_io(struct resources *rs, unsigned long start, int len,
-	   const char *name)
-{
-	struct res *r;
-
-	r = kmalloc(sizeof(*r), GFP_KERNEL);
-	if (!r) {
-		printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
-		goto err;
-	}
-	if (!request_region(start, len, name)) {
-		printk(KERN_WARNING "%s: IO %#lx-%#lx already in use\n",
-		       __FUNCTION__, start, start + len - 1);
-		goto err_free;
-	}
-	r->flags = IORESOURCE_IO;
-	r->start = start;
-	r->end   = start + len - 1;
-	r->name  = name;
-	list_add_tail(&r->node, &rs->res_head);
-
-	return r->start;
-
- err_free:
-	kfree(r);
- err:
-	return 0;
-}
-
-void *
-request_mmio(struct resources *rs, unsigned long start, int len,
-	     const char *name)
-{
-	struct res *r;
-
-	r = kmalloc(sizeof(*r), GFP_KERNEL);
-	if (!r) {
-		printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
-		goto err;
-	}
-	if (!request_mem_region(start, len, name)) {
-		printk(KERN_WARNING "%s: MMIO %#lx-%#lx already in use\n",
-		       __FUNCTION__, start, start + len - 1);
-		goto err_free;
-	}
-	r->flags            = IORESOURCE_MEM;
-	r->start            = start;
-	r->end              = start + len - 1;
-	r->name             = name;
-	r->r_u.ioremap_addr = ioremap(start, len);
-	if (!r->r_u.ioremap_addr)
-		goto err_release;
-
-	list_add_tail(&r->node, &rs->res_head);
-
-	return r->r_u.ioremap_addr;
-
- err_release:
-	release_mem_region(r->start, r->end - r->start + 1);
- err_free:
-	kfree(r);
- err:
-	return 0;
-}
-
-void
-hisax_release_resources(struct IsdnCardState *cs)
-{
-	resources_release(&cs->rs);
-}
-
 #include <linux/pci.h>
 
-static struct pci_device_id hisax_pci_tbl[] = {
+static struct pci_device_id hisax_pci_tbl[] __initdata = {
 #ifdef CONFIG_HISAX_FRITZPCI
 	{PCI_VENDOR_ID_AVM,      PCI_DEVICE_ID_AVM_A1,           PCI_ANY_ID, PCI_ANY_ID},
 #endif
@@ -2121,7 +1894,9 @@
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20,     PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20_U,   PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA201,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA202,    PCI_ANY_ID, PCI_ANY_ID},
+//#########################################################################################	
 #endif
 #ifdef CONFIG_HISAX_ELSA
 	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK,   PCI_ANY_ID, PCI_ANY_ID},
--- diff/drivers/isdn/hisax/diva.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/diva.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.25.6.5 2001/09/23 22:24:47 kai Exp $
+/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $
  *
  * low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
@@ -28,8 +28,7 @@
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.25.6.5 $";
-static spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
+const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -82,376 +81,715 @@
 #endif
 #define PITA_INT0_STATUS	0x02
 
-static inline u8
-readreg(unsigned int ale, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&diva_lock, flags);
 	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&diva_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writereg(unsigned int ale, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&diva_lock, flags);
 	byteout(ale, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&diva_lock, flags);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
 	byteout(ale, off);
-	insb(adr, data, size);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(unsigned int ale, unsigned int adr, u8 off, u8 *data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
 {
 	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static inline u8
-memreadreg(unsigned long adr, u8 off)
+static inline u_char
+memreadreg(unsigned long adr, u_char off)
 {
-	return readb(((unsigned int *)adr) + off);
+	return(*((unsigned char *)
+		(((unsigned int *)adr) + off)));
 }
 
 static inline void
-memwritereg(unsigned long adr, u8 off, u8 data)
+memwritereg(unsigned long adr, u_char off, u_char data)
 {
-	writeb(data, ((unsigned int *)adr) + off);
+	register u_char *p;
+	
+	p = (unsigned char *)(((unsigned int *)adr) + off);
+	*p = data;
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset);
+	return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
 {
 	readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
 {
 	writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, 
-		       offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx,
-		 offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value);
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, hscx ? 0x40 : 0, data, size);
+	readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, hscx ? 0x40 : 0, data, size);
+	writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg  = hscx_read,
-	.write_reg = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset);
+	return(readreg(cs->hw.diva.hscx_adr,
+		cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-static inline void
-ipac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
+	writereg(cs->hw.diva.hscx_adr,
+		cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static u_char
+MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-	readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, data, size);
+	return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80));
 }
 
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static void
+MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, data, size);
+	memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value);
 }
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
-
-BUILD_IPAC_OPS(ipac);
-
-static inline u8
-mem_ipac_read(struct IsdnCardState *cs, u8 offset)
+static void
+MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	return memreadreg(cs->hw.diva.cfg_reg, offset);
+	while(size--)
+		*data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80);
 }
 
-static inline void
-mem_ipac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+static void
+MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	memwritereg(cs->hw.diva.cfg_reg, offset, value);
+	while(size--)
+		memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++);
 }
 
-static inline void
-mem_ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static u_char
+MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	while(size--)
-		*data++ = memreadreg(cs->hw.diva.cfg_reg, offset);
+	return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0)));
 }
 
-static inline void
-mem_ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static void
+MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	while(size--)
-		memwritereg(cs->hw.diva.cfg_reg, offset, *data++);
+	memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
 }
 
-/* This will generate mem_ipac_dc_ops and mem_ipac_bc_ops using the functions
- * above */
-
-BUILD_IPAC_OPS(mem_ipac);
-
 /* IO-Functions for IPACX type cards */
-static u8
-ipacx_dc_read(struct IsdnCardState *cs, u8 offset)
+static u_char
+MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
 {
-	return memreadreg(cs->hw.diva.cfg_reg, offset);
+	return (memreadreg(cs->hw.diva.cfg_reg, offset));
 }
 
 static void
-ipacx_dc_write(struct IsdnCardState *cs, u8 offset, u8 value)
+MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	memwritereg(cs->hw.diva.cfg_reg, offset, value);
 }
 
 static void
-ipacx_dc_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
+MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
 {
 	while(size--)
 		*data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
 }
 
 static void
-ipacx_dc_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
 {
 	while(size--)
 		memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
 }
 
-static struct dc_hw_ops ipacx_dc_ops = {
-	.read_reg   = ipacx_dc_read,
-	.write_reg  = ipacx_dc_write,
-	.read_fifo  = ipacx_dc_read_fifo,
-	.write_fifo = ipacx_dc_write_fifo,
-};
-
-static u8
-ipacx_bc_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return memreadreg(cs->hw.diva.cfg_reg, offset + 
-			  (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1));
+	return(memreadreg(cs->hw.diva.cfg_reg, offset + 
+                    (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
 }
 
 static void
-ipacx_bc_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
 	memwritereg(cs->hw.diva.cfg_reg, offset + 
               (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
 }
 
-static void
-ipacx_bc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int len)
-{
-	int i;
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-	for (i = 0; i < len ; i++)
-		*data++ = ipacx_bc_read(cs, hscx, IPACX_RFIFOB);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \
+		cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \
+                cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)
 
-static struct bc_hw_ops ipacx_bc_ops = {
-	.read_reg   = ipacx_bc_read,
-	.write_reg  = ipacx_bc_write,
-	.read_fifo  = ipacx_bc_read_fifo,
-};
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \
+		cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \
+		cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
 
 static irqreturn_t
 diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 sval;
+	u_char val, sval;
+	u_long flags;
 	int cnt=5;
 
+	spin_lock_irqsave(&cs->lock, flags);
 	while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) {
-		hscxisac_irq(intno, dev_id, regs);
+		val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40);
+		if (val)
+			hscx_int_main(cs, val);
+		val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
+		if (val)
+			isac_interrupt(cs, val);
+		cnt--;
 	}
 	if (!cnt)
 		printk(KERN_WARNING "Diva: IRQ LOOP\n");
+	writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0);
+	writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t
-diva_ipac_pci_irq(int intno, void *dev_id, struct pt_regs *regs)
+diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_char ista,val;
+	u_long flags;
+	int icnt=5;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
+Start_IPACISA:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val)
+			hscx_int_main(cs, val);
+	}
+	if (ista & 0x20) {
+		val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista  = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPACISA;
+	}
+	if (!icnt)
+		printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n");
+	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF);
+	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
 
-	val = readb(cs->hw.diva.pci_cfg);
-	if (!(val & PITA_INT0_STATUS))
-		return IRQ_NONE; /* other shared IRQ */
-	writeb(PITA_INT0_STATUS, cs->hw.diva.pci_cfg); /* Reset pending INT0 */
+static inline void
+MemwaitforCEC(struct IsdnCardState *cs, int hscx)
+{
+	int to = 50;
 
-	return ipac_irq(intno, dev_id, regs);
+	while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
 }
 
-static irqreturn_t
-diva_ipacx_pci_irq(int intno, void *dev_id, struct pt_regs *regs)
+
+static inline void
+MemwaitforXFW(struct IsdnCardState *cs, int hscx)
 {
-	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	int to = 50;
 
-	val = readb(cs->hw.diva.pci_cfg);
-	if (!(val &PITA_INT0_STATUS))
-		return IRQ_NONE; // other shared IRQ
-	interrupt_ipacx(cs);      // handler for chip
-	writeb(PITA_INT0_STATUS, cs->hw.diva.pci_cfg);  // Reset PLX interrupt
-	return IRQ_HANDLED;
+	while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
 }
 
-static void
-diva_release(struct IsdnCardState *cs)
+static inline void
+MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
 {
-	del_timer_sync(&cs->hw.diva.tl);
-	if (cs->hw.diva.cfg_reg)
-		byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
+	MemwaitforCEC(cs, hscx);
+	MemWriteHSCX(cs, hscx, HSCX_CMDR, data);
+}
 
-	hisax_release_resources(cs);
+static void
+Memhscx_empty_fifo(struct BCState *bcs, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *cs = bcs->cs;
+	int cnt;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hscx_empty_fifo");
+
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "hscx_empty_fifo: incoming packet too large");
+		MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	cnt = count;
+	while (cnt--)
+		*ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0);
+	MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static void
-diva_ipac_pci_release(struct IsdnCardState *cs)
+Memhscx_fill_fifo(struct BCState *bcs)
 {
-	writel(0, cs->hw.diva.pci_cfg); /* disable INT0/1 */ 
-	writel(2, cs->hw.diva.pci_cfg); /* reset pending INT0 */
-	hisax_release_resources(cs);
+	struct IsdnCardState *cs = bcs->cs;
+	int more, count, cnt;
+	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+	u_char *ptr,*p;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hscx_fill_fifo");
+
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
+		return;
+
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > fifo_size) {
+		more = !0;
+		count = fifo_size;
+	} else
+		count = bcs->tx_skb->len;
+	cnt = count;
+	MemwaitforXFW(cs, bcs->hw.hscx.hscx);
+	p = ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	while(cnt--)
+		memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0,
+			*p++);
+	MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
-static int
-diva_ipac_isa_reset(struct IsdnCardState *cs)
+static inline void
+Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
-	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
-	return 0;
+	u_char r;
+	struct BCState *bcs = cs->bcs + hscx;
+	struct sk_buff *skb;
+	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+	int count;
+
+	if (!test_bit(BC_FLG_INIT, &bcs->Flag))
+		return;
+
+	if (val & 0x80) {	/* RME */
+		r = MemReadHSCX(cs, hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!(r & 0x80))
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX invalid frame");
+			if ((r & 0x40) && bcs->mode)
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX RDO mode=%d",
+						bcs->mode);
+			if (!(r & 0x20))
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX CRC error");
+			MemWriteHSCXCMDR(cs, hscx, 0x80);
+		} else {
+			count = MemReadHSCX(cs, hscx, HSCX_RBCL) & (
+				test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
+			if (count == 0)
+				count = fifo_size;
+			Memhscx_empty_fifo(bcs, count);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug & L1_DEB_HSCX_FIFO)
+					debugl1(cs, "HX Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HSCX: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
+		}
+		bcs->hw.hscx.rcvidx = 0;
+		schedule_event(bcs, B_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		Memhscx_empty_fifo(bcs, fifo_size);
+		if (bcs->mode == L1_MODE_TRANS) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(fifo_size)))
+				printk(KERN_WARNING "HiSax: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			schedule_event(bcs, B_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				Memhscx_fill_fifo(bcs);
+				return;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.hscx.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_irq(bcs->tx_skb);
+				bcs->hw.hscx.count = 0; 
+				bcs->tx_skb = NULL;
+			}
+		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.hscx.count = 0;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			Memhscx_fill_fifo(bcs);
+		} else {
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
+	}
 }
 
-static int
-diva_ipac_pci_reset(struct IsdnCardState *cs)
+static inline void
+Memhscx_int_main(struct IsdnCardState *cs, u_char val)
+{
+
+	u_char exval;
+	struct BCState *bcs;
+
+	if (val & 0x01) { // EXB
+		bcs = cs->bcs + 1;
+		exval = MemReadHSCX(cs, 1, HSCX_EXIR);
+		if (exval & 0x40) {
+			if (bcs->mode == 1)
+				Memhscx_fill_fifo(bcs);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (bcs->tx_skb) {
+					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+					bcs->tx_cnt += bcs->hw.hscx.count;
+					bcs->hw.hscx.count = 0;
+				}
+				MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
+			}
+		} else if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX B EXIR %x", exval);
+	}
+	if (val & 0xf8) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX B interrupt %x", val);
+		Memhscx_interrupt(cs, val, 1);
+	}
+	if (val & 0x02) {	// EXA
+		bcs = cs->bcs;
+		exval = MemReadHSCX(cs, 0, HSCX_EXIR);
+		if (exval & 0x40) {
+			if (bcs->mode == L1_MODE_TRANS)
+				Memhscx_fill_fifo(bcs);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (bcs->tx_skb) {
+					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+					bcs->tx_cnt += bcs->hw.hscx.count;
+					bcs->hw.hscx.count = 0;
+				}
+				MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
+			}
+		} else if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX A EXIR %x", exval);
+	}
+	if (val & 0x04) {	// ICA
+		exval = MemReadHSCX(cs, 0, HSCX_ISTA);
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX A interrupt %x", exval);
+		Memhscx_interrupt(cs, exval, 0);
+	}
+}
+
+static irqreturn_t
+diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs)
 {
-	unsigned long misc_reg = cs->hw.diva.pci_cfg + PITA_MISC_REG;
+	struct IsdnCardState *cs = dev_id;
+	u_char ista,val;
+	int icnt=5;
+	u_char *cfg;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	cfg = (u_char *) cs->hw.diva.pci_cfg;
+	val = *cfg;
+	if (!(val & PITA_INT0_STATUS)) {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE; /* other shared IRQ */
+	}
+	*cfg = PITA_INT0_STATUS; /* Reset pending INT0 */
+	ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
+Start_IPACPCI:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val)
+			Memhscx_int_main(cs, val);
+	}
+	if (ista & 0x20) {
+		val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista  = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPACPCI;
+	}
+	if (!icnt)
+		printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n");
+	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF);
+	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
 
-	writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, misc_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writel(PITA_PARA_MPX_MODE, misc_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
-	return 0;
+static irqreturn_t
+diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_char *cfg;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	cfg = (u_char *) cs->hw.diva.pci_cfg;
+	val = *cfg;
+	if (!(val &PITA_INT0_STATUS)) {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE; // other shared IRQ
+	}
+ 	interrupt_ipacx(cs);      // handler for chip
+	*cfg = PITA_INT0_STATUS;  // Reset PLX interrupt
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
-static int
-diva_ipacx_pci_reset(struct IsdnCardState *cs)
+void
+release_io_diva(struct IsdnCardState *cs)
 {
-	unsigned long misc_reg = cs->hw.diva.pci_cfg + PITA_MISC_REG;
+	int bytecnt;
 
-	writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, misc_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, misc_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	ipacx_dc_write(cs, IPACX_MASK, 0xff); // Interrupts off
-	return 0;
+	if ((cs->subtyp == DIVA_IPAC_PCI) || 
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+		u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
+
+		*cfg = 0; /* disable INT0/1 */ 
+		*cfg = 2; /* reset pending INT0 */
+		iounmap((void *)cs->hw.diva.cfg_reg);
+		iounmap((void *)cs->hw.diva.pci_cfg);
+		return;
+	} else if (cs->subtyp != DIVA_IPAC_ISA) {
+		del_timer(&cs->hw.diva.tl);
+		if (cs->hw.diva.cfg_reg)
+			byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
+	}
+	if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+		bytecnt = 8;
+	else
+		bytecnt = 32;
+	if (cs->hw.diva.cfg_reg) {
+		release_region(cs->hw.diva.cfg_reg, bytecnt);
+	}
 }
 
-static int
-diva_reset(struct IsdnCardState *cs)
+static void
+reset_diva(struct IsdnCardState *cs)
 {
-	/* DIVA 2.0 */
-	cs->hw.diva.ctrl_reg = 0;        /* Reset On */
-	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
-	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	if (cs->subtyp == DIVA_ISA) {
-		cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
-	} else {
-		/* Workaround PCI9060 */
-		byteout(cs->hw.diva.pci_cfg + 0x69, 9);
-		cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
+	if (cs->subtyp == DIVA_IPAC_ISA) {
+		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
+		mdelay(10);
+		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
+		mdelay(10);
+		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
+	} else if (cs->subtyp == DIVA_IPAC_PCI) {
+		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+					PITA_MISC_REG);
+		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+		mdelay(10);
+		*ireg = PITA_PARA_MPX_MODE;
+		mdelay(10);
+		memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+					PITA_MISC_REG);
+		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+		mdelay(10);
+		*ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
+		mdelay(10);
+		MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
+	} else { /* DIVA 2.0 */
+		cs->hw.diva.ctrl_reg = 0;        /* Reset On */
+		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+		mdelay(10);
+		cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
+		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+		mdelay(10);
+		if (cs->subtyp == DIVA_ISA)
+			cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
+		else {
+			/* Workaround PCI9060 */
+			byteout(cs->hw.diva.pci_cfg + 0x69, 9);
+			cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
+		}
+		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
 	}
-	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-	return 0;
 }
 
+#define DIVA_ASSIGN 1
+
 static void
 diva_led_handler(struct IsdnCardState *cs)
 {
 	int blink = 0;
 
-	if (cs->status & 0x0001)
+	if ((cs->subtyp == DIVA_IPAC_ISA) ||
+	    (cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   )
+		return;
+	del_timer(&cs->hw.diva.tl);
+	if (cs->hw.diva.status & DIVA_ASSIGN)
 		cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
 			DIVA_ISA_LED_A : DIVA_PCI_LED_A;
 	else {
@@ -459,10 +797,10 @@
 			DIVA_ISA_LED_A : DIVA_PCI_LED_A;
 		blink = 250;
 	}
-	if (cs->status & 0xf000)
+	if (cs->hw.diva.status & 0xf000)
 		cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
 			DIVA_ISA_LED_B : DIVA_PCI_LED_B;
-	else if (cs->status & 0x0f00) {
+	else if (cs->hw.diva.status & 0x0f00) {
 		cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
 			DIVA_ISA_LED_B : DIVA_PCI_LED_B;
 		blink = 500;
@@ -471,212 +809,90 @@
 			DIVA_ISA_LED_B : DIVA_PCI_LED_B);
 
 	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-	if (blink)
-		mod_timer(&cs->hw.diva.tl, jiffies + (blink * HZ) / 1000);
-}
-
-static void
-diva_ipacx_pci_init(struct IsdnCardState *cs)
-{
-	writel(PITA_INT0_ENABLE, cs->hw.diva.pci_cfg);
-	init_ipacx(cs, 3); // init chip and enable interrupts
-}
-
-static void
-diva_ipac_pci_init(struct IsdnCardState *cs)
-{
-	writel(PITA_INT0_ENABLE, cs->hw.diva.pci_cfg);
-	ipac_init(cs);
-}
-
-static struct card_ops diva_ops = {
-	.init        = inithscxisac,
-	.reset       = diva_reset,
-	.release     = diva_release,
-	.led_handler = diva_led_handler,
-	.irq_func    = diva_interrupt,
-};
-
-static struct card_ops diva_ipac_isa_ops = {
-	.init        = ipac_init,
-	.reset       = diva_ipac_isa_reset,
-	.release     = hisax_release_resources,
-	.irq_func    = ipac_irq,
-};
-
-static struct card_ops diva_ipac_pci_ops = {
-	.init        = diva_ipac_pci_init,
-	.reset       = diva_ipac_pci_reset,
-	.release     = diva_ipac_pci_release,
-	.irq_func    = diva_ipac_pci_irq,
-};
-
-static struct card_ops diva_ipacx_pci_ops = {
-	.init        = diva_ipacx_pci_init,
-	.reset       = diva_ipacx_pci_reset,
-	.release     = diva_ipac_pci_release,
-	.irq_func    = diva_ipacx_pci_irq,
-};
-
-static int __init
-diva_ipac_probe(struct IsdnCardState *cs)
-{
-	u8 val;
-
-	// request_io
-	val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
-		      cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
-	printk(KERN_INFO "Diva: IPAC version %x\n", val);
-	return (val == 1 || val == 2);
-}
-
-static int __init
-diva_ipac_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = DIVA_IPAC_ISA;
-	cs->irq = card->para[0];
-	cs->hw.diva.cfg_reg  = card->para[1];
-	cs->hw.diva.isac     = card->para[1] + DIVA_IPAC_DATA;
-	cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
-	printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n",
-	       "IPAC ISA", cs->hw.diva.cfg_reg, cs->irq);
-	if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn"))
-		goto err;
-	diva_ipac_isa_reset(cs);
-	cs->card_ops = &diva_ipac_isa_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-diva_isac_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = DIVA_ISA;
-	cs->irq = card->para[0];
-	cs->hw.diva.cfg_reg  = card->para[1];
-	cs->hw.diva.ctrl     = card->para[1] + DIVA_ISA_CTRL;
-	cs->hw.diva.isac     = card->para[1] + DIVA_ISA_ISAC_DATA;
-	cs->hw.diva.hscx     = card->para[1] + DIVA_HSCX_DATA;
-	cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-	cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
-	printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n",
-	       "ISA", cs->hw.diva.cfg_reg, cs->irq);
-	if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn"))
-		goto err;
-	diva_reset(cs);
-	init_timer(&cs->hw.diva.tl);
-	cs->hw.diva.tl.function = (void *) diva_led_handler;
-	cs->hw.diva.tl.data = (long) cs;
-	cs->card_ops = &diva_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-diva_isa_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	int is_ipac;
-	cs->hw.diva.cfg_reg  = card->para[1];
-	if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 8, "diva isdn"))
-		return -EBUSY;
-
-	is_ipac = diva_ipac_probe(cs);
-	hisax_release_resources(cs);
-
-	if (is_ipac)
-		return diva_ipac_isa_probe(cs, card);
-	else
-		return diva_isac_isa_probe(cs, card);
+	if (blink) {
+		init_timer(&cs->hw.diva.tl);
+		cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000);
+		add_timer(&cs->hw.diva.tl);
+	}
 }
 
-static int __init
-diva_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
+static int
+Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	if (pci_enable_device(pdev))
-		goto err;
+	u_int *ireg;
+	u_long flags;
 
-	cs->subtyp = DIVA_PCI;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.diva.cfg_reg  = pci_resource_start(pdev, 2);
-	cs->hw.diva.ctrl     = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
-	cs->hw.diva.isac     = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
-	cs->hw.diva.hscx     = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
-	cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
-	cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
-	printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n",
-	       "PCI", cs->hw.diva.cfg_reg, cs->irq);
-	printk(KERN_INFO "Diva: %s space at %#lx\n",
-	       "PCI", cs->hw.diva.pci_cfg);
-	if (!request_io(&cs->rs, cs->hw.diva.cfg_reg, 32, "diva isdn"))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-diva_ipac_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = DIVA_IPAC_PCI;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.diva.pci_cfg = (unsigned long)request_mmio(
-		&cs->rs, pci_resource_start(pdev, 0), 4096, "diva");
-	cs->hw.diva.cfg_reg = (unsigned long)request_mmio(
-		&cs->rs, pci_resource_start(pdev, 1), 4096, "diva");
-	printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n",
-	       "IPAC PCI", cs->hw.diva.cfg_reg, cs->irq);
-	printk(KERN_INFO "Diva: %s space at %#lx\n",
-	       "IPAC PCI", cs->hw.diva.pci_cfg);
-	diva_ipac_pci_reset(cs);
-	cs->card_ops = &diva_ipac_pci_ops;
-	if (ipac_setup(cs, &mem_ipac_dc_ops, &mem_ipac_bc_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-diva_ipacx_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = DIVA_IPACX_PCI;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n",
-	       "IPACX PCI", cs->hw.diva.cfg_reg, cs->irq);
-	printk(KERN_INFO "Diva: %s space at %#lx\n",
-	       "IPACX PCI", cs->hw.diva.pci_cfg);
-	diva_ipacx_pci_reset(cs);
-	cs->card_ops = &diva_ipacx_pci_ops;
-	if (ipacx_setup(cs, &ipacx_dc_ops, &ipacx_bc_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_diva(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_diva(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_diva(cs);
+			if (cs->subtyp == DIVA_IPACX_PCI) {
+				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+				*ireg = PITA_INT0_ENABLE;
+				init_ipacx(cs, 3); // init chip and enable interrupts
+				spin_unlock_irqrestore(&cs->lock, flags);
+				return (0);
+			}
+			if (cs->subtyp == DIVA_IPAC_PCI) {
+				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+				*ireg = PITA_INT0_ENABLE;
+			}
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+		case (MDL_REMOVE | REQUEST):
+			cs->hw.diva.status = 0;
+			break;
+		case (MDL_ASSIGN | REQUEST):
+			cs->hw.diva.status |= DIVA_ASSIGN;
+			break;
+		case MDL_INFO_SETUP:
+			if ((long)arg)
+				cs->hw.diva.status |=  0x0200;
+			else
+				cs->hw.diva.status |=  0x0100;
+			break;
+		case MDL_INFO_CONN:
+			if ((long)arg)
+				cs->hw.diva.status |=  0x2000;
+			else
+				cs->hw.diva.status |=  0x1000;
+			break;
+		case MDL_INFO_REL:
+			if ((long)arg) {
+				cs->hw.diva.status &=  ~0x2000;
+				cs->hw.diva.status &=  ~0x0200;
+			} else {
+				cs->hw.diva.status &=  ~0x1000;
+				cs->hw.diva.status &=  ~0x0100;
+			}
+			break;
+	}
+	if ((cs->subtyp != DIVA_IPAC_ISA) && 
+	    (cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)) {
+	    	spin_lock_irqsave(&cs->lock, flags);
+		diva_led_handler(cs);
+		spin_unlock_irqrestore(&cs->lock, flags);
+	}
+	return(0);
 }
 
 static struct pci_dev *dev_diva __initdata = NULL;
 static struct pci_dev *dev_diva_u __initdata = NULL;
 static struct pci_dev *dev_diva201 __initdata = NULL;
+static struct pci_dev *dev_diva202 __initdata = NULL;
+
 #ifdef __ISAPNP__
 static struct isapnp_device_id diva_ids[] __initdata = {
 	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
@@ -700,99 +916,268 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *pdev = &diva_ids[0];
+static struct isapnp_device_id *ipid __initdata = &diva_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
+
 int __init
 setup_diva(struct IsdnCard *card)
 {
+	int bytecnt = 8;
+	u_char val;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, Diva_revision);
 	printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+		return(0);
+	cs->hw.diva.status = 0;
 	if (card->para[1]) {
-		if (diva_isa_probe(card->cs, card) < 0)
-			return 0;
-		return 1;
-		
-	}
+		cs->hw.diva.ctrl_reg = 0;
+		cs->hw.diva.cfg_reg = card->para[1];
+		val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+			cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+		if ((val == 1) || (val==2)) {
+			cs->subtyp = DIVA_IPAC_ISA;
+			cs->hw.diva.ctrl = 0;
+			cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+			cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+			cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+			cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+		} else {
+			cs->subtyp = DIVA_ISA;
+			cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+			cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+			cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+			cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+		}
+		cs->irq = card->para[0];
+	} else {
 #ifdef __ISAPNP__
-	if (isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
-		
-		while(pdev->card_vendor) {
-			if ((pb = pnp_find_card(pdev->card_vendor,
-						pdev->card_device, pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       pdev->vendor,
-						       pdev->function,
-						       pd))) {
-					printk(KERN_INFO "HiSax: %s detected\n",
-					       (char *)pdev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "Diva PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "Diva PnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
-					}
-					if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) {
-						printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
-						       pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
-						return(0);
-					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
-					if (pdev->function == ISAPNP_FUNCTION(0xA1)) {
-						if (diva_ipac_isa_probe(card->cs, card))
-							return 0;
-						return 1;
+		if (isapnp_present()) {
+			struct pnp_dev *pnp_d;
+			while(ipid->card_vendor) {
+				if ((pnp_c = pnp_find_card(ipid->card_vendor,
+					ipid->card_device, pnp_c))) {
+					pnp_d = NULL;
+					if ((pnp_d = pnp_find_dev(pnp_c,
+						ipid->vendor, ipid->function, pnp_d))) {
+						int err;
+
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)ipid->driver_data);
+						pnp_disable_dev(pnp_d);
+						err = pnp_activate_dev(pnp_d);
+						if (err<0) {
+							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+								__FUNCTION__, err);
+							return(0);
+						}
+						card->para[1] = pnp_port_start(pnp_d, 0);
+						card->para[0] = pnp_irq(pnp_d, 0);
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pnp_disable_dev(pnp_d); 
+							return(0);
+						}
+						cs->hw.diva.cfg_reg  = card->para[1];
+						cs->irq = card->para[0];
+						if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+							cs->subtyp = DIVA_IPAC_ISA;
+							cs->hw.diva.ctrl = 0;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+						} else {
+							cs->subtyp = DIVA_ISA;
+							cs->hw.diva.ctrl =
+								card->para[1] + DIVA_ISA_CTRL;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_ISA_ISAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_HSCX_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_ISA_ISAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_HSCX_ADR;
+						}
+						goto ready;
 					} else {
-						if (diva_isac_isa_probe(card->cs, card))
-							return 0;
-						return 1;
+						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+						return(0);
 					}
-				} else {
-					printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
-					return(0);
 				}
-				pdev++;
+				ipid++;
 				pnp_c=NULL;
 			} 
-			if (!pdev->card_vendor) {
+			if (!ipid->card_vendor) {
 				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
 			}
 		}
-	}
 #endif
-#ifdef CONFIG_PCI
-	if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
-					PCI_DEVICE_ID_EICON_DIVA20,
-					dev_diva))) {
-		if (diva_pci_probe(card->cs, dev_diva))
-			return 0;
-		return 1;
-	} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
-						 PCI_DEVICE_ID_EICON_DIVA20_U,
-						 dev_diva_u))) {
-		if (diva_pci_probe(card->cs, dev_diva_u))
-			return 0;
-		return 1;
-	} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
-						  PCI_DEVICE_ID_EICON_DIVA201,
-						  dev_diva201))) {
-		if (diva_ipac_pci_probe(card->cs, dev_diva201))
-			return 0;
-		return 1;
-	}
-	printk(KERN_WARNING "Diva: No PCI card found\n");
+#if CONFIG_PCI
+		cs->subtyp = 0;
+		if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+			if (pci_enable_device(dev_diva))
+				return(0);
+			cs->subtyp = DIVA_PCI;
+			cs->irq = dev_diva->irq;
+			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+			if (pci_enable_device(dev_diva_u))
+				return(0);
+			cs->subtyp = DIVA_PCI;
+			cs->irq = dev_diva_u->irq;
+			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+		} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+			if (pci_enable_device(dev_diva201))
+				return(0);
+			cs->subtyp = DIVA_IPAC_PCI;
+			cs->irq = dev_diva201->irq;
+			cs->hw.diva.pci_cfg =
+				(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+			cs->hw.diva.cfg_reg =
+				(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+		} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+			if (pci_enable_device(dev_diva202))
+				return(0);
+			cs->subtyp = DIVA_IPACX_PCI;
+			cs->irq = dev_diva202->irq;
+			cs->hw.diva.pci_cfg =
+				(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+			cs->hw.diva.cfg_reg =
+				(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+		} else {
+			printk(KERN_WARNING "Diva: No PCI card found\n");
+			return(0);
+		}
+
+		if (!cs->irq) {
+			printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+			return(0);
+		}
+
+		if (!cs->hw.diva.cfg_reg) {
+			printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+			return(0);
+		}
+		cs->irq_flags |= SA_SHIRQ;
+#else
+		printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
+		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
+		return (0);
 #endif /* CONFIG_PCI */
-	return 0;
+		if ((cs->subtyp == DIVA_IPAC_PCI) ||
+		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+			cs->hw.diva.ctrl = 0;
+			cs->hw.diva.isac = 0;
+			cs->hw.diva.hscx = 0;
+			cs->hw.diva.isac_adr = 0;
+			cs->hw.diva.hscx_adr = 0;
+			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+			bytecnt = 0;
+		} else {
+			cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+			cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+			cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+			cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+			cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+			bytecnt = 32;
+		}
+	}
+ready:
+	printk(KERN_INFO
+		"Diva: %s card configured at %#lx IRQ %d\n",
+		(cs->subtyp == DIVA_PCI) ? "PCI" :
+		(cs->subtyp == DIVA_ISA) ? "ISA" : 
+		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
+		(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
+		cs->hw.diva.cfg_reg, cs->irq);
+	if ((cs->subtyp == DIVA_IPAC_PCI)  || 
+	    (cs->subtyp == DIVA_IPACX_PCI) || 
+	    (cs->subtyp == DIVA_PCI)         )
+		printk(KERN_INFO "Diva: %s space at %#lx\n",
+			(cs->subtyp == DIVA_PCI) ? "PCI" :
+			(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
+			cs->hw.diva.pci_cfg);
+	if ((cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   ) {
+		if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
+			printk(KERN_WARNING
+			       "HiSax: %s config port %lx-%lx already in use\n",
+			       CardType[card->typ],
+			       cs->hw.diva.cfg_reg,
+			       cs->hw.diva.cfg_reg + bytecnt);
+			return (0);
+		}
+	}
+	cs->BC_Read_Reg  = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Diva_card_msg;
+	setup_isac(cs);
+	if (cs->subtyp == DIVA_IPAC_ISA) {
+		cs->readisac  = &ReadISAC_IPAC;
+		cs->writeisac = &WriteISAC_IPAC;
+		cs->readisacfifo  = &ReadISACfifo_IPAC;
+		cs->writeisacfifo = &WriteISACfifo_IPAC;
+		cs->irq_func = &diva_irq_ipac_isa;
+		val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID);
+		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	} else if (cs->subtyp == DIVA_IPAC_PCI) {
+		cs->readisac  = &MemReadISAC_IPAC;
+		cs->writeisac = &MemWriteISAC_IPAC;
+		cs->readisacfifo  = &MemReadISACfifo_IPAC;
+		cs->writeisacfifo = &MemWriteISACfifo_IPAC;
+		cs->BC_Read_Reg  = &MemReadHSCX;
+		cs->BC_Write_Reg = &MemWriteHSCX;
+		cs->BC_Send_Data = &Memhscx_fill_fifo;
+		cs->irq_func = &diva_irq_ipac_pci;
+		val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
+		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		cs->readisac  = &MemReadISAC_IPACX;
+		cs->writeisac = &MemWriteISAC_IPACX;
+		cs->readisacfifo  = &MemReadISACfifo_IPACX;
+		cs->writeisacfifo = &MemWriteISACfifo_IPACX;
+		cs->BC_Read_Reg  = &MemReadHSCX_IPACX;
+		cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
+		cs->BC_Send_Data = 0; // function located in ipacx module
+		cs->irq_func = &diva_irq_ipacx_pci;
+		printk(KERN_INFO "Diva: IPACX Design Id: %x\n", 
+			MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
+	} else { /* DIVA 2.0 */
+		cs->hw.diva.tl.function = (void *) diva_led_handler;
+		cs->hw.diva.tl.data = (long) cs;
+		init_timer(&cs->hw.diva.tl);
+		cs->readisac  = &ReadISAC;
+		cs->writeisac = &WriteISAC;
+		cs->readisacfifo  = &ReadISACfifo;
+		cs->writeisacfifo = &WriteISACfifo;
+		cs->irq_func = &diva_interrupt;
+		ISACVersion(cs, "Diva:");
+		if (HscxVersion(cs, "Diva:")) {
+			printk(KERN_WARNING
+		       "Diva: wrong HSCX versions check IO address\n");
+			release_io_diva(cs);
+			return (0);
+		}
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/elsa.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/elsa.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 2.26.6.6 2001/09/23 22:24:47 kai Exp $
+/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $
  *
  * low level stuff for Elsa isdn cards
  *
@@ -32,9 +32,8 @@
 #include <linux/serial_reg.h>
 
 extern const char *CardType[];
-static spinlock_t elsa_lock = SPIN_LOCK_UNLOCKED;
 
-const char *Elsa_revision = "$Revision: 2.26.6.6 $";
+const char *Elsa_revision = "$Revision: 2.32.2.4 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
  "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", 
@@ -106,6 +105,7 @@
 /* Status Flags */
 #define ELSA_TIMER_AKTIV 1
 #define ELSA_BAD_PWR     2
+#define ELSA_ASSIGN      4
 
 #define RS_ISR_PASS_LIMIT 256
 #define _INLINE_ inline
@@ -141,163 +141,123 @@
 #include "elsa_ser.c"
 #endif /* ARCOFI_USE */
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&elsa_lock, flags);
-	byteout(cs->hw.elsa.ale, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&elsa_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&elsa_lock, flags);
-	byteout(cs->hw.elsa.ale, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&elsa_lock, flags);
+	byteout(ale, off);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.elsa.ale, off);
-	insb(adr, data, size);
+	byteout(ale, off);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.elsa.ale, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.elsa.isac, offset);
+	return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.elsa.isac, offset, value);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.elsa.isac, 0, data, size);
+	readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.elsa.isac, 0, data, size);
+	writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.elsa.hscx, hscx ? 0x40 : 0, data, size);
+	readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	writefifo(cs, cs->hw.elsa.hscx, hscx ? 0x40 : 0, data, size);
-}
-
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 offset)
-{
-	return readreg(cs, cs->hw.elsa.isac, offset);
-}
-
-static inline void
-ipac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writereg(cs, cs->hw.elsa.isac, offset, value);
+	writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
-static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	readfifo(cs, cs->hw.elsa.isac, offset, data, size);
+	return (readreg(cs->hw.elsa.ale,
+			cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writefifo(cs, cs->hw.elsa.isac, offset, data, size);
+	writereg(cs->hw.elsa.ale,
+		 cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
-
-BUILD_IPAC_OPS(ipac);
-
-static inline u8
-readitac(struct IsdnCardState *cs, u8 off)
+static inline u_char
+readitac(struct IsdnCardState *cs, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&elsa_lock, flags);
 	byteout(cs->hw.elsa.ale, off);
 	ret = bytein(cs->hw.elsa.itac);
-	spin_unlock_irqrestore(&elsa_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writeitac(struct IsdnCardState *cs, u8 off, u8 data)
+writeitac(struct IsdnCardState *cs, u_char off, u_char data)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&elsa_lock, flags);
 	byteout(cs->hw.elsa.ale, off);
 	byteout(cs->hw.elsa.itac, data);
-	spin_unlock_irqrestore(&elsa_lock, flags);
 }
 
 static inline int
 TimerRun(struct IsdnCardState *cs)
 {
-	register u8 v;
+	register u_char v;
 
 	v = bytein(cs->hw.elsa.cfg);
 	if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
@@ -306,12 +266,30 @@
 		return (v & ELSA_TIMER_RUN_PCC8);
 	return (v & ELSA_TIMER_RUN);
 }
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
+		cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
+		cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
+		cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
+		cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
 
 static irqreturn_t
 elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_long flags;
+	u_char val;
+	int icnt=5;
 
 	if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) {
 	/* The card tends to generate interrupts while being removed
@@ -319,19 +297,45 @@
 		printk(KERN_WARNING "Elsa: card not available!\n");
 		return IRQ_NONE;
 	}
+	spin_lock_irqsave(&cs->lock, flags);
 #if ARCOFI_USE
 	if (cs->hw.elsa.MFlag) {
 		val = serial_inp(cs, UART_IIR);
 		if (!(val & UART_IIR_NO_INT)) {
 			debugl1(cs,"IIR %02x", val);
-			spin_lock(&cs->lock);
 			rs_interrupt_elsa(intno, cs);
-			spin_unlock(&cs->lock);
 		}
 	}
 #endif
-	hscxisac_irq(intno, dev_id, regs);
-
+	val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val) {
+		hscx_int_main(cs, val);
+	}
+	val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val) {
+		isac_interrupt(cs, val);
+	}
+	val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+	if (val && icnt) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		icnt--;
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+	if (val && icnt) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		icnt--;
+		goto Start_ISAC;
+	}
+	if (!icnt)
+		printk(KERN_WARNING"ELSA IRQ LOOP\n");
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
 	if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
 		if (!TimerRun(cs)) {
 			/* Timer Restart */
@@ -351,6 +355,10 @@
 #endif
 	if (cs->hw.elsa.trig)
 		byteout(cs->hw.elsa.trig, 0x00);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -358,35 +366,70 @@
 elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_long flags;
+	u_char ista,val;
+	int icnt=5;
 
-	if (!cs) {
-		printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
-		return IRQ_NONE;
-	}
+	spin_lock_irqsave(&cs->lock, flags);
 	if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) {
 		val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
-		if (!test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags) && 
-		    !(val & ELSA_PCI_IRQ_MASK))
+		if (!(val & ELSA_PCI_IRQ_MASK)) {
+			spin_unlock_irqrestore(&cs->lock, flags);
 			return IRQ_NONE;
+		}
 	}
 #if ARCOFI_USE
 	if (cs->hw.elsa.MFlag) {
 		val = serial_inp(cs, UART_IIR);
 		if (!(val & UART_IIR_NO_INT)) {
 			debugl1(cs,"IIR %02x", val);
-			spin_lock(&cs->lock);
 			rs_interrupt_elsa(intno, cs);
-			spin_unlock(&cs->lock);
 		}
 	}
 #endif
-	return ipac_irq(intno, dev_id, regs);
+	ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+Start_IPAC:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val)
+			hscx_int_main(cs, val);
+	}
+	if (ista & 0x20) {
+		val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista  = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPAC;
+	}
+	if (!icnt)
+		printk(KERN_WARNING "ELSA IRQ LOOP\n");
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
+	writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
-static void
-elsa_release(struct IsdnCardState *cs)
+void
+release_io_elsa(struct IsdnCardState *cs)
 {
+	int bytecnt = 8;
+
 	del_timer(&cs->hw.elsa.tl);
 #if ARCOFI_USE
 	clear_arcofi(cs);
@@ -395,28 +438,33 @@
 		byteout(cs->hw.elsa.ctrl, 0);	/* LEDs Out */
 	if (cs->subtyp == ELSA_QS1000PCI) {
 		byteout(cs->hw.elsa.cfg + 0x4c, 0x01);  /* disable IRQ */
-		writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		bytecnt = 2;
+		release_region(cs->hw.elsa.cfg, 0x80);
 	}
 	if (cs->subtyp == ELSA_QS3000PCI) {
 		byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */
-		writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		release_region(cs->hw.elsa.cfg, 0x80);
 	}
  	if (cs->subtyp == ELSA_PCMCIA_IPAC) {
-		writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
  	}
-#if ARCOFI_USE
 	if ((cs->subtyp == ELSA_PCFPRO) ||
 		(cs->subtyp == ELSA_QS3000) ||
 		(cs->subtyp == ELSA_PCF) ||
 		(cs->subtyp == ELSA_QS3000PCI)) {
+		bytecnt = 16;
+#if ARCOFI_USE
 		release_modem(cs);
-	}
 #endif
-	hisax_release_resources(cs);
+	}
+	if (cs->hw.elsa.base)
+		release_region(cs->hw.elsa.base, bytecnt);
 }
 
-static int
-elsa_reset(struct IsdnCardState *cs)
+static void
+reset_elsa(struct IsdnCardState *cs)
 {
 	if (cs->hw.elsa.timer) {
 		/* Wait 1 Timer */
@@ -437,28 +485,25 @@
 			byteout(cs->hw.elsa.trig, 0xff);
 	}
 	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
-		writereg(cs, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
-		writereg(cs, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		writereg(cs, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
-		schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
+		mdelay(10);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
+		mdelay(10);
 		if (cs->subtyp != ELSA_PCMCIA_IPAC) {
-			writereg(cs, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
-			writereg(cs, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
+			writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
+			writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
 		} else {
-			writereg(cs, cs->hw.elsa.isac, IPAC_PCFG, 0x10);
-			writereg(cs, cs->hw.elsa.isac, IPAC_ACFG, 0x4);
-			writereg(cs, cs->hw.elsa.isac, IPAC_AOE, 0xf8);
+			writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10);
+			writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4);
+			writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8);
 		}
-		writereg(cs, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
 		if (cs->subtyp == ELSA_QS1000PCI)
 			byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
 		else if (cs->subtyp == ELSA_QS3000PCI)
 			byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */
 	}
-	return 0;
 }
 
 #if ARCOFI_USE
@@ -476,7 +521,7 @@
 	int arcofi_present = 0;
 	char tmp[40];
 	char *t;
-	u8 *p;
+	u_char *p;
 
 	if (!cs->dc.isac.mon_tx)
 		if (!(cs->dc.isac.mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
@@ -525,14 +570,28 @@
 				"Elsa: %s detected modem at 0x%lx\n",
 				Elsa_Types[cs->subtyp],
 				cs->hw.elsa.base+8);
-			request_io(&cs->rs, cs->hw.elsa.base+8, 8, "elsa isdn modem");
+			release_region(cs->hw.elsa.base, 8);
+			if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
+				printk(KERN_WARNING
+					"HiSax: %s config port %lx-%lx already in use\n",
+					Elsa_Types[cs->subtyp],
+					cs->hw.elsa.base + 8,
+					cs->hw.elsa.base + 16);
+			}
 		} else if (cs->subtyp==ELSA_PCC16) {
 			cs->subtyp = ELSA_PCF;
 			printk(KERN_INFO
 				"Elsa: %s detected modem at 0x%lx\n",
 				Elsa_Types[cs->subtyp],
 				cs->hw.elsa.base+8);
-			request_io(&cs->rs, cs->hw.elsa.base+8, 8, "elsa isdn modem");
+			release_region(cs->hw.elsa.base, 8);
+			if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
+				printk(KERN_WARNING
+					"HiSax: %s config port %lx-%lx already in use\n",
+					Elsa_Types[cs->subtyp],
+					cs->hw.elsa.base + 8,
+					cs->hw.elsa.base + 16);
+			}
 		} else
 			printk(KERN_INFO
 				"Elsa: %s detected modem at 0x%lx\n",
@@ -553,15 +612,8 @@
 
 	if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC)
 		return;
-
-	if (cs->typ == ISDN_CTYPE_ELSA) {
-		int pwr = bytein(cs->hw.elsa.ale);
-		if (pwr & 0x08)
-			cs->hw.elsa.status |= ELSA_BAD_PWR;
-		else
-			cs->hw.elsa.status &= ~ELSA_BAD_PWR;
-	}
-	if (cs->status & 0x0001)
+	del_timer(&cs->hw.elsa.tl);
+	if (cs->hw.elsa.status & ELSA_ASSIGN)
 		cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
 	else if (cs->hw.elsa.status & ELSA_BAD_PWR)
 		cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
@@ -569,9 +621,9 @@
 		cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
 		blink = 250;
 	}
-	if (cs->status & 0xf000)
+	if (cs->hw.elsa.status & 0xf000)
 		cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
-	else if (cs->status & 0x0f00) {
+	else if (cs->hw.elsa.status & 0x0f00) {
 		cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
 		blink = 500;
 	} else
@@ -579,159 +631,148 @@
 
 	if ((cs->subtyp == ELSA_QS1000PCI) ||
 		(cs->subtyp == ELSA_QS3000PCI)) {
-		u8 led = 0xff;
+		u_char led = 0xff;
 		if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED)
 			led ^= ELSA_IPAC_LINE_LED;
 		if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED)
 			led ^= ELSA_IPAC_STAT_LED;
-		writereg(cs, cs->hw.elsa.isac, IPAC_ATX, led);
+		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led);
 	} else
 		byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
-
-	if (blink)
-		mod_timer(&cs->hw.elsa.tl, jiffies + (blink * HZ) / 1000);
-}
-
-#if ARCOFI_USE
-static void
-elsa_aux_ind(struct IsdnCardState *cs, void *arg)
-{
-	 if (cs->hw.elsa.MFlag) {
-		 int len;
-		 u8 *msg;
-		 
-		 if (!arg)
-			 return;
-		 msg = arg;
-		 len = *msg;
-		 msg++;
-		 modem_write_cmd(cs, msg, len);
-	 }
-}
-#else
-#define elsa_aux_ind NULL
-#endif
-
-static void
-elsa_init(struct IsdnCardState *cs)
-{
-	if (cs->subtyp == ELSA_QS1000 || cs->subtyp == ELSA_QS3000)
-		byteout(cs->hw.elsa.timer, 0);
-
-	if (cs->hw.elsa.trig)
-		byteout(cs->hw.elsa.trig, 0xff);
-
-	inithscxisac(cs);
+	if (blink) {
+		init_timer(&cs->hw.elsa.tl);
+		cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
+		add_timer(&cs->hw.elsa.tl);
+	}
 }
 
-static void
-elsa_ipac_init(struct IsdnCardState *cs)
+static int
+Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	if (cs->hw.elsa.trig)
-		byteout(cs->hw.elsa.trig, 0xff);
-
-	ipac_init(cs);
-}
+	int ret = 0;
+	u_long flags;
 
-static void
-elsa_test(struct IsdnCardState *cs)
-{
-	if ((cs->subtyp == ELSA_PCMCIA) ||
-	    (cs->subtyp == ELSA_PCMCIA_IPAC) ||
-	    (cs->subtyp == ELSA_QS1000PCI)) {
-		return;
-	} 
-	if (cs->subtyp != ELSA_QS3000PCI) {
-		cs->hw.elsa.counter = 0;
-		cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
-		cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
-		byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
-		byteout(cs->hw.elsa.timer, 0);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((110*HZ)/1000);
-		cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
-		byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
-		cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
-		printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
-		       cs->hw.elsa.counter);
-		if ((cs->hw.elsa.counter > 10) &&
-		    (cs->hw.elsa.counter < 16)) {
-			printk(KERN_INFO "Elsa: timer and irq OK\n");
-		} else {
-			printk(KERN_WARNING
-			       "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
-			       cs->hw.elsa.counter, cs->irq);
-		}
-	}
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_elsa(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_elsa(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->debug |= L1_DEB_IPAC;
+			reset_elsa(cs);
+			inithscxisac(cs, 1);
+			if ((cs->subtyp == ELSA_QS1000) ||
+			    (cs->subtyp == ELSA_QS3000))
+			{
+				byteout(cs->hw.elsa.timer, 0);
+			}
+			if (cs->hw.elsa.trig)
+				byteout(cs->hw.elsa.trig, 0xff);
+			inithscxisac(cs, 2);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			if ((cs->subtyp == ELSA_PCMCIA) ||
+				(cs->subtyp == ELSA_PCMCIA_IPAC) ||
+				(cs->subtyp == ELSA_QS1000PCI)) {
+				return(0);
+			} else if (cs->subtyp == ELSA_QS3000PCI) {
+				ret = 0;
+			} else {
+				spin_lock_irqsave(&cs->lock, flags);
+				cs->hw.elsa.counter = 0;
+				cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
+				cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
+				byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+				byteout(cs->hw.elsa.timer, 0);
+				spin_unlock_irqrestore(&cs->lock, flags);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout((110*HZ)/1000);
+				spin_lock_irqsave(&cs->lock, flags);
+				cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
+				byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+				cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
+				spin_unlock_irqrestore(&cs->lock, flags);
+				printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
+				       cs->hw.elsa.counter);
+				if ((cs->hw.elsa.counter > 10) &&
+					(cs->hw.elsa.counter < 16)) {
+					printk(KERN_INFO "Elsa: timer and irq OK\n");
+					ret = 0;
+				} else {
+					printk(KERN_WARNING
+					       "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+					       cs->hw.elsa.counter, cs->irq);
+					ret = 1;
+				}
+			}
 #if ARCOFI_USE
-	if (check_arcofi(cs)) {
-		init_modem(cs);
-	}
+			if (check_arcofi(cs)) {
+				init_modem(cs);
+			}
 #endif
-	elsa_led_handler(cs);
-}
-
-static struct card_ops elsa_ops = {
-	.init        = elsa_init,
-	.test        = elsa_test,
-	.reset       = elsa_reset,
-	.release     = elsa_release,
-	.aux_ind     = elsa_aux_ind,
-	.led_handler = elsa_led_handler,
-	.irq_func    = elsa_interrupt,
-};
-
-static struct card_ops elsa_ipac_ops = {
-	.init        = elsa_ipac_init,
-	.test        = elsa_test,
-	.reset       = elsa_reset,
-	.release     = elsa_release,
-	.aux_ind     = elsa_aux_ind,
-	.led_handler = elsa_led_handler,
-	.irq_func    = elsa_interrupt_ipac,
-};
-
-static void __init
-elsa_arcofi_init(struct IsdnCardState *cs)
-{
+			elsa_led_handler(cs);
+			return(ret);
+		case (MDL_REMOVE | REQUEST):
+			cs->hw.elsa.status &= 0;
+			break;
+		case (MDL_ASSIGN | REQUEST):
+			cs->hw.elsa.status |= ELSA_ASSIGN;
+			break;
+		case MDL_INFO_SETUP:
+			if ((long) arg)
+				cs->hw.elsa.status |= 0x0200;
+			else
+				cs->hw.elsa.status |= 0x0100;
+			break;
+		case MDL_INFO_CONN:
+			if ((long) arg)
+				cs->hw.elsa.status |= 0x2000;
+			else
+				cs->hw.elsa.status |= 0x1000;
+			break;
+		case MDL_INFO_REL:
+			if ((long) arg) {
+				cs->hw.elsa.status &= ~0x2000;
+				cs->hw.elsa.status &= ~0x0200;
+			} else {
+				cs->hw.elsa.status &= ~0x1000;
+				cs->hw.elsa.status &= ~0x0100;
+			}
+			break;
 #if ARCOFI_USE
-	init_arcofi(cs);
+		case CARD_AUX_IND:
+			if (cs->hw.elsa.MFlag) {
+				int len;
+				u_char *msg;
+
+				if (!arg)
+					return(0);
+				msg = arg;
+				len = *msg;
+				msg++;
+				modem_write_cmd(cs, msg, len);
+			}
+			break;
 #endif
-}
-
-static void __init
-elsa_timer_init(struct IsdnCardState *cs)
-{
-	cs->hw.elsa.tl.function = (void *) elsa_led_handler;
-	cs->hw.elsa.tl.data = (long) cs;
-	init_timer(&cs->hw.elsa.tl);
-}
-
-static int __init
-elsa_timer_test(struct IsdnCardState *cs)
-{
-	/* test timer */
-	byteout(cs->hw.elsa.trig, 0xff);
-	byteout(cs->hw.elsa.timer, 0);
-	if (!TimerRun(cs)) {
-		byteout(cs->hw.elsa.timer, 0);	/* second attempt */
-		if (!TimerRun(cs)) {
-			printk(KERN_WARNING "Elsa: timer does not start\n");
-			goto err;
-		}
 	}
-	HZDELAY(10 * HZ / 1000); /* wait >=10 ms */
-	if (TimerRun(cs)) {
-		printk(KERN_WARNING "Elsa: timer does not run\n");
-		goto err;
-	}
-	printk(KERN_INFO "Elsa: timer OK; resetting card\n");
-	return 0;
- err:
-	return -EBUSY;
+	if (cs->typ == ISDN_CTYPE_ELSA) {
+		int pwr = bytein(cs->hw.elsa.ale);
+		if (pwr & 0x08)
+			cs->hw.elsa.status |= ELSA_BAD_PWR;
+		else
+			cs->hw.elsa.status &= ~ELSA_BAD_PWR;
+	}
+	elsa_led_handler(cs);
+	return(ret);
 }
 
-static unsigned char __init
+static unsigned char
 probe_elsa_adr(unsigned int adr, int typ)
 {
 	int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
@@ -740,13 +781,18 @@
 	/* In case of the elsa pcmcia card, this region is in use,
 	   reserved for us by the card manager. So we do not check it
 	   here, it would fail. */
-	if (typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(adr, 8, "elsa")) {
-		printk(KERN_WARNING "Elsa: probing port 0x%x: in use\n",  adr);
-		return 0;
+	if (typ != ISDN_CTYPE_ELSA_PCMCIA) {
+		if (request_region(adr, 8, "elsa card")) {
+			release_region(adr, 8);
+		} else {
+			printk(KERN_WARNING
+			       "Elsa: Probing Port 0x%x: already in use\n", adr);
+			return (0);
+		}
 	}
 	for (i = 0; i < 16; i++) {
-		in1 = inb(adr + ELSA_CONFIG);	/* 'toggels' at */
-		in2 = inb(adr + ELSA_CONFIG);	/* each access  */
+		in1 = inb(adr + ELSA_CONFIG);	/* 'toggelt' bei */
+		in2 = inb(adr + ELSA_CONFIG);	/* jedem Zugriff */
 		p16_1 += 0x04 & in1;
 		p16_2 += 0x04 & in2;
 		p8_1 += 0x02 & in1;
@@ -756,7 +802,6 @@
 		pfp_1 += 0x40 & in1;
 		pfp_2 += 0x40 & in2;
 	}
-	release_region(adr, 8);
 	printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
 	if (65 == ++p16_1 * ++p16_2) {
 		printk(" PCC-16/PCF found\n");
@@ -776,227 +821,18 @@
 	}
 }
 
-static int __init
-elsa_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static unsigned int
+probe_elsa(struct IsdnCardState *cs)
 {
-	u8 val;
-	int i, bytecnt = 8;
-	unsigned int CARD_portlist[] = {0x160, 0x170, 0x260, 0x360, 0};
-
-	cs->hw.elsa.base = card->para[0];
-	printk(KERN_INFO "Elsa: Microlink IO probing\n");
-	if (cs->hw.elsa.base) {
-		cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, cs->typ);
-		if (!cs->subtyp) {
-			printk(KERN_WARNING "Elsa: no Microlink at %#lx\n",
-			       cs->hw.elsa.base);
-			goto err;
-		}
-	} else {
-		for (i = 0; CARD_portlist[i]; i++) {
-			cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ);
-			if (cs->subtyp)
-				cs->hw.elsa.base = CARD_portlist[i];
-			break;
-		}
-	}
-	if (!cs->hw.elsa.base)
-		goto err;
-		
-	cs->hw.elsa.cfg   = cs->hw.elsa.base + ELSA_CONFIG;
-	cs->hw.elsa.ctrl  = cs->hw.elsa.base + ELSA_CONTROL;
-	cs->hw.elsa.ale   = cs->hw.elsa.base + ELSA_ALE;
-	cs->hw.elsa.isac  = cs->hw.elsa.base + ELSA_ISAC;
-	cs->hw.elsa.itac  = cs->hw.elsa.base + ELSA_ITAC;
-	cs->hw.elsa.hscx  = cs->hw.elsa.base + ELSA_HSCX;
-	cs->hw.elsa.trig  = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-	val = bytein(cs->hw.elsa.cfg);
-	if (cs->subtyp == ELSA_PC) {
-		const u8 CARD_IrqTab[8] = {7, 3, 5, 9, 0, 0, 0, 0};
-		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
-	} else if (cs->subtyp == ELSA_PCC8) {
-		const u8 CARD_IrqTab[8] = {7, 3, 5, 9, 0, 0, 0, 0};
-		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
-	} else {
-		const u8 CARD_IrqTab[8] = {15, 10, 15, 3, 11, 5, 11, 9};
-		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
-	}
-	val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
-	if (val < 3)
-		val |= 8;
-	val += 'A' - 3;
-	if (val == 'B' || val == 'C')
-		val ^= 1;
-	if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
-		val = 'C';
-	printk(KERN_INFO "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
-	       Elsa_Types[cs->subtyp], cs->hw.elsa.base, val, cs->irq);
-	val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
-	if (val) {
-		printk(KERN_WARNING "Elsa: Microlink S0 bus power bad\n");
-		cs->hw.elsa.status |= ELSA_BAD_PWR;
-	}
-	switch (cs->subtyp) {
-		case ELSA_PCFPRO: bytecnt = 16;	break;
-	}
-	if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn"))
-		goto err;
-	elsa_arcofi_init(cs);
-	elsa_timer_init(cs);
-	if (elsa_timer_test(cs))
-		goto err;
-	elsa_reset(cs);
-	cs->card_ops = &elsa_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	if (cs->subtyp == ELSA_PC) {
-		val = readitac(cs, ITAC_SYS);
-		printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
-		writeitac(cs, ITAC_ISEN, 0);
-		writeitac(cs, ITAC_RFIE, 0);
-		writeitac(cs, ITAC_XFIE, 0);
-		writeitac(cs, ITAC_SCIE, 0);
-		writeitac(cs, ITAC_STIE, 0);
-	}
-	return 0;
- err:
-	elsa_release(cs);
-	return -EBUSY;
-}
-
-static int __init
-elsa_qs_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	int bytecnt = 8;
+	int i;
+	unsigned int CARD_portlist[] =
+	{0x160, 0x170, 0x260, 0x360, 0};
 
-	cs->irq           = card->para[0];
-	cs->hw.elsa.base  = card->para[1];
-	cs->hw.elsa.cfg   = cs->hw.elsa.base + ELSA_CONFIG;
-	cs->hw.elsa.ale   = cs->hw.elsa.base + ELSA_ALE;
-	cs->hw.elsa.isac  = cs->hw.elsa.base + ELSA_ISAC;
-	cs->hw.elsa.hscx  = cs->hw.elsa.base + ELSA_HSCX;
-	cs->hw.elsa.trig  = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-	cs->hw.elsa.ctrl  = cs->hw.elsa.base + ELSA_CONTROL;
-	printk(KERN_INFO "Elsa: %s defined at %#lx IRQ %d\n",
-	       Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq);
-	switch (cs->subtyp) {
-	case ELSA_QS3000: bytecnt = 16;	break;
-	}
-	if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn"))
-		goto err;
-	elsa_arcofi_init(cs);
-	elsa_timer_init(cs);
-	if (elsa_timer_test(cs))
-		goto err;
-	elsa_reset(cs);
-	cs->card_ops = &elsa_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	elsa_release(cs);
-	return -EBUSY;
-}
-
-static int __init
-elsa_qs1000_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = ELSA_QS1000;
-	return elsa_qs_probe(cs, card);
-}
-
-static int __init
-elsa_qs3000_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = ELSA_QS3000;
-	return elsa_qs_probe(cs, card);
-}
-
-static int __init
-elsa_pcmcia_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	u8 val;
-
-	cs->irq = card->para[0];
-	cs->hw.elsa.base = card->para[1];
-	cs->hw.elsa.ale = cs->hw.elsa.base + 0;
-	val = readreg(cs, cs->hw.elsa.base + 2, IPAC_ID);
-	if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
-		cs->subtyp = ELSA_PCMCIA_IPAC;
-		cs->hw.elsa.isac = cs->hw.elsa.base + 2;
-	} else {
-		cs->subtyp = ELSA_PCMCIA;
-		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
-		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
-		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-	}
-	cs->hw.elsa.timer = 0;
-	cs->hw.elsa.trig = 0;
-	cs->hw.elsa.ctrl = 0;
-	printk(KERN_INFO "Elsa: %s defined at %#lx IRQ %d\n",
-	       Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq);
-	elsa_arcofi_init(cs);
-	elsa_reset(cs);
-	if (cs->subtyp == ELSA_PCMCIA_IPAC) {
-		cs->card_ops = &elsa_ipac_ops;
-		if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-			goto err;
-	} else {
-		cs->card_ops = &elsa_ops;
-		if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-			goto err;
-	}
-	return 0;
- err:
-	elsa_release(cs);
-	return -EBUSY;
-}
-
-static int __init
-elsa_qs_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev,
-		  int subtyp)
-{
-	int bytecnt = 2;
-	u8 pci_rev;
-
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = subtyp;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.elsa.cfg = pci_resource_start(pdev, 1);
-	cs->hw.elsa.base = pci_resource_start(pdev, 3);
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-	if (cs->hw.elsa.cfg & 0x80 && pci_rev == 1) {
-		printk(KERN_INFO "Elsa: PLX9050 rev1 workaround activated\n");
-		__set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags);
-	}
-	cs->hw.elsa.ale  = cs->hw.elsa.base;
-	cs->hw.elsa.isac = cs->hw.elsa.base +1;
-	cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
-	printk(KERN_INFO "Elsa: %s defined at %#lx/%#x IRQ %d\n",
-	       Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->hw.elsa.cfg,
-	       cs->irq);
-	switch (cs->subtyp) {
-	case ELSA_QS3000PCI: bytecnt = 16; break;
+	for (i = 0; CARD_portlist[i]; i++) {
+		if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
+			break;
 	}
-	if (!request_io(&cs->rs, cs->hw.elsa.base, bytecnt, "elsa isdn"))
-		goto err;
-	if (!request_io(&cs->rs, cs->hw.elsa.cfg, 0x80, "elsa isdn pci"))
-		goto err;
-	elsa_arcofi_init(cs);
-	elsa_timer_init(cs);
-	elsa_reset(cs);
-	cs->card_ops = &elsa_ipac_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		goto err;
-	return 0;
- err:
-	elsa_release(cs);
-	return -EBUSY;
+	return (CARD_portlist[i]);
 }
 
 static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
@@ -1013,109 +849,343 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *pdev = &elsa_ids[0];
+static struct isapnp_device_id *ipid __initdata = &elsa_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __devinit
 setup_elsa(struct IsdnCard *card)
 {
+	int bytecnt;
+	u_char val;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, Elsa_revision);
 	printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-
-	if (card->typ == ISDN_CTYPE_ELSA) {
-		if (elsa_probe(card->cs, card))
-			return 0;
-		return 1;
-	} else if (card->typ == ISDN_CTYPE_ELSA_PNP) {
+	cs->hw.elsa.ctrl_reg = 0;
+	cs->hw.elsa.status = 0;
+	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
+	if (cs->typ == ISDN_CTYPE_ELSA) {
+		cs->hw.elsa.base = card->para[0];
+		printk(KERN_INFO "Elsa: Microlink IO probing\n");
+		if (cs->hw.elsa.base) {
+			if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+							  cs->typ))) {
+				printk(KERN_WARNING
+				       "Elsa: no Elsa Microlink at %#lx\n",
+				       cs->hw.elsa.base);
+				return (0);
+			}
+		} else
+			cs->hw.elsa.base = probe_elsa(cs);
+		if (cs->hw.elsa.base) {
+			cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+			cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+			cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+			cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+			cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+			val = bytein(cs->hw.elsa.cfg);
+			if (cs->subtyp == ELSA_PC) {
+				const u_char CARD_IrqTab[8] =
+				{7, 3, 5, 9, 0, 0, 0, 0};
+				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+			} else if (cs->subtyp == ELSA_PCC8) {
+				const u_char CARD_IrqTab[8] =
+				{7, 3, 5, 9, 0, 0, 0, 0};
+				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+			} else {
+				const u_char CARD_IrqTab[8] =
+				{15, 10, 15, 3, 11, 5, 11, 9};
+				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+			}
+			val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+			if (val < 3)
+				val |= 8;
+			val += 'A' - 3;
+			if (val == 'B' || val == 'C')
+				val ^= 1;
+			if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+				val = 'C';
+			printk(KERN_INFO
+			       "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+			       Elsa_Types[cs->subtyp],
+			       cs->hw.elsa.base,
+			       val, cs->irq);
+			val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+			if (val) {
+				printk(KERN_WARNING
+				   "Elsa: Microlink S0 bus power bad\n");
+				cs->hw.elsa.status |= ELSA_BAD_PWR;
+			}
+		} else {
+			printk(KERN_WARNING
+			       "No Elsa Microlink found\n");
+			return (0);
+		}
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
 #ifdef __ISAPNP__
 		if (!card->para[1] && isapnp_present()) {
-			struct pnp_card *pb;
-			struct pnp_dev *pd;
-			
-			while(pdev->card_vendor) {
-				if ((pb = pnp_find_card(pdev->card_vendor,
-							pdev->card_device,
-							pnp_c))) {
-					pnp_c = pb;
-					pd = NULL;
-					if ((pd = pnp_find_dev(pnp_c,
-							       pdev->vendor,
-							       pdev->function,
-							       pd))) {
+			struct pnp_dev *pnp_d;
+			while(ipid->card_vendor) {
+				if ((pnp_c = pnp_find_card(ipid->card_vendor,
+					ipid->card_device, pnp_c))) {
+					pnp_d = NULL;
+					if ((pnp_d = pnp_find_dev(pnp_c,
+						ipid->vendor, ipid->function, pnp_d))) {
+						int err;
+
 						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)pdev->driver_data);
-						if (pnp_device_attach(pd) < 0) {
-							printk(KERN_ERR "Elsa PnP: attach failed\n");
-							return 0;
-						}
-						if (pnp_activate_dev(pd) < 0) {
-							pnp_device_detach(pd);
-							printk(KERN_ERR "Elsa PnP: activate failed\n");
-							return 0;
+							(char *)ipid->driver_data);
+						pnp_disable_dev(pnp_d);
+						err = pnp_activate_dev(pnp_d);
+						if (err<0) {
+							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+								__FUNCTION__, err);
+							return(0);
 						}
-						if (!pnp_port_valid(pd, 0) ||
-						    !pnp_irq_valid(pd, 0)) {
+						card->para[1] = pnp_port_start(pnp_d, 0);
+						card->para[0] = pnp_irq(pnp_d, 0);
+
+						if (!card->para[0] || !card->para[1]) {
 							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
-							       pnp_irq(pd, 0), pnp_port_start(pd, 0));
-							pnp_device_detach(pd);
+								card->para[0], card->para[1]);
+							pnp_disable_dev(pnp_d);
 							return(0);
 						}
-						card->para[1] = pnp_port_start(pd, 0);
-						card->para[0] = pnp_irq(pd, 0);
-						if (pdev->function == ISAPNP_FUNCTION(0x133)) {
-							if (elsa_qs1000_probe(card->cs, card))
-								return 0;
-							return 1;
-						} else {
-							if (elsa_qs3000_probe(card->cs, card))
-								return 0;
-							return 1;
-						}
+						if (ipid->function == ISAPNP_FUNCTION(0x133))
+							cs->subtyp = ELSA_QS1000;
+						else
+							cs->subtyp = ELSA_QS3000;
 						break;
 					} else {
 						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
 						return(0);
 					}
 				}
-				pdev++;
+				ipid++;
 				pnp_c=NULL;
 			} 
-			if (!pdev->card_vendor) {
+			if (!ipid->card_vendor) {
 				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
 				return(0);
 			}
 		}
 #endif
-		if (elsa_qs1000_probe(card->cs, card))
-			return 0;
-		return 1;
-
-	} else if (card->typ == ISDN_CTYPE_ELSA_PCMCIA) {
-		if (elsa_pcmcia_probe(card->cs, card))
-			return 0;
-		return 1;
-	} else if (card->typ == ISDN_CTYPE_ELSA_PCI) {
-#ifdef CONFIG_PCI
+		if (card->para[1] && card->para[0]) { 
+			cs->hw.elsa.base = card->para[1];
+			cs->irq = card->para[0];
+			if (!cs->subtyp)
+				cs->subtyp = ELSA_QS1000;
+		} else {
+			printk(KERN_ERR "Elsa PnP: no parameter\n");
+		}
+		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+		cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+		cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+		cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+		printk(KERN_INFO
+		       "Elsa: %s defined at %#lx IRQ %d\n",
+		       Elsa_Types[cs->subtyp],
+		       cs->hw.elsa.base,
+		       cs->irq);
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+		cs->hw.elsa.base = card->para[1];
+		cs->irq = card->para[0];
+		val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+		if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+			cs->subtyp = ELSA_PCMCIA_IPAC;
+			cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+			cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+			cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+		} else {
+			cs->subtyp = ELSA_PCMCIA;
+			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+		}
+		cs->hw.elsa.timer = 0;
+		cs->hw.elsa.trig = 0;
+		cs->hw.elsa.ctrl = 0;
+		cs->irq_flags |= SA_SHIRQ;
+		printk(KERN_INFO
+		       "Elsa: %s defined at %#lx IRQ %d\n",
+		       Elsa_Types[cs->subtyp],
+		       cs->hw.elsa.base,
+		       cs->irq);
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+#if CONFIG_PCI
+		cs->subtyp = 0;
 		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
 			PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
-			if (elsa_qs_pci_probe(card->cs, dev_qs1000,
-					      ELSA_QS1000PCI))
-				return 0;
-			return 1;
+			if (pci_enable_device(dev_qs1000))
+				return(0);
+			cs->subtyp = ELSA_QS1000PCI;
+			cs->irq = dev_qs1000->irq;
+			cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+			cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
 		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
 			PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
-			if (elsa_qs_pci_probe(card->cs, dev_qs3000,
-					      ELSA_QS3000PCI))
-				return 0;
-			return 1;
+			if (pci_enable_device(dev_qs3000))
+				return(0);
+			cs->subtyp = ELSA_QS3000PCI;
+			cs->irq = dev_qs3000->irq;
+			cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+			cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
 		} else {
 			printk(KERN_WARNING "Elsa: No PCI card found\n");
-			return 0;
+			return(0);
+		}
+		if (!cs->irq) {
+			printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+			return(0);
+		}
+
+		if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+			printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+			return(0);
+		}
+		if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+			printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+			printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+			printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
 		}
+		cs->hw.elsa.ale  = cs->hw.elsa.base;
+		cs->hw.elsa.isac = cs->hw.elsa.base +1;
+		cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+		cs->hw.elsa.timer = 0;
+		cs->hw.elsa.trig  = 0;
+		cs->irq_flags |= SA_SHIRQ;
+		printk(KERN_INFO
+		       "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+		       Elsa_Types[cs->subtyp],
+		       cs->hw.elsa.base,
+		       cs->hw.elsa.cfg,
+		       cs->irq);
+#else
+		printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
+		printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
+		return (0);
 #endif /* CONFIG_PCI */
+	} else 
+		return (0);
+
+	switch (cs->subtyp) {
+		case ELSA_PC:
+		case ELSA_PCC8:
+		case ELSA_PCC16:
+		case ELSA_QS1000:
+		case ELSA_PCMCIA:
+		case ELSA_PCMCIA_IPAC:
+			bytecnt = 8;
+			break;
+		case ELSA_PCFPRO:
+		case ELSA_PCF:
+		case ELSA_QS3000:
+		case ELSA_QS3000PCI:
+			bytecnt = 16;
+			break;
+		case ELSA_QS1000PCI:
+			bytecnt = 2;
+			break;
+		default:
+			printk(KERN_WARNING
+			       "Unknown ELSA subtype %d\n", cs->subtyp);
+			return (0);
+	}
+	/* In case of the elsa pcmcia card, this region is in use,
+	   reserved for us by the card manager. So we do not check it
+	   here, it would fail. */
+	if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %#lx-%#lx already in use\n",
+		       CardType[card->typ],
+		       cs->hw.elsa.base,
+		       cs->hw.elsa.base + bytecnt);
+		return (0);
+	}
+	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+		if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
+			printk(KERN_WARNING
+			       "HiSax: %s pci port %x-%x already in use\n",
+				CardType[card->typ],
+				cs->hw.elsa.cfg,
+				cs->hw.elsa.cfg + 0x80);
+			release_region(cs->hw.elsa.base, bytecnt);
+			return (0);
+		}
+	}
+#if ARCOFI_USE
+	init_arcofi(cs);
+#endif
+	setup_isac(cs);
+	cs->hw.elsa.tl.function = (void *) elsa_led_handler;
+	cs->hw.elsa.tl.data = (long) cs;
+	init_timer(&cs->hw.elsa.tl);
+	/* Teste Timer */
+	if (cs->hw.elsa.timer) {
+		byteout(cs->hw.elsa.trig, 0xff);
+		byteout(cs->hw.elsa.timer, 0);
+		if (!TimerRun(cs)) {
+			byteout(cs->hw.elsa.timer, 0);	/* 2. Versuch */
+			if (!TimerRun(cs)) {
+				printk(KERN_WARNING
+				       "Elsa: timer do not start\n");
+				release_io_elsa(cs);
+				return (0);
+			}
+		}
+		HZDELAY((HZ/100) + 1);	/* wait >=10 ms */
+		if (TimerRun(cs)) {
+			printk(KERN_WARNING "Elsa: timer do not run down\n");
+			release_io_elsa(cs);
+			return (0);
+		}
+		printk(KERN_INFO "Elsa: timer OK; resetting card\n");
+	}
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Elsa_card_msg;
+	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
+		cs->readisac = &ReadISAC_IPAC;
+		cs->writeisac = &WriteISAC_IPAC;
+		cs->readisacfifo = &ReadISACfifo_IPAC;
+		cs->writeisacfifo = &WriteISACfifo_IPAC;
+		cs->irq_func = &elsa_interrupt_ipac;
+		val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
+		printk(KERN_INFO "Elsa: IPAC version %x\n", val);
+	} else {
+		cs->readisac = &ReadISAC;
+		cs->writeisac = &WriteISAC;
+		cs->readisacfifo = &ReadISACfifo;
+		cs->writeisacfifo = &WriteISACfifo;
+		cs->irq_func = &elsa_interrupt;
+		ISACVersion(cs, "Elsa:");
+		if (HscxVersion(cs, "Elsa:")) {
+			printk(KERN_WARNING
+				"Elsa: wrong HSCX versions check IO address\n");
+			release_io_elsa(cs);
+			return (0);
+		}
+	}
+	if (cs->subtyp == ELSA_PC) {
+		val = readitac(cs, ITAC_SYS);
+		printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
+		writeitac(cs, ITAC_ISEN, 0);
+		writeitac(cs, ITAC_RFIE, 0);
+		writeitac(cs, ITAC_XFIE, 0);
+		writeitac(cs, ITAC_SCIE, 0);
+		writeitac(cs, ITAC_STIE, 0);
 	}
-	return 0;
+	return (1);
 }
--- diff/drivers/isdn/hisax/elsa_cs.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/hisax/elsa_cs.c	2004-02-18 09:03:59.000000000 +0000
@@ -53,6 +53,7 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
+#include "hisax_cfg.h"
 
 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
 MODULE_AUTHOR("Klaus Lichtenwalder");
@@ -71,7 +72,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
 static char *version =
-"elsa_cs.c $Revision: 1.1.2.2 $ $Date: 2001/09/23 22:24:47 $ (K.Lichtenwalder)";
+"elsa_cs.c $Revision: 1.2.2.4 $ $Date: 2004/01/25 15:07:06 $ (K.Lichtenwalder)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -93,8 +94,6 @@
 static int protocol = 2;        /* EURO-ISDN Default */
 MODULE_PARM(protocol, "i");
 
-extern int elsa_init_pcmcia(int, int, int*, int);
-
 /*====================================================================*/
 
 /*
@@ -168,6 +167,7 @@
     dev_link_t          link;
     dev_node_t          node;
     int                 busy;
+    int			cardnr;
 } local_info_t;
 
 /*======================================================================
@@ -188,7 +188,6 @@
     dev_link_t *link;
     local_info_t *local;
     int ret, i;
-    void elsa_interrupt(int, void *, struct pt_regs *);
 
     DEBUG(0, "elsa_cs_attach()\n");
 
@@ -196,6 +195,7 @@
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
     if (!local) return NULL;
     memset(local, 0, sizeof(local_info_t));
+    local->cardnr = -1;
     link = &local->link; link->priv = local;
 
     /* Interrupt setup */
@@ -337,6 +337,7 @@
     int i, j, last_fn;
     u_short buf[128];
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    IsdnCard_t icard;
 
     DEBUG(0, "elsa_config(0x%p)\n", link);
     handle = link->handle;
@@ -430,9 +431,19 @@
 
     link->state &= ~DEV_CONFIG_PENDING;
 
-    elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ,
-                     &(((local_info_t*)link->priv)->busy),
-                     protocol);
+    icard.para[0] = link->irq.AssignedIRQ;
+    icard.para[1] = link->io.BasePort1;
+    icard.protocol = protocol;
+    icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
+    
+    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
+    if (i < 0) {
+    	printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n",
+    		i, link->io.BasePort1);
+    	elsa_cs_release(link);
+    } else
+    	((local_info_t*)link->priv)->cardnr = i;
+
     return;
 cs_failed:
     cs_error(link->handle, last_fn, i);
@@ -449,9 +460,16 @@
 
 static void elsa_cs_release(dev_link_t *link)
 {
+    local_info_t *local = link->priv;
 
     DEBUG(0, "elsa_cs_release(0x%p)\n", link);
 
+    if (local) {
+    	if (local->cardnr >= 0) {
+    	    /* no unregister function with hisax */
+	    HiSax_closecard(local->cardnr);
+	}
+    }
     /* Unlink the device chain */
     link->dev = NULL;
 
--- diff/drivers/isdn/hisax/elsa_ser.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/elsa_ser.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: elsa_ser.c,v 2.10.6.4 2001/09/23 22:24:47 kai Exp $
+/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $
  *
  * stuff for the serial modem on ELSA cards
  *
@@ -26,11 +26,10 @@
 //#define SERIAL_DEBUG_REG 1
 
 #ifdef SERIAL_DEBUG_REG
-static u8 deb[32];
+static u_char deb[32];
 const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"};
 const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"};
 #endif
-static spinlock_t elsa_ser_lock = SPIN_LOCK_UNLOCKED;
 
 static char *MInit_1 = "AT&F&C1E0&D2\r\0";
 static char *MInit_2 = "ATL2M1S64=13\r\0";
@@ -111,7 +110,6 @@
 	int	quot = 0, baud_base;
 	unsigned cval, fcr = 0;
 	int	bits;
-	unsigned long	flags;
 
 
 	/* byte size and parity */
@@ -135,23 +133,17 @@
 	serial_outp(cs, UART_IER, cs->hw.elsa.IER);
 
 	debugl1(cs,"modem quot=0x%x", quot);
-	spin_lock_irqsave(&elsa_ser_lock, flags);
 	serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
 	serial_outp(cs, UART_DLL, quot & 0xff);		/* LS of divisor */
 	serial_outp(cs, UART_DLM, quot >> 8);		/* MS of divisor */
 	serial_outp(cs, UART_LCR, cval);		/* reset DLAB */
 	serial_inp(cs, UART_RX);
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 }
 
 static int mstartup(struct IsdnCardState *cs)
 {
-	unsigned long flags;
 	int	retval=0;
 
-
-	spin_lock_irqsave(&elsa_ser_lock, flags);
-
 	/*
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
@@ -207,7 +199,6 @@
 	change_speed(cs, BASE_BAUD);
 	cs->hw.elsa.MFlag = 1;
 errout:
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 	return retval;
 }
 
@@ -217,15 +208,11 @@
  */
 static void mshutdown(struct IsdnCardState *cs)
 {
-	unsigned long	flags;
-
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk(KERN_DEBUG"Shutting down serial ....");
 #endif
 	
-	spin_lock_irqsave(&elsa_ser_lock, flags);  /* Disable interrupts */
-
 	/*
 	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
 	 * here so the queue might never be waken up
@@ -245,7 +232,6 @@
 	serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
 	serial_inp(cs, UART_RX);    /* read data port to reset things */
 	
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 #ifdef SERIAL_DEBUG_OPEN
 	printk(" done\n");
 #endif
@@ -255,14 +241,12 @@
 write_modem(struct BCState *bcs) {
 	int ret=0;
 	struct IsdnCardState *cs = bcs->cs;
-	u_int count, len, fp;
-	unsigned long flags;
+	int count, len, fp;
 	
 	if (!bcs->tx_skb)
 		return 0;
 	if (bcs->tx_skb->len <= 0)
 		return 0;
-	spin_lock_irqsave(&elsa_ser_lock, flags);
 	len = bcs->tx_skb->len;
 	if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
 		len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
@@ -288,14 +272,37 @@
 			cs->hw.elsa.IER |= UART_IER_THRI;
 		serial_outp(cs, UART_IER, cs->hw.elsa.IER);
 	}
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 	return(ret);
 }
 
-static void
-modem_fill(struct BCState *bcs)
-{
-	xmit_xpr_b(bcs);
+inline void
+modem_fill(struct BCState *bcs) {
+		
+	if (bcs->tx_skb) {
+		if (bcs->tx_skb->len) {
+			write_modem(bcs);
+			return;
+		} else {
+			if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+				(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+				u_long	flags;
+				spin_lock_irqsave(&bcs->aclock, flags);
+				bcs->ackcnt += bcs->hw.hscx.count;
+				spin_unlock_irqrestore(&bcs->aclock, flags);
+				schedule_event(bcs, B_ACKPENDING);
+			}
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+		}
+	}
+	if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+		bcs->hw.hscx.count = 0;
+		test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+		write_modem(bcs);
+	} else {
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		schedule_event(bcs, B_XMTBUFREADY);
+	}
 }
 
 static inline void receive_chars(struct IsdnCardState *cs,
@@ -329,7 +336,7 @@
 				cs->hw.elsa.rcvcnt);
 			skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb);
 		}
-		sched_b_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
+		schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
 	} else {
 		char tmp[128];
 		char *t = tmp;
@@ -375,6 +382,7 @@
 	}
 }
 
+
 static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs)
 {
 	int status, iir, msr;
@@ -419,10 +427,10 @@
 {
 	modehscx(bcs, 0, bcs->channel);
 	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
-		if (bcs->rcvbuf) {
+		if (bcs->hw.hscx.rcvbuf) {
 			if (bcs->mode != L1_MODE_MODEM)
-				kfree(bcs->rcvbuf);
-			bcs->rcvbuf = NULL;
+				kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
 		}
 		skb_queue_purge(&bcs->rqueue);
 		skb_queue_purge(&bcs->squeue);
@@ -435,16 +443,13 @@
 }
 
 void
-modem_write_cmd(struct IsdnCardState *cs, u8 *buf, u_int len) {
-	u_int count, fp;
-	u8 *msg = buf;
-	unsigned long flags;
+modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
+	int count, fp;
+	u_char *msg = buf;
 	
 	if (!len)
 		return;
-	spin_lock_irqsave(&elsa_ser_lock, flags);
 	if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
-		spin_unlock_irqrestore(&elsa_ser_lock, flags);
 		return;
 	}
 	fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
@@ -465,16 +470,13 @@
 		cs->hw.elsa.IER |= UART_IER_THRI;
 		serial_outp(cs, UART_IER, cs->hw.elsa.IER);
 	}
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 }
 
 void
 modem_set_init(struct IsdnCardState *cs) {
-	unsigned long flags;
 	int timeout;
 
 #define RCV_DELAY 20000	
-	spin_lock_irqsave(&elsa_ser_lock, flags);
 	modem_write_cmd(cs, MInit_1, strlen(MInit_1));
 	timeout = 1000;
 	while(timeout-- && cs->hw.elsa.transcnt)
@@ -517,16 +519,13 @@
 		udelay(1000);
 	debugl1(cs, "msi tout=%d", timeout);
 	udelay(RCV_DELAY);
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 }
 
 void
 modem_set_dial(struct IsdnCardState *cs, int outgoing) {
-	unsigned long flags;
 	int timeout;
 #define RCV_DELAY 20000	
 
-	spin_lock_irqsave(&elsa_ser_lock, flags);
 	modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
 	timeout = 1000;
 	while(timeout-- && cs->hw.elsa.transcnt)
@@ -542,40 +541,39 @@
 		udelay(1000);
 	debugl1(cs, "msi tout=%d", timeout);
 	udelay(RCV_DELAY);
-	spin_unlock_irqrestore(&elsa_ser_lock, flags);
 }
 
 void
 modem_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
-	unsigned long flags;
+	u_long flags;
 
 	if (pr == (PH_DATA | REQUEST)) {
-		spin_lock_irqsave(&elsa_ser_lock, flags);
-		if (st->l1.bcs->tx_skb) {
-			skb_queue_tail(&st->l1.bcs->squeue, skb);
-			spin_unlock_irqrestore(&elsa_ser_lock, flags);
+		spin_lock_irqsave(&bcs->cs->lock, flags);
+		if (bcs->tx_skb) {
+			skb_queue_tail(&bcs->squeue, skb);
 		} else {
-			st->l1.bcs->tx_skb = skb;
-			test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			st->l1.bcs->count = 0;
-			spin_unlock_irqrestore(&elsa_ser_lock, flags);
-			write_modem(st->l1.bcs);
+			bcs->tx_skb = skb;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bcs->hw.hscx.count = 0;
+			write_modem(bcs);
 		}
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
 	} else if (pr == (PH_ACTIVATE | REQUEST)) {
-		test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-		L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
-		set_arcofi(st->l1.bcs->cs, st->l1.bc);
-		mstartup(st->l1.bcs->cs);
-		modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
-		st->l1.bcs->cs->hw.elsa.MFlag=2;
+		test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+		st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+		set_arcofi(bcs->cs, st->l1.bc);
+		mstartup(bcs->cs);
+		modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
+		bcs->cs->hw.elsa.MFlag=2;
 	} else if (pr == (PH_DEACTIVATE | REQUEST)) {
-		test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-		st->l1.bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
-		arcofi_fsm(st->l1.bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
-		interruptible_sleep_on(&st->l1.bcs->cs->dc.isac.arcofi_wait);
-		st->l1.bcs->cs->hw.elsa.MFlag=1;
+		test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+		bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
+		arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
+		interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait);
+		bcs->cs->hw.elsa.MFlag=1;
 	} else {
 		printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr);
 	}
@@ -591,24 +589,22 @@
 		case L1_MODE_TRANS:
 			if (open_hscxstate(st->l1.hardware, bcs))
 				return (-1);
-			st->l1.l2l1 = hscx_l2l1;
-			// bcs->cs->BC_Send_Data = hscx_fill_fifo; FIXME
+			st->l2.l2l1 = hscx_l2l1;
 			break;
 		case L1_MODE_MODEM:
 			bcs->mode = L1_MODE_MODEM;
 			if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
-				bcs->rcvbuf = bcs->cs->hw.elsa.rcvbuf;
+				bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
 				skb_queue_head_init(&bcs->rqueue);
 				skb_queue_head_init(&bcs->squeue);
 			}
 			bcs->tx_skb = NULL;
 			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 			bcs->event = 0;
-			bcs->rcvidx = 0;
+			bcs->hw.hscx.rcvidx = 0;
 			bcs->tx_cnt = 0;
 			bcs->cs->hw.elsa.bcs = bcs;
-			st->l1.l2l1 = modem_l2l1;
-//			bcs->cs->bc_l1_ops = &modem_l1_ops;
+			st->l2.l2l1 = modem_l2l1;
 			break;
 	}
 	st->l1.bcs = bcs;
@@ -618,17 +614,13 @@
 	return (0);
 }
 
-static struct bc_l1_ops modem_l1_ops = {
-	.fill_fifo = modem_fill,
-	.open      = setstack_elsa,
-	.close     = close_elsastate,
-};
-
 void
-init_modem(struct IsdnCardState *cs)
-{
-	cs->bc_l1_ops = &modem_l1_ops;
+init_modem(struct IsdnCardState *cs) {
 
+	cs->bcs[0].BC_SetStack = setstack_elsa;
+	cs->bcs[1].BC_SetStack = setstack_elsa;
+	cs->bcs[0].BC_Close = close_elsastate;
+	cs->bcs[1].BC_Close = close_elsastate;
 	if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
 		GFP_ATOMIC))) {
 		printk(KERN_WARNING
--- diff/drivers/isdn/hisax/enternow.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/enternow.h	2004-02-18 09:03:59.000000000 +0000
@@ -40,3 +40,12 @@
  * den TigerJet i/o-Raum gemappt
  * -> 0x01 des AMD bei hw.njet.base + 0C4 */
 #define TJ_AMD_PORT						0xC0
+
+
+
+/* ***************************************************************************************** *
+ * *************************************** Prototypen ************************************** *
+ * ***************************************************************************************** */
+
+BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
+void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
--- diff/drivers/isdn/hisax/enternow_pci.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/enternow_pci.c	2004-02-18 09:03:59.000000000 +0000
@@ -74,13 +74,14 @@
 
 
 
-const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
+const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
+
 
 /* *************************** I/O-Interface functions ************************************* */
 
 
 /* cs->readisac, macro rByteAMD */
-static BYTE
+BYTE
 ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
 {
 	/* direktes Register */
@@ -95,7 +96,7 @@
 }
 
 /* cs->writeisac, macro wByteAMD */
-static void
+void
 WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
 {
 	/* direktes Register */
@@ -110,14 +111,8 @@
 }
 
 
-static struct dc_hw_ops amd7930_ops = {
-	.read_reg   = ReadByteAmd7930,
-	.write_reg  = WriteByteAmd7930,
-};
-
-static void
-enpci_setIrqMask(struct IsdnCardState *cs, BYTE val)
-{
+void
+enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
         if (!val)
 	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
         else
@@ -125,6 +120,17 @@
 }
 
 
+static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+{
+        return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+{
+
+}
+
+
 /* ******************************************************************************** */
 
 
@@ -137,15 +143,12 @@
 	/* Reset on, (also for AMD) */
 	cs->hw.njet.ctrl_reg = 0x07;
 	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	/* 80 ms delay */
-	schedule_timeout((80*HZ)/1000);
+	mdelay(20);
 	/* Reset off */
-	cs->hw.njet.ctrl_reg = 0x70;
+	cs->hw.njet.ctrl_reg = 0x30;
 	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	/* 80ms delay */
-	schedule_timeout((80*HZ)/1000);
+	/* 20ms delay */
+	mdelay(20);
 	cs->hw.njet.auxd = 0;  // LED-status
 	cs->hw.njet.dmactrl = 0;
 	OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
@@ -153,96 +156,124 @@
 	OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
 }
 
-static void
-enpci_bc_activate(struct IsdnCardState *cs, int chan)
-{
-	if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", chan);
-	
-	cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (chan + 1)), "MDL_BC_ASSIGN");
-	/* at least one b-channel in use, LED 2 on */
-	cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
-	OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
-}
 
-static void
-enpci_bc_deactivate(struct IsdnCardState *cs, int chan)
+static int
+enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", chan);
-	
-	cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(chan + 1)), "MDL_BC_RELEASE");
-	/* no b-channel active -> LED2 off */
-	if (!(cs->dc.amd7930.lmr1 & 3)) {
-		cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
-		OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
-	}
-}
+	u_long flags;
+        BYTE *chan;
 
-static void
-enpci_led_handler(struct IsdnCardState *cs)
-{
-	if (cs->status & 0x0001) {
-		/* TEI assigned, LED1 on */
-		cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
-		OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
-	} else {
-		/* TEI removed, LEDs off */
-		cs->hw.njet.auxd = 0;
-		OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
-	}
-}
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
 
-static void
-enpci_init(struct IsdnCardState *cs)
-{
-	inittiger(cs);
-	Amd7930_init(cs);
-}
+        switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_enpci(cs);
+                        Amd7930_init(cs);
+                        spin_unlock_irqrestore(&cs->lock, flags);
+			break;
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			break;
+		case CARD_INIT:
+			reset_enpci(cs);
+			inittiger(cs);
+			/* irq must be on here */
+			Amd7930_init(cs);
+			break;
+		case CARD_TEST:
+			break;
+                case MDL_ASSIGN:
+                        /* TEI assigned, LED1 on */
+                        cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_REMOVE:
+                        /* TEI removed, LEDs off */
+	                cs->hw.njet.auxd = 0;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+                        break;
+                case MDL_BC_ASSIGN:
+                        /* activate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
+                        /* at least one b-channel in use, LED 2 on */
+                        cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_BC_RELEASE:
+                        /* deactivate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
+                        /* no b-channel active -> LED2 off */
+                        if (!(cs->dc.amd7930.lmr1 & 3)) {
+                                cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
+                                OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        }
+                        break;
+                default:
+                        break;
 
-static int
-enpci_reset(struct IsdnCardState *cs)
-{
-	reset_enpci(cs);
-	Amd7930_init(cs);
-	return 0;
+	}
+	return(0);
 }
 
 static irqreturn_t
 enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	BYTE sval, ir;
-
-	spin_lock(&cs->lock);
+	BYTE s0val, s1val, ir;
+	u_long flags;
 
-	sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+	spin_lock_irqsave(&cs->lock, flags);
+	s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
 
         /* AMD threw an interrupt */
-	if (!(sval & TJ_AMD_IRQ)) {
+	if (!(s1val & TJ_AMD_IRQ)) {
                 /* read and clear interrupt-register */
 		ir = ReadByteAmd7930(cs, 0x00);
 		Amd7930_interrupt(cs, ir);
-	}
+		s1val = 1;
+	} else
+		s1val = 0;
+	s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0);
+	if ((s0val | s1val)==0) { // shared IRQ
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
+	} 
+	if (s0val)
+		OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
 
 	/* DMA-Interrupt: B-channel-stuff */
 	/* set bits in sval to indicate which page is free */
-
-	/* set bits in sval to indicate which page is free */
 	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
 		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
 		/* the 2nd write page is free */
-		sval = 0x08;
+		s0val = 0x08;
 	else	/* the 1st write page is free */
-		sval = 0x04;
+		s0val = 0x04;
 	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
 		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
 		/* the 2nd read page is free */
-		sval = sval | 0x02;
+		s0val = s0val | 0x02;
 	else	/* the 1st read page is free */
-		sval = sval | 0x01;
-	if (sval != cs->hw.njet.last_is0) { /* we have a DMA interrupt */
-		cs->hw.njet.irqstat0 = sval;
+		s0val = s0val | 0x01;
+	if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return IRQ_HANDLED;
+		}
+		cs->hw.njet.irqstat0 = s0val;
 		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
 			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
 			/* we have a read dma int */
@@ -251,71 +282,12 @@
 			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
 			/* we have a write dma int */
 			write_tiger(cs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	}
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static struct card_ops enpci_ops = {
-	.init        = enpci_init,
-	.reset       = enpci_reset,
-	.release     = netjet_release,
-	.led_handler = enpci_led_handler,
-	.irq_func    = enpci_interrupt,
-};
-
-static int __init
-enpci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.njet.base = pci_resource_start(pdev, 0);
-	if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "Fn_ISDN"))
-		goto err;
-
-	cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-	cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
-
-	/* Reset an */
-	cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
-	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	/* 50 ms Pause */
-	schedule_timeout((50*HZ)/1000);
-	
-	cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
-	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	
-	cs->hw.njet.auxd = 0x00; // war 0xc0
-	cs->hw.njet.dmactrl = 0;
-	
-	OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
-	OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
-	OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
-	
-	printk(KERN_INFO
-	       "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
-	       cs->hw.njet.base, cs->irq);
-	reset_enpci(cs);
-	cs->hw.njet.last_is0 = 0;
-	cs->hw.njet.bc_activate = enpci_bc_activate;
-	cs->hw.njet.bc_deactivate = enpci_bc_deactivate;
-	amd7930_setup(cs, &amd7930_ops, &enpci_setIrqMask);
-
-	cs->card_ops = &enpci_ops;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
 
 static struct pci_dev *dev_netjet __initdata = NULL;
 
@@ -323,30 +295,105 @@
 int __init
 setup_enternow_pci(struct IsdnCard *card)
 {
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
+#if CONFIG_PCI
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
         strcpy(tmp, enternow_pci_rev);
 	printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
-
-	dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				     PCI_DEVICE_ID_TIGERJET_300, dev_netjet);
-	if (dev_netjet) {
-		if (dev_netjet->subsystem_vendor != 0x55 ||
-		    dev_netjet->subsystem_device != 0x02) {
-			printk(KERN_WARNING "enter:now: You tried to load "
-			       "this driver with an incompatible "
-			       "TigerJet-card\n");
-			printk(KERN_WARNING "Use type=20 for Traverse "
-			       "NetJet PCI Card.\n");
-			return 0;
+	if (cs->typ != ISDN_CTYPE_ENTERNOW)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+	for ( ;; )
+	{
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+                        /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+			if ((dev_netjet->subsystem_vendor != 0x55) ||
+				(dev_netjet->subsystem_device != 0x02)) {
+				printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+                                printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+                                return(0);
+                        }
+		} else {
+                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+			return(0);
 		}
-		if (enpci_probe(card->cs, dev_netjet))
-			return 1;
-		return 0;
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
+
+		/* Reset an */
+		cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		/* 20 ms Pause */
+		mdelay(20);
+
+		cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		mdelay(10);
+
+		cs->hw.njet.auxd = 0x00; // war 0xc0
+		cs->hw.njet.dmactrl = 0;
+
+		OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+		break;
+	}
+#else
+
+	printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
+		printk(KERN_WARNING
+			   "HiSax: %s config port %lx-%lx already in use\n",
+			   CardType[card->typ],
+			   cs->hw.njet.base,
+			   cs->hw.njet.base + bytecnt);
+		return (0);
 	}
-	printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
-	return 0;
+	setup_Amd7930(cs);
+	cs->hw.njet.last_is0 = 0;
+        /* macro rByteAMD */
+        cs->readisac = &ReadByteAmd7930;
+        /* macro wByteAMD */
+        cs->writeisac = &WriteByteAmd7930;
+        cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
+
+        cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &enpci_card_msg;
+	cs->irq_func = &enpci_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+
+        return (1);
 }
--- diff/drivers/isdn/hisax/gazel.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/gazel.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: gazel.c,v 2.11.6.7 2001/09/23 22:24:47 kai Exp $
+/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $
  *
  * low level stuff for Gazel isdn cards
  *
@@ -21,8 +21,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.11.6.7 $";
-static spinlock_t gazel_lock = SPIN_LOCK_UNLOCKED;
+const char *gazel_revision = "$Revision: 2.19.2.4 $";
 
 #define R647      1
 #define R685      2
@@ -44,492 +43,642 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static inline u8
+static inline u_char
 readreg(unsigned int adr, u_short off)
 {
 	return bytein(adr + off);
 }
 
 static inline void
-writereg(unsigned int adr, u_short off, u8 data)
+writereg(unsigned int adr, u_short off, u_char data)
 {
 	byteout(adr + off, data);
 }
 
 
 static inline void
-read_fifo(unsigned int adr, u8 * data, int size)
+read_fifo(unsigned int adr, u_char * data, int size)
 {
 	insb(adr, data, size);
 }
 
 static void
-write_fifo(unsigned int adr, u8 * data, int size)
+write_fifo(unsigned int adr, u_char * data, int size)
 {
 	outsb(adr, data, size);
 }
 
-static u8
-r685_isac_read(struct IsdnCardState *cs, u8 off)
+static inline u_char
+readreg_ipac(unsigned int adr, u_short off)
 {
-	return readreg(cs->hw.gazel.isac, off);
-}
+	register u_char ret;
 
-static u8
-r647_isac_read(struct IsdnCardState *cs, u8 off)
-{
-	return readreg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf));
+	byteout(adr, off);
+	ret = bytein(adr + 4);
+	return ret;
 }
 
-static void
-r685_isac_write(struct IsdnCardState *cs, u8 off, u8 value)
+static inline void
+writereg_ipac(unsigned int adr, u_short off, u_char data)
 {
-	writereg(cs->hw.gazel.isac, off, value);
+	byteout(adr, off);
+	byteout(adr + 4, data);
 }
 
-static void
-r647_isac_write(struct IsdnCardState *cs, u8 off, u8 value)
-{
-	writereg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf), value);
-}
 
-static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+static inline void
+read_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
 {
-	read_fifo(cs->hw.gazel.isacfifo, data, size);
+	byteout(adr, off);
+	insb(adr + 4, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+write_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
 {
-	write_fifo(cs->hw.gazel.isacfifo, data, size);
+	byteout(adr, off);
+	outsb(adr + 4, data, size);
 }
 
-static struct dc_hw_ops r685_isac_ops = {
-	.read_reg   = r685_isac_read,
-	.write_reg  = r685_isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
+/* Interface functions */
 
-static struct dc_hw_ops r647_isac_ops = {
-	.read_reg   = r647_isac_read,
-	.write_reg  = r647_isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-  
-static u8
-r685_hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.gazel.hscx[hscx], off);
+	u_short off2 = offset;
+
+	switch (cs->subtyp) {
+		case R647:
+			off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+		case R685:
+			return (readreg(cs->hw.gazel.isac, off2));
+		case R753:
+		case R742:
+			return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
+	}
+	return 0;
 }
 
-static u8
-r647_hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	return readreg(cs->hw.gazel.hscx[hscx],
-		       (off << 8 & 0xf000) | (off & 0xf));
+	u_short off2 = offset;
+
+	switch (cs->subtyp) {
+		case R647:
+			off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+		case R685:
+			writereg(cs->hw.gazel.isac, off2, value);
+			break;
+		case R753:
+		case R742:
+			writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
+			break;
+	}
 }
 
 static void
-r685_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writereg(cs->hw.gazel.hscx[hscx], off, value);
+	switch (cs->subtyp) {
+		case R647:
+		case R685:
+			read_fifo(cs->hw.gazel.isacfifo, data, size);
+			break;
+		case R753:
+		case R742:
+			read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
+			break;
+	}
 }
 
 static void
-r647_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writereg(cs->hw.gazel.hscx[hscx],
-		 (off << 8 & 0xf000) | (off & 0xf), value);
+	switch (cs->subtyp) {
+		case R647:
+		case R685:
+			write_fifo(cs->hw.gazel.isacfifo, data, size);
+			break;
+		case R753:
+		case R742:
+			write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
+			break;
+	}
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
+ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
 {
-	read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+	switch (cs->subtyp) {
+		case R647:
+		case R685:
+			read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+			break;
+		case R753:
+		case R742:
+			read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
+			break;
+	}
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
+WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
 {
-	write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+	switch (cs->subtyp) {
+		case R647:
+		case R685:
+			write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+			break;
+		case R753:
+		case R742:
+			write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
+			break;
+	}
 }
 
-static struct bc_hw_ops r685_hscx_ops = {
-	.read_reg   = r685_hscx_read,
-	.write_reg  = r685_hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static struct bc_hw_ops r647_hscx_ops = {
-	.read_reg   = r647_hscx_read,
-	.write_reg  = r647_hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u_short off)
-{
-	register u8 ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gazel_lock, flags);
-	byteout(cs->hw.gazel.ipac, off);
-	ret = bytein(cs->hw.gazel.ipac + 4);
-	spin_unlock_irqrestore(&gazel_lock, flags);
-	return ret;
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	u_short off2 = offset;
+
+	switch (cs->subtyp) {
+		case R647:
+			off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+		case R685:
+			return (readreg(cs->hw.gazel.hscx[hscx], off2));
+		case R753:
+		case R742:
+			return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
+	}
+	return 0;
 }
 
-static inline void
-ipac_write(struct IsdnCardState *cs, u_short off, u8 data)
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	unsigned long flags;
+	u_short off2 = offset;
 
-	spin_lock_irqsave(&gazel_lock, flags);
-	byteout(cs->hw.gazel.ipac, off);
-	byteout(cs->hw.gazel.ipac + 4, data);
-	spin_unlock_irqrestore(&gazel_lock, flags);
+	switch (cs->subtyp) {
+		case R647:
+			off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+		case R685:
+			writereg(cs->hw.gazel.hscx[hscx], off2, value);
+			break;
+		case R753:
+		case R742:
+			writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
+			break;
+	}
 }
 
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 off, u8 * data, int size)
-{
-	byteout(cs->hw.gazel.ipac, off);
-	insb(cs->hw.gazel.ipac + 4, data, size);
+#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 5
+	struct IsdnCardState *cs = dev_id;
+	u_char valisac, valhscx;
+	int count = 0;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	do {
+		valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
+		if (valhscx)
+			hscx_int_main(cs, valhscx);
+		valisac = ReadISAC(cs, ISAC_ISTA);
+		if (valisac)
+			isac_interrupt(cs, valisac);
+		count++;
+	} while ((valhscx || valisac) && (count < MAXCOUNT));
+
+	WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
+	WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
+	WriteISAC(cs, ISAC_MASK, 0xFF);
+	WriteISAC(cs, ISAC_MASK, 0x0);
+	WriteHSCX(cs, 0, HSCX_MASK, 0x0);
+	WriteHSCX(cs, 1, HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size)
-{
-	byteout(cs->hw.gazel.ipac, off);
-	outsb(cs->hw.gazel.ipac + 4, data, size);
-}
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
+static irqreturn_t
+gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char ista, val;
+	int count = 0;
+	u_long flags;
+	
+	spin_lock_irqsave(&cs->lock, flags);
+	ista = ReadISAC(cs, IPAC_ISTA - 0x80);
+	do {
+		if (ista & 0x0f) {
+			val = ReadHSCX(cs, 1, HSCX_ISTA);
+			if (ista & 0x01)
+				val |= 0x01;
+			if (ista & 0x04)
+				val |= 0x02;
+			if (ista & 0x08)
+				val |= 0x04;
+			if (val) {
+				hscx_int_main(cs, val);
+			}
+		}
+		if (ista & 0x20) {
+			val = 0xfe & ReadISAC(cs, ISAC_ISTA);
+			if (val) {
+				isac_interrupt(cs, val);
+			}
+		}
+		if (ista & 0x10) {
+			val = 0x01;
+			isac_interrupt(cs, val);
+		}
+		ista = ReadISAC(cs, IPAC_ISTA - 0x80);
+		count++;
+	}
+	while ((ista & 0x3f) && (count < MAXCOUNT));
 
-BUILD_IPAC_OPS(ipac);
+	WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
+	WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+void
+release_io_gazel(struct IsdnCardState *cs)
+{
+	unsigned int i;
+
+	switch (cs->subtyp) {
+		case R647:
+			for (i = 0x0000; i < 0xC000; i += 0x1000)
+				release_region(i + cs->hw.gazel.hscx[0], 16);
+			release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
+			break;
 
-static int
-r647_reset(struct IsdnCardState *cs)
-{
-	writereg(cs->hw.gazel.cfg_reg, 0, 0);
-	HZDELAY(10);
-	writereg(cs->hw.gazel.cfg_reg, 0, 1);
-	HZDELAY(2);
-	return 0;
+		case R685:
+			release_region(cs->hw.gazel.hscx[0], 0x100);
+			release_region(cs->hw.gazel.cfg_reg, 0x80);
+			break;
+
+		case R753:
+			release_region(cs->hw.gazel.ipac, 0x8);
+			release_region(cs->hw.gazel.cfg_reg, 0x80);
+			break;
+
+		case R742:
+			release_region(cs->hw.gazel.ipac, 8);
+			break;
+	}
 }
 
 static int
-r685_reset(struct IsdnCardState *cs)
+reset_gazel(struct IsdnCardState *cs)
 {
 	unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
 
-	plxcntrl = inl(addr + PLX_CNTRL);
-	plxcntrl |= (RESET_9050 + RESET_GAZEL);
-	outl(plxcntrl, addr + PLX_CNTRL);
-	plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
-	HZDELAY(4);
-	outl(plxcntrl, addr + PLX_CNTRL);
-	HZDELAY(10);
-	outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
-	return 0;
+	switch (cs->subtyp) {
+		case R647:
+			writereg(addr, 0, 0);
+			HZDELAY(10);
+			writereg(addr, 0, 1);
+			HZDELAY(2);
+			break;
+		case R685:
+			plxcntrl = inl(addr + PLX_CNTRL);
+			plxcntrl |= (RESET_9050 + RESET_GAZEL);
+			outl(plxcntrl, addr + PLX_CNTRL);
+			plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
+			HZDELAY(4);
+			outl(plxcntrl, addr + PLX_CNTRL);
+			HZDELAY(10);
+			outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
+			break;
+		case R753:
+			plxcntrl = inl(addr + PLX_CNTRL);
+			plxcntrl |= (RESET_9050 + RESET_GAZEL);
+			outl(plxcntrl, addr + PLX_CNTRL);
+			plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
+			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
+			HZDELAY(4);
+			outl(plxcntrl, addr + PLX_CNTRL);
+			HZDELAY(10);
+			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
+			WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
+			WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
+			WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
+			WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
+			outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
+			WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
+			break;
+		case R742:
+			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
+			HZDELAY(4);
+			WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
+			WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
+			WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
+			WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
+			WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
+			WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
+			break;
+	}
+	return (0);
 }
 
 static int
-r753_reset(struct IsdnCardState *cs)
+Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
+	u_long flags;
 
-	if (test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags))
-		/* we can't read, assume the default */
-		plxcntrl = 0x18784db6;
-	else
-		plxcntrl = inl(addr + PLX_CNTRL);
-	plxcntrl |= (RESET_9050 + RESET_GAZEL);
-	outl(plxcntrl, addr + PLX_CNTRL);
-	ipac_write(cs, IPAC_POTA2, 0x20);
-	HZDELAY(4);
-	plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
-	outl(plxcntrl, addr + PLX_CNTRL);
-	HZDELAY(10);
-	ipac_write(cs, IPAC_POTA2, 0x00);
-	ipac_write(cs, IPAC_ACFG, 0xff);
-	ipac_write(cs, IPAC_AOE, 0x0);
-	ipac_write(cs, IPAC_MASK, 0xff);
-	ipac_write(cs, IPAC_CONF, 0x1);
-	outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
-	ipac_write(cs, IPAC_MASK, 0xc0);
-	return 0;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_gazel(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_RELEASE:
+			release_io_gazel(cs);
+			return (0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 1);
+			if ((cs->subtyp==R647)||(cs->subtyp==R685)) {
+				int i;
+				for (i=0;i<(2+MAX_WAITING_CALLS);i++) {
+					cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
+					cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
+				}
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
+	}
+	return (0);
 }
 
 static int
-r742_reset(struct IsdnCardState *cs)
+reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
 {
-	ipac_write(cs, IPAC_POTA2, 0x20);
-	HZDELAY(4);
-	ipac_write(cs, IPAC_POTA2, 0x00);
-	ipac_write(cs, IPAC_ACFG, 0xff);
-	ipac_write(cs, IPAC_AOE, 0x0);
-	ipac_write(cs, IPAC_MASK, 0xff);
-	ipac_write(cs, IPAC_CONF, 0x1);
-	ipac_write(cs, IPAC_MASK, 0xc0);
-	return 0;
-}
+	unsigned int i, j, base = 0, adr = 0, len = 0;
 
-static void
-gazel_init(struct IsdnCardState *cs)
-{
-	int i;
+	switch (cs->subtyp) {
+		case R647:
+			base = cs->hw.gazel.hscx[0];
+			if (!request_region(adr = (0xC000 + base), len = 1, "gazel"))
+				goto error;
+			for (i = 0x0000; i < 0xC000; i += 0x1000) {
+				if (!request_region(adr = (i + base), len = 16, "gazel"))
+					goto error;
+			}
+			if (i != 0xC000) {
+				for (j = 0; j < i; j+= 0x1000)
+					release_region(j + base, 16);
+				release_region(0xC000 + base, 1);
+				goto error;
+			}
+			break;
+
+		case R685:
+			if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel"))
+				goto error;
+			if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
+				release_region(cs->hw.gazel.hscx[0],0x100);
+				goto error;
+			}
+			break;
 
-	for (i = 0; i < 2; i++) {
-		cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
-		cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
-	}
-	inithscxisac(cs);
-}
-
-static struct card_ops r647_ops = {
-	.init     = gazel_init,
-	.reset    = r647_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static struct card_ops r685_ops = {
-	.init     = gazel_init,
-	.reset    = r685_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static struct card_ops r742_ops = {
-	.init     = ipac_init,
-	.reset    = r742_reset,
-	.release  = hisax_release_resources,
-	.irq_func = ipac_irq,
-};
-
-static struct card_ops r753_ops = {
-	.init     = ipac_init,
-	.reset    = r753_reset,
-	.release  = hisax_release_resources,
-	.irq_func = ipac_irq,
-};
+		case R753:
+			if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
+				goto error;
+			if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
+				release_region(cs->hw.gazel.ipac, 8);
+				goto error;
+			}
+			break;
+
+		case R742:
+			if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
+				goto error;
+			break;
+	}
+
+	return 0;
+
+      error:
+	printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n",
+	       CardType[cs->typ], adr, adr + len);
+	return 1;
+}
 
 static int __init
-gazel647_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
 {
-	int i, base;
+	printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
+	// we got an irq parameter, assume it is an ISA card
+	// R742 decodes address even in not started...
+	// R647 returns FF if not present or not started
+	// eventually needs improvment
+	if (readreg_ipac(card->para[1], IPAC_ID) == 1)
+		cs->subtyp = R742;
+	else
+		cs->subtyp = R647;
 
-	cs->subtyp = R647;
-	cs->irq = card->para[0];
+	setup_isac(cs);
 	cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
-
-	printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
-	cs->dc.isac.adf2 = 0x87;
-	printk(KERN_INFO "Gazel: config irq:%d isac:0x%X  cfg:0x%X\n",
-	       cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
-	printk(KERN_INFO
-	       "Gazel: hscx A:0x%X  hscx B:0x%X\n",
-	       cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
-
+	cs->hw.gazel.ipac = card->para[1];
 	cs->hw.gazel.isac = card->para[1] + 0x8000;
 	cs->hw.gazel.hscx[0] = card->para[1];
 	cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
+	cs->irq = card->para[0];
 	cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
 	cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
 	cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
 
-	base = cs->hw.gazel.hscx[0];
-	for (i = 0; i < 0xc000; i += 0x1000) {
-		if (!request_io(&cs->rs, base + i, 16, "gazel"))
-			goto err;
-	}
-	if (!request_io(&cs->rs, 0xc000 + base, 1, "gazel"))
-		goto err;
-
-	cs->card_ops = &r647_ops;
-	if (hscxisac_setup(cs, &r647_isac_ops, &r647_hscx_ops))
-		goto err;
-
-	cs->card_ops->reset(cs);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-gazel742_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = R742;
-	cs->irq = card->para[0];
-	cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
+	switch (cs->subtyp) {
+		case R647:
+			printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
+			cs->dc.isac.adf2 = 0x87;
+			printk(KERN_INFO
+				"Gazel: config irq:%d isac:0x%X  cfg:0x%X\n",
+				cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
+			printk(KERN_INFO
+				"Gazel: hscx A:0x%X  hscx B:0x%X\n",
+				cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
 
-	printk(KERN_INFO "Gazel: Card ISA R742 found\n");
-	printk(KERN_INFO "Gazel: config irq:%d ipac:0x%X\n",
-	       cs->irq, cs->hw.gazel.ipac);
-
-	if (!request_io(&cs->rs, cs->hw.gazel.ipac, 0x8, "gazel"))
-		goto err;
-
-	cs->card_ops = &r742_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		goto err;
+			break;
+		case R742:
+			printk(KERN_INFO "Gazel: Card ISA R742 found\n");
+			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+			printk(KERN_INFO
+			       "Gazel: config irq:%d ipac:0x%X\n",
+			       cs->irq, cs->hw.gazel.ipac);
+			break;
+	}
 
-	cs->card_ops->reset(cs);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return (0);
 }
 
+static struct pci_dev *dev_tel __initdata = NULL;
+
 static int __init
-gazel685_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
+setup_gazelpci(struct IsdnCardState *cs)
 {
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->subtyp               = R685;
-	cs->irq                  = pdev->irq;
-	cs->irq_flags           |= SA_SHIRQ;
-	cs->hw.gazel.cfg_reg     = pci_resource_start(pdev, 1);
-	cs->hw.gazel.isac        = pci_resource_start(pdev, 2) + 0x80;
-	cs->hw.gazel.hscx[0]     = pci_resource_start(pdev, 2);
-	cs->hw.gazel.hscx[1]     = pci_resource_start(pdev, 2) + 0x40;
-	cs->hw.gazel.isacfifo    = cs->hw.gazel.isac;
+	u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
+	u_char pci_irq = 0, found;
+	u_int nbseek, seekcard;
+
+	printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
+
+	found = 0;
+	seekcard = PCI_DEVICE_ID_PLX_R685;
+	for (nbseek = 0; nbseek < 3; nbseek++) {
+		if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) {
+			if (pci_enable_device(dev_tel))
+				return 1;
+			pci_irq = dev_tel->irq;
+			pci_ioaddr0 = pci_resource_start(dev_tel, 1);
+			pci_ioaddr1 = pci_resource_start(dev_tel, 2);
+			found = 1;
+		}
+		if (found)
+			break;
+		else {
+			switch (seekcard) {
+				case PCI_DEVICE_ID_PLX_R685:
+					seekcard = PCI_DEVICE_ID_PLX_R753;
+					break;
+				case PCI_DEVICE_ID_PLX_R753:
+					seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
+					break;
+			}
+		}
+	}
+	if (!found) {
+		printk(KERN_WARNING "Gazel: No PCI card found\n");
+		return (1);
+	}
+	if (!pci_irq) {
+		printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
+		return 1;
+	}
+	cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
+	cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
+	setup_isac(cs);
+	pci_ioaddr1 &= 0xfffe;
+	cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
+	cs->hw.gazel.ipac = pci_ioaddr1;
+	cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
+	cs->hw.gazel.hscx[0] = pci_ioaddr1;
+	cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
+	cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
 	cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
 	cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
-	cs->dc.isac.adf2 = 0x87;
-
-	if (!request_io(&cs->rs, cs->hw.gazel.hscx[0], 0x100, "gazel"))
-		goto err;
-	if (!request_io(&cs->rs, cs->hw.gazel.cfg_reg, 0x80, "gazel"))
-		goto err;
-
-	printk(KERN_INFO "Gazel: Card PCI R685 found\n");
-	printk(KERN_INFO "Gazel: config irq:%d isac:0x%X  cfg:0x%X\n",
-	       cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
-	printk(KERN_INFO "Gazel: hscx A:0x%X  hscx B:0x%X\n",
-	       cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
-
-	cs->card_ops  = &r685_ops;
-	if (hscxisac_setup(cs, &r685_isac_ops, &r685_hscx_ops))
-		goto err;
+	cs->irq = pci_irq;
+	cs->irq_flags |= SA_SHIRQ;
 
-	cs->card_ops->reset(cs);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-gazel753_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	u8 pci_rev;
-
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->subtyp           = R753;
-	cs->irq              = pdev->irq;
-	cs->irq_flags       |= SA_SHIRQ;
-	cs->hw.gazel.cfg_reg = pci_resource_start(pdev, 1);
-	cs->hw.gazel.ipac    = pci_resource_start(pdev, 2);
-
-	if (!request_io(&cs->rs, cs->hw.gazel.ipac, 0x8, "gazel"))
-		goto err;
-	if (!request_io(&cs->rs, cs->hw.gazel.cfg_reg, 0x80, "gazel"))
-		goto err;
-
-	printk(KERN_INFO "Gazel: Card PCI R753 found\n");
-	printk(KERN_INFO "Gazel: config irq:%d ipac:0x%X  cfg:0x%X\n",
-	       cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
-	/* 
-	 * Erratum for PLX9050, revision 1:
-	 * If bit 7 of BAR 0/1 is set, local config registers
-	 * can not be read (write is okay)
-	 */
-	if (cs->hw.gazel.cfg_reg & 0x80) {
-		pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-		if (pci_rev == 1) {
-			printk(KERN_INFO "Gazel: PLX9050 rev1 workaround "
-			       "activated\n");
-			__set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags);
-		}
+	switch (seekcard) {
+		case PCI_DEVICE_ID_PLX_R685:
+			printk(KERN_INFO "Gazel: Card PCI R685 found\n");
+			cs->subtyp = R685;
+			cs->dc.isac.adf2 = 0x87;
+			printk(KERN_INFO
+			    "Gazel: config irq:%d isac:0x%X  cfg:0x%X\n",
+			cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
+			printk(KERN_INFO
+			       "Gazel: hscx A:0x%X  hscx B:0x%X\n",
+			     cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
+			break;
+		case PCI_DEVICE_ID_PLX_R753:
+		case PCI_DEVICE_ID_PLX_DJINN_ITOO:
+			printk(KERN_INFO "Gazel: Card PCI R753 found\n");
+			cs->subtyp = R753;
+			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+			printk(KERN_INFO
+			    "Gazel: config irq:%d ipac:0x%X  cfg:0x%X\n",
+			cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
+			break;
 	}
-	cs->card_ops = &r753_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		goto err;
 
-	cs->card_ops->reset(cs);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return (0);
 }
 
-static struct pci_dev *dev_tel __initdata = NULL;
-static u16 __initdata dev_id = PCI_DEVICE_ID_PLX_R685;
-
 int __init
 setup_gazel(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
+	u_char val;
 
 	strcpy(tmp, gazel_revision);
 	printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
 
+	if (cs->typ != ISDN_CTYPE_GAZEL)
+		return (0);
+
 	if (card->para[0]) {
-		printk(KERN_INFO "Gazel: ISA card automatic recognition\n");
-		// we got an irq parameter, assume it is an ISA card
-		// R742 decodes address even in not started...
-		// R647 returns FF if not present or not started
-		// eventually needs improvment
-		card->cs->hw.gazel.ipac = card->para[1];
-		if (ipac_read(card->cs, IPAC_ID) == 1) {
-			if (gazel742_probe(card->cs, card))
-				return 0;
-		} else {
-			if (gazel647_probe(card->cs, card))
-				return 0;
-		}
-		return 1;
+		if (setup_gazelisa(card, cs))
+			return (0);
+	} else {
+
+#if CONFIG_PCI
+		if (setup_gazelpci(cs))
+			return (0);
+#else
+		printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
+		return (0);
+#endif				/* CONFIG_PCI */
 	}
 
-	for (;;) {
-		dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, dev_id, dev_tel);
-		if (dev_tel) {
-			switch (dev_id) {
-			case PCI_DEVICE_ID_PLX_R685:
-				if (gazel685_probe(card->cs, dev_tel))
-					return 0;
-				return 1;
-			case PCI_DEVICE_ID_PLX_R753:
-			case PCI_DEVICE_ID_PLX_DJINN_ITOO:
-				if (gazel753_probe(card->cs, dev_tel))
-					return 0;
-				return 1;
+	if (reserve_regions(card, cs)) {
+		return (0);
+	}
+	if (reset_gazel(cs)) {
+		printk(KERN_WARNING "Gazel: wrong IRQ\n");
+		release_io_gazel(cs);
+		return (0);
+	}
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Gazel_card_msg;
+
+	switch (cs->subtyp) {
+		case R647:
+		case R685:
+			cs->irq_func = &gazel_interrupt;
+			ISACVersion(cs, "Gazel:");
+			if (HscxVersion(cs, "Gazel:")) {
+				printk(KERN_WARNING
+				       "Gazel: wrong HSCX versions check IO address\n");
+				release_io_gazel(cs);
+				return (0);
 			}
-		}
-		switch (dev_id) {
-		case PCI_DEVICE_ID_PLX_R685:
-			dev_id = PCI_DEVICE_ID_PLX_R753;
-		case PCI_DEVICE_ID_PLX_R753:
-			dev_id = PCI_DEVICE_ID_PLX_DJINN_ITOO;
-		default:
 			break;
-		}
+		case R742:
+		case R753:
+			cs->irq_func = &gazel_interrupt_ipac;
+			val = ReadISAC(cs, IPAC_ID - 0x80);
+			printk(KERN_INFO "Gazel: IPAC version %x\n", val);
+			break;
 	}
-	printk(KERN_WARNING "Gazel: No PCI card found\n");
-	return 0;
-}
-
 
+	return (1);
+}
--- diff/drivers/isdn/hisax/hfc_2bds0.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hfc_2bds0.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.15.6.3 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $
  *
  * specific routines for CCD's HFC 2BDS0
  *
@@ -23,10 +23,16 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static inline u8
-ReadReg(struct IsdnCardState *cs, int data, u8 reg)
+static void
+dummyf(struct IsdnCardState *cs, u_char * data, int size)
+{
+	printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");
+}
+
+static inline u_char
+ReadReg(struct IsdnCardState *cs, int data, u_char reg)
 {
-	register u8 ret;
+	register u_char ret;
 
 	if (data) {
 		if (cs->hw.hfcD.cip != reg) { 
@@ -44,7 +50,7 @@
 }
 
 static inline void
-WriteReg(struct IsdnCardState *cs, int data, u8 reg, u8 value)
+WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
 {
 	if (cs->hw.hfcD.cip != reg) { 
 		cs->hw.hfcD.cip = reg;
@@ -58,31 +64,20 @@
 #endif
 }
 
-static struct bc_hw_ops hfcs_bc_ops = {
-	.read_reg  = ReadReg,
-	.write_reg = WriteReg,
-};
-
 /* Interface functions */
 
-static inline u8
-hfcs_read_reg(struct IsdnCardState *cs, u8 offset)
+static u_char
+readreghfcd(struct IsdnCardState *cs, u_char offset)
 {
-	return ReadReg(cs, HFCD_DATA, offset);
+	return(ReadReg(cs, HFCD_DATA, offset));
 }
 
-static inline void
-hfcs_write_reg(struct IsdnCardState *cs, u8 offset, u8 value)
+static void
+writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	WriteReg(cs, HFCD_DATA, offset, value);
 }
 
-void
-set_cs_func(struct IsdnCardState *cs)
-{
-	cs->bc_hw_ops = &hfcs_bc_ops;
-}
-
 static inline int
 WaitForBusy(struct IsdnCardState *cs)
 {
@@ -112,13 +107,12 @@
 }
 
 static int
-SelFiFo(struct IsdnCardState *cs, u8 FiFo)
+SelFiFo(struct IsdnCardState *cs, u_char FiFo)
 {
-	u8 cip;
+	u_char cip;
 
 	if (cs->hw.hfcD.fifo == FiFo)
 		return(1);
-
 	switch(FiFo) {
 		case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;
 			break;
@@ -138,10 +132,11 @@
 	}
 	cs->hw.hfcD.fifo = FiFo;
 	WaitNoBusy(cs);
-	WriteReg(cs, HFCD_DATA, cip, 0);
+	cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);
 	WaitForBusy(cs);
 	return(2);
 }
+
 static int
 GetFreeFifoBytes_B(struct BCState *bcs)
 {
@@ -171,7 +166,7 @@
 }
 
 static int
-ReadZReg(struct IsdnCardState *cs, u8 reg)
+ReadZReg(struct IsdnCardState *cs, u_char reg)
 {
 	int val;
 
@@ -185,12 +180,12 @@
 static struct sk_buff
 *hfc_empty_fifo(struct BCState *bcs, int count)
 {
-	u8 *ptr;
+	u_char *ptr;
 	struct sk_buff *skb;
 	struct IsdnCardState *cs = bcs->cs;
 	int idx;
 	int chksum;
-	u8 stat, cip;
+	u_char stat, cip;
 	
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hfc_empty_fifo");
@@ -264,10 +259,9 @@
 hfc_fill_fifo(struct BCState *bcs)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	u_int idx;
-	int fcnt;
-	u_int count;
-	u8 cip;
+	int idx, fcnt;
+	int count;
+	u_char cip;
 
 	if (!bcs->tx_skb)
 		return;
@@ -320,7 +314,16 @@
 		printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
 	} else {
 		bcs->tx_cnt -= bcs->tx_skb->len;
-		xmit_complete_b(bcs);
+		if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+			(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+			u_long	flags;
+			spin_lock_irqsave(&bcs->aclock, flags);
+			bcs->ackcnt += bcs->tx_skb->len;
+			spin_unlock_irqrestore(&bcs->aclock, flags);
+			schedule_event(bcs, B_ACKPENDING);
+		}
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
 	}
 	WaitForBusy(cs);
 	WaitNoBusy(cs);
@@ -330,17 +333,33 @@
 	return;
 }
 
+static void
+hfc_send_data(struct BCState *bcs)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	
+	if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		hfc_fill_fifo(bcs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		debugl1(cs,"send_data %d blocked", bcs->channel);
+}
+
 void
 main_rec_2bds0(struct BCState *bcs)
 {
 	struct IsdnCardState *cs = bcs->cs;
 	int z1, z2, rcnt;
-	u8 f1, f2, cip;
+	u_char f1, f2, cip;
 	int receive, count = 5;
 	struct sk_buff *skb;
 
     Begin:
 	count--;
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs,"rec_data %d blocked", bcs->channel);
+		return;
+	}
 	SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));
 	cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
 	WaitNoBusy(cs);
@@ -363,7 +382,7 @@
 				bcs->channel, z1, z2, rcnt);
 		if ((skb = hfc_empty_fifo(bcs, rcnt))) {
 			skb_queue_tail(&bcs->rqueue, skb);
-			sched_b_event(bcs, B_RCVBUFREADY);
+			schedule_event(bcs, B_RCVBUFREADY);
 		}
 		rcnt = f1 -f2;
 		if (rcnt<0)
@@ -374,6 +393,7 @@
 			receive = 0;
 	} else
 		receive = 0;
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && receive)
 		goto Begin;	
 	return;
@@ -430,31 +450,57 @@
 static void
 hfc_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+			} else {
+//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			mode_2bs0(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			mode_2bs0(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			mode_2bs0(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -495,7 +541,7 @@
 	if (open_hfcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hfc_l2l1;
+	st->l2.l2l1 = hfc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -503,11 +549,8 @@
 }
 
 static void
-hfcd_bh(void *data)
+hfcd_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
-/*	struct PStack *stptr;
-*/
 	if (!cs)
 		return;
 	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
@@ -543,18 +586,22 @@
 	struct sk_buff *skb;
 	int idx;
 	int rcnt, z1, z2;
-	u8 stat, cip, f1, f2;
+	u_char stat, cip, f1, f2;
 	int chksum;
 	int count=5;
-	u8 *ptr;
+	u_char *ptr;
 
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_dmsg blocked");
+		return(1);
+	}
 	SelFiFo(cs, 4 | HFCD_REC);
 	cip = HFCD_FIFO | HFCD_F1 | HFCD_REC;
 	WaitNoBusy(cs);
-	f1 = hfcs_read_reg(cs, cip) & 0xf;
+	f1 = cs->readisac(cs, cip) & 0xf;
 	cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
 	WaitNoBusy(cs);
-	f2 = hfcs_read_reg(cs, cip) & 0xf;
+	f2 = cs->readisac(cs, cip) & 0xf;
 	while ((f1 != f2) && count--) {
 		z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC);
 		z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC);
@@ -617,7 +664,7 @@
 #endif
 				} else {
 					skb_queue_tail(&cs->rq, skb);
-					sched_d_event(cs, D_RCVBUFREADY);
+					schedule_event(cs, D_RCVBUFREADY);
 				}
 			}
 		} else
@@ -629,17 +676,18 @@
 		WaitForBusy(cs);
 		cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
 		WaitNoBusy(cs);
-		f2 = hfcs_read_reg(cs, cip) & 0xf;
+		f2 = cs->readisac(cs, cip) & 0xf;
 	}
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	return(1);
 } 
 
 static void
 hfc_fill_dfifo(struct IsdnCardState *cs)
 {
-	int fcnt;
-	u_int idx, count;
-	u8 cip;
+	int idx, fcnt;
+	int count;
+	u_char cip;
 
 	if (!cs->tx_skb)
 		return;
@@ -711,26 +759,31 @@
 }
 
 void
-hfc2bds0_interrupt(struct IsdnCardState *cs, u8 val)
+hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
 {
-       	u8 exval;
+       	u_char exval;
        	struct BCState *bcs;
 	int count=15;
 
 	if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "HFCD irq %x", val);
-
+		debugl1(cs, "HFCD irq %x %s", val,
+			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+			"locked" : "unlocked");
 	val &= cs->hw.hfcD.int_m1;
 	if (val & 0x40) { /* TE state machine irq */
-		exval = hfcs_read_reg(cs, HFCD_STATES) & 0xf;
+		exval = cs->readisac(cs, HFCD_STATES) & 0xf;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state,
 				exval);
 		cs->dc.hfcd.ph_state = exval;
-		sched_d_event(cs, D_L1STATECHANGE);
+		schedule_event(cs, D_L1STATECHANGE);
 		val &= ~0x40;
 	}
 	while (val) {
+		if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			cs->hw.hfcD.int_s1 |= val;
+			return;
+		}
 		if (cs->hw.hfcD.int_s1 & 0x18) {
 			exval = val;
 			val =  cs->hw.hfcD.int_s1;
@@ -755,7 +808,23 @@
 				if (cs->debug)
 					debugl1(cs, "hfcd spurious 0x01 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfc_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs,"fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfc_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs,"fill_data %d blocked", bcs->channel);
+					} else {
+						schedule_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x02) {
@@ -763,15 +832,60 @@
 				if (cs->debug)
 					debugl1(cs, "hfcd spurious 0x02 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfc_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs,"fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfc_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs,"fill_data %d blocked", bcs->channel);
+					} else {
+						schedule_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x20) {	/* receive dframe */
 			receive_dmsg(cs);
 		}
 		if (val & 0x04) {	/* dframe transmitted */
-			xmit_xpr_d(cs);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				schedule_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) {
+				if (cs->tx_skb->len) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfc_fill_dfifo(cs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else {
+						debugl1(cs, "hfc_fill_dfifo irq blocked");
+					}
+					goto afterXPR;
+				} else {
+					dev_kfree_skb_irq(cs->tx_skb);
+					cs->tx_cnt = 0;
+					cs->tx_skb = NULL;
+				}
+			}
+			if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+				cs->tx_cnt = 0;
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfc_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else {
+					debugl1(cs, "hfc_fill_dfifo irq blocked");
+				}
+			} else
+				schedule_event(cs, D_XMTBUFREADY);
 		}
+      afterXPR:
 		if (cs->hw.hfcD.int_s1 && count--) {
 			val = cs->hw.hfcD.int_s1;
 			cs->hw.hfcD.int_s1 = 0;
@@ -787,36 +901,101 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 	
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfc_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else
+					debugl1(cs, "hfc_fill_dfifo blocked");
+
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
-		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+		case (PH_PULL | INDICATION):
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				spin_unlock_irqrestore(&cs->lock, flags);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				hfc_fill_dfifo(cs);
+				test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+			} else
+				debugl1(cs, "hfc_fill_dfifo blocked");
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
-			hfcs_write_reg(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
 			udelay(6);
-			hfcs_write_reg(cs, HFCD_STATES, 3); /* HFC ST 2 */
+			cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */
 			cs->hw.hfcD.mst_m |= HFCD_MASTER;
-			hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
-			hfcs_write_reg(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+			cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 			break;
 		case (HW_ENABLE | REQUEST):
-			hfcs_write_reg(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
-			hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcD.mst_m |= HFCD_MASTER;
-			hfcs_write_reg(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -825,11 +1004,10 @@
 	}
 }
 
-static int
+void
 setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = HFCD_l1hw;
-	return 0;
 }
 
 static void
@@ -852,30 +1030,21 @@
 	return(send);
 }
 
-static struct bc_l1_ops hfcd_bc_l1_ops = {
-	.fill_fifo = hfc_fill_fifo,
-	.open      = setstack_2b,
-	.close     = close_2bs0,
-};
-
-static struct dc_l1_ops hfcd_dc_l1_ops = {
-	.fill_fifo  = hfc_fill_dfifo,
-	.open       = setstack_hfcd,
-	.bh_func    = hfcd_bh,
-	.dbusy_func = hfc_dbusy_timer,
-};
-
 void __init
 init2bds0(struct IsdnCardState *cs)
 {
-	dc_l1_init(cs, &hfcd_dc_l1_ops);
-	cs->bc_l1_ops = &hfcd_bc_l1_ops;
+	cs->setstack_d = setstack_hfcd;
 	if (!cs->hw.hfcD.send)
 		cs->hw.hfcD.send = init_send_hfcd(16);
 	if (!cs->bcs[0].hw.hfc.send)
 		cs->bcs[0].hw.hfc.send = init_send_hfcd(32);
 	if (!cs->bcs[1].hw.hfc.send)
 		cs->bcs[1].hw.hfc.send = init_send_hfcd(32);
+	cs->BC_Send_Data = &hfc_send_data;
+	cs->bcs[0].BC_SetStack = setstack_2b;
+	cs->bcs[1].BC_SetStack = setstack_2b;
+	cs->bcs[0].BC_Close = close_2bs0;
+	cs->bcs[1].BC_Close = close_2bs0;
 	mode_2bs0(cs->bcs, 0, 0);
 	mode_2bs0(cs->bcs + 1, 0, 1);
 }
@@ -896,3 +1065,18 @@
 		cs->hw.hfcD.send = NULL;
 	}
 }
+
+void
+set_cs_func(struct IsdnCardState *cs)
+{
+	cs->readisac = &readreghfcd;
+	cs->writeisac = &writereghfcd;
+	cs->readisacfifo = &dummyf;
+	cs->writeisacfifo = &dummyf;
+	cs->BC_Read_Reg = &ReadReg;
+	cs->BC_Write_Reg = &WriteReg;
+	cs->dbusytimer.function = (void *) hfc_dbusy_timer;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+	INIT_WORK(&cs->tqueue, (void *)(void *) hfcd_bh, cs);
+}
--- diff/drivers/isdn/hisax/hfc_2bds0.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hfc_2bds0.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.h,v 1.4.6.2 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * specific defines for CCD's HFC 2BDS0
  *
@@ -124,5 +124,5 @@
 extern void main_irq_2bds0(struct BCState *bcs);
 extern void init2bds0(struct IsdnCardState *cs);
 extern void release2bds0(struct IsdnCardState *cs);
-extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u8 val);
+extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
 extern void set_cs_func(struct IsdnCardState *cs);
--- diff/drivers/isdn/hisax/hfc_2bs0.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hfc_2bs0.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.17.6.3 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $
  *
  * specific routines for CCD's HFC 2BS0
  *
@@ -17,26 +17,14 @@
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
-static inline u8
-hfc_read_reg(struct IsdnCardState *cs, int data, u8 reg)
-{
-	return cs->bc_hw_ops->read_reg(cs, data, reg);
-}
-
-static inline void
-hfc_write_reg(struct IsdnCardState *cs, int data, u8 reg, u8 val)
-{
-	cs->bc_hw_ops->write_reg(cs, data, reg, val);
-}
-
 static inline int
 WaitForBusy(struct IsdnCardState *cs)
 {
 	int to = 130;
-	u8 val;
+	u_char val;
 
-	while (!(hfc_read_reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
-		val = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
+	while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+		val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
 				      (cs->hw.hfc.cip & 3));
 		udelay(1);
 		to--;
@@ -53,7 +41,7 @@
 {
 	int to = 125;
 
-	while ((hfc_read_reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+	while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
 		udelay(1);
 		to--;
 	}
@@ -79,14 +67,14 @@
 }
 
 int
-ReadZReg(struct BCState *bcs, u8 reg)
+ReadZReg(struct BCState *bcs, u_char reg)
 {
 	int val;
 
 	WaitNoBusy(bcs->cs);
-	val = 256 * hfc_read_reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
+	val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
 	WaitNoBusy(bcs->cs);
-	val += hfc_read_reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
+	val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
 	return (val);
 }
 
@@ -96,21 +84,20 @@
 	struct IsdnCardState *cs = bcs->cs;
 	int idx, cnt;
 	int rcnt, z1, z2;
-	u8 cip, f1, f2;
+	u_char cip, f1, f2;
 
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hfc_clear_fifo");
-
 	cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
 	if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
-		hfc_write_reg(cs, HFC_STATUS, cip, cip);
+		cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
 		WaitForBusy(cs);
 	}
 	WaitNoBusy(cs);
-	f1 = hfc_read_reg(cs, HFC_DATA, cip);
+	f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 	cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
 	WaitNoBusy(cs);
-	f2 = hfc_read_reg(cs, HFC_DATA, cip);
+	f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 	z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
 	z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
 	cnt = 32;
@@ -129,21 +116,21 @@
 		cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
 		idx = 0;
 		while ((idx < rcnt) && WaitNoBusy(cs)) {
-			hfc_read_reg(cs, HFC_DATA_NODEB, cip);
+			cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
 			idx++;
 		}
 		if (f1 != f2) {
 			WaitNoBusy(cs);
-			hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+			cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 					HFC_CHANNEL(bcs->channel));
 			WaitForBusy(cs);
 		}
 		cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
 		WaitNoBusy(cs);
-		f1 = hfc_read_reg(cs, HFC_DATA, cip);
+		f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
 		WaitNoBusy(cs);
-		f2 = hfc_read_reg(cs, HFC_DATA, cip);
+		f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
 		z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
 	}
@@ -155,12 +142,12 @@
 *
 hfc_empty_fifo(struct BCState *bcs, int count)
 {
-	u8 *ptr;
+	u_char *ptr;
 	struct sk_buff *skb;
 	struct IsdnCardState *cs = bcs->cs;
 	int idx;
 	int chksum;
-	u8 stat, cip;
+	u_char stat, cip;
 
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hfc_empty_fifo");
@@ -170,9 +157,9 @@
 			debugl1(cs, "hfc_empty_fifo: incoming packet too large");
 		cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
 		while ((idx++ < count) && WaitNoBusy(cs))
-			hfc_read_reg(cs, HFC_DATA_NODEB, cip);
+			cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
 		WaitNoBusy(cs);
-		stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+		stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 				       HFC_CHANNEL(bcs->channel));
 		WaitForBusy(cs);
 		return (NULL);
@@ -182,9 +169,9 @@
 			debugl1(cs, "hfc_empty_fifo: incoming packet too small");
 		cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
 		while ((idx++ < count) && WaitNoBusy(cs))
-			hfc_read_reg(cs, HFC_DATA_NODEB, cip);
+			cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
 		WaitNoBusy(cs);
-		stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+		stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 				       HFC_CHANNEL(bcs->channel));
 		WaitForBusy(cs);
 #ifdef ERROR_STATISTIC
@@ -203,7 +190,7 @@
 		idx = 0;
 		cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
 		while ((idx < count) && WaitNoBusy(cs)) {
-			*ptr++ = hfc_read_reg(cs, HFC_DATA_NODEB, cip);
+			*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
 			idx++;
 		}
 		if (idx != count) {
@@ -212,7 +199,7 @@
 			dev_kfree_skb_any(skb);
 			if (bcs->mode != L1_MODE_TRANS) {
 			  WaitNoBusy(cs);
-			  stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+			  stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 						 HFC_CHANNEL(bcs->channel));
 			  WaitForBusy(cs);
 			}
@@ -220,11 +207,11 @@
 		}
 		if (bcs->mode != L1_MODE_TRANS) {
 		  WaitNoBusy(cs);
-		  chksum = (hfc_read_reg(cs, HFC_DATA, cip) << 8);
+		  chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
 		  WaitNoBusy(cs);
-		  chksum += hfc_read_reg(cs, HFC_DATA, cip);
+		  chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		  WaitNoBusy(cs);
-		  stat = hfc_read_reg(cs, HFC_DATA, cip);
+		  stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		  if (cs->debug & L1_DEB_HSCX)
 		    debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
 			    bcs->channel, chksum, stat);
@@ -237,7 +224,7 @@
 #endif
 		  }
 		  WaitNoBusy(cs);
-		  stat = hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+		  stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 					 HFC_CHANNEL(bcs->channel));
 		  WaitForBusy(cs);
 		}
@@ -249,10 +236,10 @@
 hfc_fill_fifo(struct BCState *bcs)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int fcnt;
-	u_int idx, count;
+	int idx, fcnt;
+	int count;
 	int z1, z2;
-	u8 cip;
+	u_char cip;
 
 	if (!bcs->tx_skb)
 		return;
@@ -261,15 +248,15 @@
 
 	cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
 	if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
-	  hfc_write_reg(cs, HFC_STATUS, cip, cip);
+	  cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
 	  WaitForBusy(cs);
 	}
 	WaitNoBusy(cs);
 	if (bcs->mode != L1_MODE_TRANS) {
-	  bcs->hw.hfc.f1 = hfc_read_reg(cs, HFC_DATA, cip);
+	  bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 	  cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
 	  WaitNoBusy(cs);
-	  bcs->hw.hfc.f2 = hfc_read_reg(cs, HFC_DATA, cip);
+	  bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 	  bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
 	  if (cs->debug & L1_DEB_HSCX)
 	    debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
@@ -305,7 +292,7 @@
 	cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
 	idx = 0;
 	while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
-		hfc_write_reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
+		cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
 	if (idx != bcs->tx_skb->len) {
 		debugl1(cs, "FIFO Send BUSY error");
 		printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
@@ -314,12 +301,20 @@
 		bcs->tx_cnt -= count;
 		if (PACKET_NOACK == bcs->tx_skb->pkt_type)
 			count = -1;
-
-		xmit_complete_b(bcs);
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
 		if (bcs->mode != L1_MODE_TRANS) {
 		  WaitForBusy(cs);
 		  WaitNoBusy(cs);
-		  hfc_read_reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+		  cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+		}
+		if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+			(count >= 0)) {
+			u_long	flags;
+			spin_lock_irqsave(&bcs->aclock, flags);
+			bcs->ackcnt += count;
+			spin_unlock_irqrestore(&bcs->aclock, flags);
+			schedule_event(bcs, B_ACKPENDING);
 		}
 		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 	}
@@ -331,7 +326,7 @@
 {
 	struct IsdnCardState *cs = bcs->cs;
 	int z1, z2, rcnt;
-	u8 f1, f2, cip;
+	u_char f1, f2, cip;
 	int receive, transmit, count = 5;
 	struct sk_buff *skb;
 
@@ -339,16 +334,16 @@
 	count--;
 	cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
 	if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
-		hfc_write_reg(cs, HFC_STATUS, cip, cip);
+		cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
 		WaitForBusy(cs);
 	}
 	WaitNoBusy(cs);
 	receive = 0;
 	if (bcs->mode == L1_MODE_HDLC) {
-		f1 = hfc_read_reg(cs, HFC_DATA, cip);
+		f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
 		WaitNoBusy(cs);
-		f2 = hfc_read_reg(cs, HFC_DATA, cip);
+		f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
 		if (f1 != f2) {
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
@@ -368,14 +363,14 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
 					bcs->channel, z1, z2, rcnt);
+			/*              sti(); */
 			if ((skb = hfc_empty_fifo(bcs, rcnt))) {
 				skb_queue_tail(&bcs->rqueue, skb);
-				sched_b_event(bcs, B_RCVBUFREADY);
+				schedule_event(bcs, B_RCVBUFREADY);
 			}
 		}
 		receive = 1;
 	}
-	udelay(1);
 	if (bcs->tx_skb) {
 		transmit = 1;
 		test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
@@ -391,7 +386,7 @@
 				transmit = 0;
 		} else {
 			transmit = 0;
-			sched_b_event(bcs, B_XMTBUFREADY);
+			schedule_event(bcs, B_XMTBUFREADY);
 		}
 	}
 	if ((receive || transmit) && count)
@@ -423,7 +418,7 @@
 			break;
 		case (L1_MODE_TRANS):
 		        cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */ 
-			hfc_write_reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+			cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
 			hfc_clear_fifo(bcs); /* complete fifo clear */ 
 			if (bc) {
 				cs->hw.hfc.ctmt |= 1;
@@ -447,8 +442,8 @@
 			}
 			break;
 	}
-	hfc_write_reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
-	cs->dc_hw_ops->write_reg(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
+	cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+	cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
 	if (mode == L1_MODE_HDLC)
 		hfc_clear_fifo(bcs);
 }
@@ -456,31 +451,57 @@
 static void
 hfc_l2l1(struct PStack *st, int pr, void *arg)
 {
-	struct sk_buff *skb = arg;
+	struct BCState	*bcs = st->l1.bcs;
+	struct sk_buff	*skb = arg;
+	u_long		flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+			} else {
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			mode_hfc(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			mode_hfc(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			mode_hfc(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -523,7 +544,7 @@
 	if (open_hfcstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hfc_l2l1;
+	st->l2.l2l1 = hfc_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -544,18 +565,16 @@
 		bcs->hw.hfc.send[i] = 0x1fff;
 }
 
-static struct bc_l1_ops hfc_l1_ops = {
-	.fill_fifo = hfc_fill_fifo,
-	.open      = setstack_hfc,
-	.close     = close_hfcstate,
-};
-
 void __init
 inithfc(struct IsdnCardState *cs)
 {
 	init_send(&cs->bcs[0]);
 	init_send(&cs->bcs[1]);
-	cs->bc_l1_ops = &hfc_l1_ops;
+	cs->BC_Send_Data = &hfc_fill_fifo;
+	cs->bcs[0].BC_SetStack = setstack_hfc;
+	cs->bcs[1].BC_SetStack = setstack_hfc;
+	cs->bcs[0].BC_Close = close_hfcstate;
+	cs->bcs[1].BC_Close = close_hfcstate;
 	mode_hfc(cs->bcs, 0, 0);
 	mode_hfc(cs->bcs + 1, 0, 0);
 }
@@ -572,10 +591,3 @@
 		cs->bcs[1].hw.hfc.send = NULL;
 	}
 }
-
-int
-hfc_setup(struct IsdnCardState *cs, struct bc_hw_ops *hfc_ops)
-{
-	cs->bc_hw_ops = hfc_ops;
-	return 0;
-}
--- diff/drivers/isdn/hisax/hfc_2bs0.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/hfc_2bs0.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.h,v 1.3.6.2 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * specific defines for CCD's HFC 2BS0
  *
@@ -58,4 +58,3 @@
 extern void main_irq_hfc(struct BCState *bcs);
 extern void inithfc(struct IsdnCardState *cs);
 extern void releasehfc(struct IsdnCardState *cs);
-extern int  hfc_setup(struct IsdnCardState *cs, struct bc_hw_ops *hfc_ops);
--- diff/drivers/isdn/hisax/hfc_pci.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hfc_pci.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.34.6.8 2001/09/23 22:24:47 kai Exp $
+/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $
  *
  * low level driver for CCD´s hfc-pci based cards
  *
@@ -25,7 +25,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.34.6.8 $";
+static const char *hfcpci_revision = "$Revision: 1.48.2.4 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
@@ -65,45 +65,47 @@
 };
 
 
+#if CONFIG_PCI
+
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
-static void
-hfcpci_release(struct IsdnCardState *cs)
+void
+release_io_hfcpci(struct IsdnCardState *cs)
 {
 	printk(KERN_INFO "HiSax: release hfcpci at %p\n",
 		cs->hw.hfcpci.pci_io);
-	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
+	cs->hw.hfcpci.int_m2 = 0;					/* interrupt output off ! */
 	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
-	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
-	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-	pci_disable_device(cs->hw.hfcpci.pdev);
+	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);			/* Reset On */
+	mdelay(10);
+	Write_hfc(cs, HFCPCI_CIRM, 0);					/* Reset Off */
+	mdelay(10);
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
 	del_timer(&cs->hw.hfcpci.timer);
-	pci_free_consistent(cs->hw.hfcpci.pdev, 32768, cs->hw.hfcpci.fifos, cs->hw.hfcpci.fifos_dma);
-	hisax_release_resources(cs);
+	kfree(cs->hw.hfcpci.share_start);
+	cs->hw.hfcpci.share_start = NULL;
+	iounmap((void *)cs->hw.hfcpci.pci_io);
 }
 
 /********************************************************************************/
 /* function called to reset the HFC PCI chip. A complete software reset of chip */
 /* and fifos is done.                                                           */
 /********************************************************************************/
-static int
-hfcpci_reset(struct IsdnCardState *cs)
+static void
+reset_hfcpci(struct IsdnCardState *cs)
 {
-	pci_disable_device(cs->hw.hfcpci.pdev);
+	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
 	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
 	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
 
 	printk(KERN_INFO "HFC_PCI: resetting card\n");
-	pci_set_master(cs->hw.hfcpci.pdev);
+	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	mdelay(10);
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+	mdelay(10);
 	if (Read_hfc(cs, HFCPCI_STATUS) & 2)
 		printk(KERN_WARNING "HFC-PCI init bit busy\n");
 
@@ -156,9 +158,7 @@
 	/* Finally enable IRQ output */
 	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
 	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
-	if (Read_hfc(cs, HFCPCI_INT_S2));
-	
-	return 0;
+	if (Read_hfc(cs, HFCPCI_INT_S1));
 }
 
 /***************************************************/
@@ -174,6 +174,27 @@
  */
 }
 
+
+/*********************************/
+/* schedule a new D-channel task */
+/*********************************/
+static void
+sched_event_D_pci(struct IsdnCardState *cs, int event)
+{
+	test_and_set_bit(event, &cs->event);
+	schedule_work(&cs->tqueue);
+}
+
+/*********************************/
+/* schedule a new b_channel task */
+/*********************************/
+static void
+hfcpci_sched_event(struct BCState *bcs, int event)
+{
+	test_and_set_bit(event, &bcs->event);
+	schedule_work(&bcs->tqueue);
+}
+
 /************************************************/
 /* select a b-channel entry matching and active */
 /************************************************/
@@ -193,7 +214,7 @@
 /* clear the desired B-channel rx fifo */
 /***************************************/
 static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
-{       u8 fifo_state;
+{       u_char fifo_state;
         bzfifo_type *bzr;
 
 	if (fifo) {
@@ -207,7 +228,7 @@
 	        cs->hw.hfcpci.fifo_en ^= fifo_state;
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 	cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;
-	bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
+	bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
 	bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
 	bzr->f1 = MAX_B_FRAMES;
 	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
@@ -220,7 +241,7 @@
 /* clear the desired B-channel tx fifo */
 /***************************************/
 static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
-{       u8 fifo_state;
+{       u_char fifo_state;
         bzfifo_type *bzt;
 
 	if (fifo) {
@@ -233,7 +254,7 @@
 	if (fifo_state)
 	        cs->hw.hfcpci.fifo_en ^= fifo_state;
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
+	bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
 	bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
 	bzt->f1 = MAX_B_FRAMES;
 	bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
@@ -247,9 +268,9 @@
 /*********************************************/
 static struct sk_buff
 *
-hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u8 * bdata, int count)
+hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count)
 {
-	u8 *ptr, *ptr1, new_f2;
+	u_char *ptr, *ptr1, new_f2;
 	struct sk_buff *skb;
 	struct IsdnCardState *cs = bcs->cs;
 	int total, maxlen, new_z2;
@@ -258,18 +279,18 @@
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hfcpci_empty_fifo");
 	zp = &bz->za[bz->f2];	/* point to Z-Regs */
-	new_z2 = le16_to_cpu(zp->z2) + count;	/* new position in fifo */
+	new_z2 = zp->z2 + count;	/* new position in fifo */
 	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
 	if ((count > HSCX_BUFMAX + 3) || (count < 4) ||
-	    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
+	    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
 #ifdef ERROR_STATISTIC
 		bcs->err_inv++;
 #endif
-		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+		bz->za[new_f2].z2 = new_z2;
 		bz->f2 = new_f2;	/* next buffer */
 		skb = NULL;
 	} else if (!(skb = dev_alloc_skb(count - 3)))
@@ -279,12 +300,12 @@
 		count -= 3;
 		ptr = skb_put(skb, count);
 
-		if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
+		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = count;		/* complete transfer */
 		else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2);	/* maximum */
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
 
-		ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);	/* start of data */
+		ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
 		memcpy(ptr, ptr1, maxlen);	/* copy data */
 		count -= maxlen;
 
@@ -293,7 +314,7 @@
 			ptr1 = bdata;	/* start of buffer */
 			memcpy(ptr, ptr1, count);	/* rest */
 		}
-		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+		bz->za[new_f2].z2 = new_z2;
 		bz->f2 = new_f2;	/* next buffer */
 
 	}
@@ -311,41 +332,45 @@
 	int maxlen;
 	int rcnt, total;
 	int count = 5;
-	u8 *ptr, *ptr1;
+	u_char *ptr, *ptr1;
 	dfifo_type *df;
 	z_type *zp;
 
 	df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx;
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_dmsg blocked");
+		return (1);
+	}
 	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
 		zp = &df->za[df->f2 & D_FREG_MASK];
-		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
+		rcnt = zp->z1 - zp->z2;
 		if (rcnt < 0)
 			rcnt += D_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
-				df->f1, df->f2, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
+				df->f1, df->f2, zp->z1, zp->z2, rcnt);
 
 		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
-		    (df->data[le16_to_cpu(zp->z1)])) {
+		    (df->data[zp->z1])) {
 			if (cs->debug & L1_DEB_WARN)
-				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[le16_to_cpu(zp->z1)]);
+				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
 #ifdef ERROR_STATISTIC
 			cs->err_rx++;
 #endif
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
-			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1));
+			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
 		} else if ((skb = dev_alloc_skb(rcnt - 3))) {
 			total = rcnt;
 			rcnt -= 3;
 			ptr = skb_put(skb, rcnt);
 
-			if ((le16_to_cpu(zp->z2) + rcnt) <= D_FIFO_SIZE)
+			if (zp->z2 + rcnt <= D_FIFO_SIZE)
 				maxlen = rcnt;	/* complete transfer */
 			else
-				maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);	/* maximum */
+				maxlen = D_FIFO_SIZE - zp->z2;	/* maximum */
 
-			ptr1 = df->data + le16_to_cpu(zp->z2);	/* start of data */
+			ptr1 = df->data + zp->z2;	/* start of data */
 			memcpy(ptr, ptr1, maxlen);	/* copy data */
 			rcnt -= maxlen;
 
@@ -355,13 +380,14 @@
 				memcpy(ptr, ptr1, rcnt);	/* rest */
 			}
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
-			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
+			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);
 
 			skb_queue_tail(&cs->rq, skb);
-			sched_d_event(cs, D_RCVBUFREADY);
+			sched_event_D_pci(cs, D_RCVBUFREADY);
 		} else
 			printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
 	}
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	return (1);
 }
 
@@ -369,17 +395,17 @@
 /* check for transparent receive data and read max one threshold size if avail */
 /*******************************************************************************/
 int
-hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u8 * bdata)
+hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
 {
 	unsigned short *z1r, *z2r;
 	int new_z2, fcnt, maxlen;
 	struct sk_buff *skb;
-	u8 *ptr, *ptr1;
+	u_char *ptr, *ptr1;
 
 	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
 	z2r = z1r + 1;
 
-	if (!(fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r)))
+	if (!(fcnt = *z1r - *z2r))
 		return (0);	/* no data avail */
 
 	if (fcnt <= 0)
@@ -387,7 +413,7 @@
 	if (fcnt > HFCPCI_BTRANS_THRESHOLD)
 		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */
 
-	new_z2 = le16_to_cpu(*z2r) + fcnt;	/* new position in fifo */
+	new_z2 = *z2r + fcnt;	/* new position in fifo */
 	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 
@@ -395,12 +421,12 @@
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
 	else {
 		ptr = skb_put(skb, fcnt);
-		if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+		if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = fcnt;	/* complete transfer */
 		else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);	/* maximum */
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
 
-		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);	/* start of data */
+		ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
 		memcpy(ptr, ptr1, maxlen);	/* copy data */
 		fcnt -= maxlen;
 
@@ -410,10 +436,10 @@
 			memcpy(ptr, ptr1, fcnt);	/* rest */
 		}
 		skb_queue_tail(&bcs->rqueue, skb);
-		sched_b_event(bcs, B_RCVBUFREADY);
+		hfcpci_sched_event(bcs, B_RCVBUFREADY);
 	}
 
-	*z2r = cpu_to_le16(new_z2);		/* new position */
+	*z2r = new_z2;		/* new position */
 	return (1);
 }				/* hfcpci_empty_fifo_trans */
 
@@ -428,9 +454,10 @@
 	int receive, count = 5;
 	struct sk_buff *skb;
 	bzfifo_type *bz;
-	u8 *bdata;
+	u_char *bdata;
 	z_type *zp;
 
+
 	if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
 		bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
 		bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
@@ -442,22 +469,26 @@
 	}
       Begin:
 	count--;
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_data %d blocked", bcs->channel);
+		return;
+	}
 	if (bz->f1 != bz->f2) {
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)",
 				bcs->channel, bz->f1, bz->f2);
 		zp = &bz->za[bz->f2];
 
-		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
+		rcnt = zp->z1 - zp->z2;
 		if (rcnt < 0)
 			rcnt += B_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
-				bcs->channel, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
+				bcs->channel, zp->z1, zp->z2, rcnt);
 		if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) {
 			skb_queue_tail(&bcs->rqueue, skb);
-			sched_b_event(bcs, B_RCVBUFREADY);
+			hfcpci_sched_event(bcs, B_RCVBUFREADY);
 		}
 		rcnt = bz->f1 - bz->f2;
 		if (rcnt < 0)
@@ -475,7 +506,7 @@
 		receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
 	else
 		receive = 0;
-
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && receive)
 		goto Begin;
 	return;
@@ -487,10 +518,10 @@
 static void
 hfcpci_fill_dfifo(struct IsdnCardState *cs)
 {
-	int fcnt, new_z1, maxlen;
-	u_int count;
+	int fcnt;
+	int count, new_z1, maxlen;
 	dfifo_type *df;
-	u8 *src, *dst, new_f1;
+	u_char *src, *dst, new_f1;
 
 	if (!cs->tx_skb)
 		return;
@@ -502,7 +533,7 @@
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
 			df->f1, df->f2,
-			le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
+			df->za[df->f1 & D_FREG_MASK].z1);
 	fcnt = df->f1 - df->f2;	/* frame count actually buffered */
 	if (fcnt < 0)
 		fcnt += (MAX_D_FRAMES + 1);	/* if wrap around */
@@ -515,7 +546,7 @@
 		return;
 	}
 	/* now determine free bytes in FIFO buffer */
-	count = le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z2) - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
+	count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1;
 	if (count <= 0)
 		count += D_FIFO_SIZE;	/* count now contains available bytes */
 
@@ -528,12 +559,12 @@
 		return;
 	}
 	count = cs->tx_skb->len;	/* get frame len */
-	new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & (D_FIFO_SIZE - 1);
+	new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1);
 	new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
 	src = cs->tx_skb->data;	/* source pointer */
-	dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
-	maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);		/* end fifo */
-	if (maxlen > (int)count)
+	dst = df->data + df->za[df->f1 & D_FREG_MASK].z1;
+	maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1;		/* end fifo */
+	if (maxlen > count)
 		maxlen = count;	/* limit size */
 	memcpy(dst, src, maxlen);	/* first copy */
 
@@ -543,8 +574,8 @@
 		src += maxlen;	/* new position */
 		memcpy(dst, src, count);
 	}
-	df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* for next buffer */
-	df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* new pos actual buffer */
+	df->za[new_f1 & D_FREG_MASK].z1 = new_z1;	/* for next buffer */
+	df->za[df->f1 & D_FREG_MASK].z1 = new_z1;	/* new pos actual buffer */
 	df->f1 = new_f1;	/* next frame */
 
 	dev_kfree_skb_any(cs->tx_skb);
@@ -559,11 +590,11 @@
 hfcpci_fill_fifo(struct BCState *bcs)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int maxlen, fcnt, new_z1;
-	u_int count;
+	int maxlen, fcnt;
+	int count, new_z1;
 	bzfifo_type *bz;
-	u8 *bdata;
-	u8 new_f1, *src, *dst;
+	u_char *bdata;
+	u_char new_f1, *src, *dst;
 	unsigned short *z1t, *z2t;
 
 	if (!bcs->tx_skb)
@@ -584,24 +615,24 @@
 		z2t = z1t + 1;
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
-				bcs->channel, le16_to_cpu(*z1t), le16_to_cpu(*z2t));
-		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
+				bcs->channel, *z1t, *z2t);
+		fcnt = *z2t - *z1t;
 		if (fcnt <= 0)
 			fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
 		fcnt = B_FIFO_SIZE - fcnt;	/* remaining bytes to send */
 
 		while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
-			if ((int)bcs->tx_skb->len < (B_FIFO_SIZE - fcnt)) {
+			if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
 				/* data is suitable for fifo */
 				count = bcs->tx_skb->len;
 
-				new_z1 = le16_to_cpu(*z1t) + count;	/* new buffer Position */
+				new_z1 = *z1t + count;	/* new buffer Position */
 				if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
 					new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
 				src = bcs->tx_skb->data;	/* source pointer */
-				dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
-				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);	/* end of fifo */
-				if (maxlen > (int)count)
+				dst = bdata + (*z1t - B_SUB_VAL);
+				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t;	/* end of fifo */
+				if (maxlen > count)
 					maxlen = count;		/* limit size */
 				memcpy(dst, src, maxlen);	/* first copy */
 
@@ -613,11 +644,20 @@
 				}
 				bcs->tx_cnt -= bcs->tx_skb->len;
 				fcnt += bcs->tx_skb->len;
-				*z1t = cpu_to_le16(new_z1);	/* now send data */
+				*z1t = new_z1;	/* now send data */
 			} else if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
 					bcs->channel, bcs->tx_skb->len);
 
+			if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+				(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+				u_long	flags;
+				spin_lock_irqsave(&bcs->aclock, flags);
+				bcs->ackcnt += bcs->tx_skb->len;
+				spin_unlock_irqrestore(&bcs->aclock, flags);
+				schedule_event(bcs, B_ACKPENDING);
+			}
+
 			dev_kfree_skb_any(bcs->tx_skb);
 			bcs->tx_skb = skb_dequeue(&bcs->squeue);	/* fetch next data */
 		}
@@ -627,7 +667,7 @@
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
 			bcs->channel, bz->f1, bz->f2,
-			le16_to_cpu(bz->za[bz->f1].z1));
+			bz->za[bz->f1].z1);
 
 	fcnt = bz->f1 - bz->f2;	/* frame count actually buffered */
 	if (fcnt < 0)
@@ -638,7 +678,7 @@
 		return;
 	}
 	/* now determine free bytes in FIFO buffer */
-	count = le16_to_cpu(bz->za[bz->f1].z2) - le16_to_cpu(bz->za[bz->f1].z1);
+	count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1;
 	if (count <= 0)
 		count += B_FIFO_SIZE;	/* count now contains available bytes */
 
@@ -653,15 +693,15 @@
 		return;
 	}
 	count = bcs->tx_skb->len;	/* get frame len */
-	new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;	/* new buffer Position */
+	new_z1 = bz->za[bz->f1].z1 + count;	/* new buffer Position */
 	if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
 
 	new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
 	src = bcs->tx_skb->data;	/* source pointer */
-	dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
-	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);		/* end fifo */
-	if (maxlen > (int)count)
+	dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL);
+	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1;		/* end fifo */
+	if (maxlen > count)
 		maxlen = count;	/* limit size */
 	memcpy(dst, src, maxlen);	/* first copy */
 
@@ -672,11 +712,20 @@
 		memcpy(dst, src, count);
 	}
 	bcs->tx_cnt -= bcs->tx_skb->len;
-	xmit_complete_b(bcs);
+	if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+		(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+		u_long	flags;
+		spin_lock_irqsave(&bcs->aclock, flags);
+		bcs->ackcnt += bcs->tx_skb->len;
+		spin_unlock_irqrestore(&bcs->aclock, flags);
+		schedule_event(bcs, B_ACKPENDING);
+	}
 
-	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
+	bz->za[new_f1].z1 = new_z1;	/* for next buffer */
 	bz->f1 = new_f1;	/* next frame */
 
+	dev_kfree_skb_any(bcs->tx_skb);
+	bcs->tx_skb = NULL;
 	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 	return;
 }
@@ -696,7 +745,7 @@
 			st->l1.l1hw(st, pr, arg);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 			break;
 		case (PH_TESTLOOP | REQUEST):
 			if (1 & (long) arg)
@@ -722,10 +771,12 @@
 static int
 hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
 {
-	int i = *(unsigned int *) ic->parm.num;
+	u_long	flags;
+	int	i = *(unsigned int *) ic->parm.num;
 
 	if ((ic->arg == 98) &&
 	    (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
+	    	spin_lock_irqsave(&cs->lock, flags);
 		Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
 		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0);	/* HFC ST G0 */
 		udelay(10);
@@ -738,7 +789,8 @@
 		cs->dc.hfcpci.ph_state = 1;
 		cs->hw.hfcpci.nt_mode = 1;
 		cs->hw.hfcpci.nt_timer = 0;
-		cs->stlist->l1.l2l1 = dch_nt_l2l1;
+		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		spin_unlock_irqrestore(&cs->lock, flags);
 		debugl1(cs, "NT mode activated");
 		return (0);
 	}
@@ -746,6 +798,7 @@
 	    (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
 		return (-EINVAL);
 
+	spin_lock_irqsave(&cs->lock, flags);
 	if (i) {
 		cs->logecho = 1;
 		cs->hw.hfcpci.trm |= 0x20;	/* enable echo chan */
@@ -768,6 +821,7 @@
 	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return (0);
 }				/* hfcpci_auxcmd */
 
@@ -780,50 +834,54 @@
 	int rcnt;
 	int receive, count = 5;
 	bzfifo_type *bz;
-	u8 *bdata;
+	u_char *bdata;
 	z_type *zp;
-	u8 *ptr, *ptr1, new_f2;
+	u_char *ptr, *ptr1, new_f2;
 	int total, maxlen, new_z2;
-	u8 e_buffer[256];
+	u_char e_buffer[256];
 
 	bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
 	bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
       Begin:
 	count--;
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "echo_rec_data blocked");
+		return;
+	}
 	if (bz->f1 != bz->f2) {
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)",
 				bz->f1, bz->f2);
 		zp = &bz->za[bz->f2];
 
-		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
+		rcnt = zp->z1 - zp->z2;
 		if (rcnt < 0)
 			rcnt += B_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
-				le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
-		new_z2 = le16_to_cpu(zp->z2) + rcnt;		/* new position in fifo */
+				zp->z1, zp->z2, rcnt);
+		new_z2 = zp->z2 + rcnt;		/* new position in fifo */
 		if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 			new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 		new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
 		if ((rcnt > 256 + 3) || (count < 4) ||
-		    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
+		    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
-			bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+			bz->za[new_f2].z2 = new_z2;
 			bz->f2 = new_f2;	/* next buffer */
 		} else {
 			total = rcnt;
 			rcnt -= 3;
 			ptr = e_buffer;
 
-			if (le16_to_cpu(zp->z2) <= (B_FIFO_SIZE + B_SUB_VAL))
+			if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
 				maxlen = rcnt;	/* complete transfer */
 			else
-				maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2);	/* maximum */
+				maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
 
-			ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);	/* start of data */
+			ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
 			memcpy(ptr, ptr1, maxlen);	/* copy data */
 			rcnt -= maxlen;
 
@@ -832,7 +890,7 @@
 				ptr1 = bdata;	/* start of buffer */
 				memcpy(ptr, ptr1, rcnt);	/* rest */
 			}
-			bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+			bz->za[new_f2].z2 = new_z2;
 			bz->f2 = new_f2;	/* next buffer */
 			if (cs->debug & DEB_DLOG_HEX) {
 				ptr = cs->dlog;
@@ -861,6 +919,7 @@
 			receive = 0;
 	} else
 		receive = 0;
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && receive)
 		goto Begin;
 	return;
@@ -872,28 +931,30 @@
 static irqreturn_t
 hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
+	u_long flags;
 	struct IsdnCardState *cs = dev_id;
-	u8 exval;
+	u_char exval;
 	struct BCState *bcs;
 	int count = 15;
-	u8 val, stat;
+	u_char val, stat;
 
-	if (!cs) {
-		printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
-		return IRQ_NONE;
+	if (!(cs->hw.hfcpci.int_m2 & 0x08)) {
+		debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2);
+		return IRQ_NONE;	/* not initialised */
 	}
-	if (!(cs->hw.hfcpci.int_m2 & 0x08))
-		return IRQ_NONE;		/* not initialised */
-
+	spin_lock_irqsave(&cs->lock, flags);
 	if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
 		val = Read_hfc(cs, HFCPCI_INT_S1);
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val);
-	} else
+	} else {
+		spin_unlock_irqrestore(&cs->lock, flags);
 		return IRQ_NONE;
-
+	}
 	if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "HFC-PCI irq %x", val);
+		debugl1(cs, "HFC-PCI irq %x %s", val,
+			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+			"locked" : "unlocked");
 	val &= cs->hw.hfcpci.int_m1;
 	if (val & 0x40) {	/* state machine irq */
 		exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
@@ -901,18 +962,23 @@
 			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
 				exval);
 		cs->dc.hfcpci.ph_state = exval;
-		sched_d_event(cs, D_L1STATECHANGE);
+		sched_event_D_pci(cs, D_L1STATECHANGE);
 		val &= ~0x40;
 	}
 	if (val & 0x80) {	/* timer irq */
 		if (cs->hw.hfcpci.nt_mode) {
 			if ((--cs->hw.hfcpci.nt_timer) < 0)
-				sched_d_event(cs, D_L1STATECHANGE);
+				sched_event_D_pci(cs, D_L1STATECHANGE);
 		}
 		val &= ~0x80;
 		Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
 	}
 	while (val) {
+		if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			cs->hw.hfcpci.int_s1 |= val;
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return IRQ_HANDLED;
+		}
 		if (cs->hw.hfcpci.int_s1 & 0x18) {
 			exval = val;
 			val = cs->hw.hfcpci.int_s1;
@@ -939,7 +1005,23 @@
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x01 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcpci_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcpci_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						hfcpci_sched_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x02) {
@@ -947,15 +1029,60 @@
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x02 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcpci_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcpci_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						hfcpci_sched_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x20) {	/* receive dframe */
 			receive_dmsg(cs);
 		}
 		if (val & 0x04) {	/* dframe transmitted */
-			xmit_xpr_d(cs);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				sched_event_D_pci(cs, D_CLEARBUSY);
+			if (cs->tx_skb) {
+				if (cs->tx_skb->len) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcpci_fill_dfifo(cs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else {
+						debugl1(cs, "hfcpci_fill_dfifo irq blocked");
+					}
+					goto afterXPR;
+				} else {
+					dev_kfree_skb_irq(cs->tx_skb);
+					cs->tx_cnt = 0;
+					cs->tx_skb = NULL;
+				}
+			}
+			if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+				cs->tx_cnt = 0;
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfcpci_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else {
+					debugl1(cs, "hfcpci_fill_dfifo irq blocked");
+				}
+			} else
+				sched_event_D_pci(cs, D_XMTBUFREADY);
 		}
+	      afterXPR:
 		if (cs->hw.hfcpci.int_s1 && count--) {
 			val = cs->hw.hfcpci.int_s1;
 			cs->hw.hfcpci.int_s1 = 0;
@@ -964,6 +1091,7 @@
 		} else
 			val = 0;
 	}
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -981,40 +1109,106 @@
 static void
 HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
 {
+	u_long flags;
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfcpci_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else
+					debugl1(cs, "hfcpci_fill_dfifo blocked");
+
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_d(cs, skb);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				spin_unlock_irqrestore(&cs->lock, flags);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				hfcpci_fill_dfifo(cs);
+				test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+			} else
+				debugl1(cs, "hfcpci_fill_dfifo blocked");
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3);	/* HFC ST 3 */
 			udelay(6);
 			Write_hfc(cs, HFCPCI_STATES, 3);	/* HFC ST 2 */
 			cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
 			Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 			break;
 		case (HW_ENABLE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_TESTLOOP | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			switch ((int) arg) {
 				case (1):
 					Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* tx slot */
@@ -1031,12 +1225,14 @@
 					break;
 
 				default:
+					spin_unlock_irqrestore(&cs->lock, flags);
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
 					return;
 			}
 			cs->hw.hfcpci.trm |= 0x80;	/* enable IOM-loop */
 			Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -1048,11 +1244,25 @@
 /***********************************************/
 /* called during init setting l1 stack pointer */
 /***********************************************/
-static int
+void
 setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = HFCPCI_l1hw;
-	return 0;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcpci_send_data(struct BCState *bcs)
+{
+	struct IsdnCardState *cs = bcs->cs;
+
+	if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		hfcpci_fill_fifo(bcs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		debugl1(cs, "send_data %d blocked", bcs->channel);
 }
 
 /***************************************************************/
@@ -1182,31 +1392,58 @@
 static void
 hfcpci_l2l1(struct PStack *st, int pr, void *arg)
 {
-	struct sk_buff *skb = arg;
+	struct BCState	*bcs = st->l1.bcs;
+	u_long		flags;
+	struct sk_buff	*skb = arg;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ 				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				spin_unlock_irqrestore(&bcs->cs->lock, flags);
+				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+				break;
+			}
+//			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bcs->tx_skb = skb;
+			bcs->cs->BC_Send_Data(bcs);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			mode_hfcpci(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			mode_hfcpci(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			mode_hfcpci(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			mode_hfcpci(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1256,7 +1493,7 @@
 	if (open_hfcpcistate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hfcpci_l2l1;
+	st->l2.l2l1 = hfcpci_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -1267,11 +1504,11 @@
 /* handle L1 state changes */
 /***************************/
 static void
-hfcpci_bh(void *data)
+hfcpci_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
-/*      struct PStack *stptr;
- */
+	u_long	flags;
+//      struct PStack *stptr;
+
 	if (!cs)
 		return;
 	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
@@ -1295,6 +1532,7 @@
 				default:
 					break;
 		} else {
+			spin_lock_irqsave(&cs->lock, flags);
 			switch (cs->dc.hfcpci.ph_state) {
 				case (2):
 					if (cs->hw.hfcpci.nt_timer < 0) {
@@ -1303,7 +1541,6 @@
 						Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
 						/* Clear already pending ints */
 						if (Read_hfc(cs, HFCPCI_INT_S1));
-
 						Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
 						udelay(10);
 						Write_hfc(cs, HFCPCI_STATES, 4);
@@ -1329,6 +1566,7 @@
 				default:
 					break;
 			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 		}
 	}
 	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
@@ -1337,18 +1575,6 @@
 		DChannel_proc_xmt(cs);
 }
 
-static struct bc_l1_ops hfcpci_bc_l1_ops = {
-	.fill_fifo = hfcpci_fill_fifo,
-	.open      = setstack_2b,
-	.close     = close_hfcpci,
-};
-
-static struct dc_l1_ops hfcpci_dc_l1_ops = {
-	.fill_fifo  = hfcpci_fill_dfifo,
-	.open       = setstack_hfcpci,
-	.bh_func    = hfcpci_bh,
-	.dbusy_func = hfcpci_dbusy_timer,
-};
 
 /********************************/
 /* called for card init message */
@@ -1356,116 +1582,167 @@
 void __init
 inithfcpci(struct IsdnCardState *cs)
 {
-	dc_l1_init(cs, &hfcpci_dc_l1_ops);
-	cs->bc_l1_ops = &hfcpci_bc_l1_ops;
+	cs->bcs[0].BC_SetStack = setstack_2b;
+	cs->bcs[1].BC_SetStack = setstack_2b;
+	cs->bcs[0].BC_Close = close_hfcpci;
+	cs->bcs[1].BC_Close = close_hfcpci;
+	cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 	mode_hfcpci(cs->bcs, 0, 0);
 	mode_hfcpci(cs->bcs + 1, 0, 1);
 }
 
-static void
-hfcpci_init(struct IsdnCardState *cs)
-{
-	inithfcpci(cs);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
-	/* now switch timer interrupt off */
-	cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
-	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	/* reinit mode reg */
-	Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
-}
 
-static struct card_ops hfcpci_ops = {
-	.init     = hfcpci_init,
-	.reset    = hfcpci_reset,
-	.release  = hfcpci_release,
-	.irq_func = hfcpci_interrupt,
-};
 
-
-static int __init
-niccy_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev, int i)
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	int rc;
-
-	rc = -EBUSY;
-	if (pci_enable_device(pdev))
-		goto err;
-
-	pci_set_master(pdev);
-
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.hfcpci.pdev = pdev;
-
-	cs->hw.hfcpci.pci_io = request_mmio(&cs->rs, 
-					    pci_resource_start(pdev, 1), 128,
-					    "hfc_pci");
-	if (!cs->hw.hfcpci.pci_io)
-		goto err;
-	
-	/* Allocate memory for FIFOS */
-	rc = -ENOMEM;
-	cs->hw.hfcpci.fifos = pci_alloc_consistent(pdev, 32768, 
-						   &cs->hw.hfcpci.fifos_dma);
-	if (!cs->hw.hfcpci.fifos)
-		goto err;
-
-	pci_write_config_dword(cs->hw.hfcpci.pdev, 0x80,
-			       (u_int)cs->hw.hfcpci.fifos_dma);
-	printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s name: %s\n",
-	       id_list[i].vendor_name, id_list[i].card_name);
-	printk(KERN_INFO "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d\n",
-	       (u_int) cs->hw.hfcpci.pci_io, (u_int) cs->hw.hfcpci.fifos,
-	       (u_int) cs->hw.hfcpci.fifos_dma, cs->irq);
-	printk("ChipID: %x\n", Read_hfc(cs, HFCPCI_CHIP_ID));
-	cs->hw.hfcpci.int_m2 = 0;	/* disable alle interrupts */
-	cs->hw.hfcpci.int_m1 = 0;
-	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
-	/* At this point the needed PCI config is done */
-	/* fifos are still not enabled */
+	u_long flags;
 
-	init_timer(&cs->hw.hfcpci.timer);
-	cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
-	cs->hw.hfcpci.timer.data = (long) cs;
-
-	hfcpci_reset(cs);
-	cs->auxcmd = &hfcpci_auxcmd;
-	cs->card_ops = &hfcpci_ops;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "HFCPCI: card_msg %x", mt);
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_hfcpci(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_RELEASE:
+			release_io_hfcpci(cs);
+			return (0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithfcpci(cs);
+			reset_hfcpci(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
+			/* now switch timer interrupt off */
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+			Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+			/* reinit mode reg */
+			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
+	}
+	return (0);
 }
 
+
 /* this variable is used as card index when more than one cards are present */
 static struct pci_dev *dev_hfcpci __initdata = NULL;
 
+#endif				/* CONFIG_PCI */
+
 int __init
 setup_hfcpci(struct IsdnCard *card)
 {
+	u_long flags;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 	int i;
 	struct pci_dev *tmp_hfcpci = NULL;
 
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
+#if CONFIG_PCI
 	cs->hw.hfcpci.int_s1 = 0;
 	cs->dc.hfcpci.ph_state = 0;
 	cs->hw.hfcpci.fifo = 255;
+	if (cs->typ == ISDN_CTYPE_HFC_PCI) {
+		i = 0;
+		while (id_list[i].vendor_id) {
+			tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+						     id_list[i].device_id,
+						     dev_hfcpci);
+			i++;
+			if (tmp_hfcpci) {
+				if (pci_enable_device(tmp_hfcpci))
+					continue;
+				pci_set_master(tmp_hfcpci);
+				if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
+					continue;
+				else
+					break;
+			}
+		}
 
-	for (i = 0; id_list[i].vendor_id; i++) {
-		tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
-					     id_list[i].device_id,
-					     dev_hfcpci);
-		if (!tmp_hfcpci)
-			continue;
-
-		if (niccy_pci_probe(card->cs, tmp_hfcpci, i) < 0)
+		if (tmp_hfcpci) {
+			i--;
+			dev_hfcpci = tmp_hfcpci;	/* old device */
+			cs->hw.hfcpci.dev = dev_hfcpci;
+			cs->irq = dev_hfcpci->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+				return (0);
+			}
+			cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
+			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
+		} else {
+			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+			return (0);
+		}
+		if (!cs->hw.hfcpci.pci_io) {
+			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
+			return (0);
+		}
+		/* Allocate memory for FIFOS */
+		/* Because the HFC-PCI needs a 32K physical alignment, we */
+		/* need to allocate the double mem and align the address */
+		if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
+			printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
 			return 0;
-		return 1;
-	}
-	return 0;
+		}
+		cs->hw.hfcpci.fifos = (void *)
+		    (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
+		pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+		cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
+		printk(KERN_INFO
+		       "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+		       (u_int) cs->hw.hfcpci.pci_io,
+		       (u_int) cs->hw.hfcpci.fifos,
+		       (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
+		       cs->irq, HZ);
+		spin_lock_irqsave(&cs->lock, flags);
+		pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+		cs->hw.hfcpci.int_m2 = 0;	/* disable alle interrupts */
+		cs->hw.hfcpci.int_m1 = 0;
+		Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+		Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+		/* At this point the needed PCI config is done */
+		/* fifos are still not enabled */
+		INIT_WORK(&cs->tqueue, (void *)(void *) hfcpci_bh, cs);
+		cs->setstack_d = setstack_hfcpci;
+		cs->BC_Send_Data = &hfcpci_send_data;
+		cs->readisac = NULL;
+		cs->writeisac = NULL;
+		cs->readisacfifo = NULL;
+		cs->writeisacfifo = NULL;
+		cs->BC_Read_Reg = NULL;
+		cs->BC_Write_Reg = NULL;
+		cs->irq_func = &hfcpci_interrupt;
+		cs->irq_flags |= SA_SHIRQ;
+		cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
+		cs->hw.hfcpci.timer.data = (long) cs;
+		init_timer(&cs->hw.hfcpci.timer);
+		cs->cardmsg = &hfcpci_card_msg;
+		cs->auxcmd = &hfcpci_auxcmd;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return (1);
+	} else
+		return (0);	/* no valid card type */
+#else
+	printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
+	return (0);
+#endif				/* CONFIG_PCI */
 }
--- diff/drivers/isdn/hisax/hfc_pci.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hfc_pci.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.h,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * specific defines for CCD's HFC 2BDS0 PCI chips
  *
@@ -185,53 +185,51 @@
 typedef struct {
     unsigned short z1;  /* Z1 pointer 16 Bit */
     unsigned short z2;  /* Z2 pointer 16 Bit */
-  } __attribute__((packed)) z_type;
+  } z_type;
 
 typedef struct {
-    u8 data[D_FIFO_SIZE]; /* FIFO data space */
-    u8 fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
-    u8 f1,f2; /* f pointers */
-    u8 fill2[0x20C0-0x20A2]; /* reserved, do not use */
+    u_char data[D_FIFO_SIZE]; /* FIFO data space */
+    u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
+    u_char f1,f2; /* f pointers */
+    u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */
     z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */
-    u8 fill3[0x4000-0x2100]; /* align 16K */  
-  } __attribute__((packed)) dfifo_type;
+    u_char fill3[0x4000-0x2100]; /* align 16K */  
+  } dfifo_type;
 
 typedef struct {
     z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ 
-    u8 f1,f2; /* f pointers */
-    u8 fill[0x2100-0x2082]; /* alignment */
-  } __attribute__((packed)) bzfifo_type;
+    u_char f1,f2; /* f pointers */
+    u_char fill[0x2100-0x2082]; /* alignment */
+  } bzfifo_type;
 
 
 typedef union {
     struct { 
       dfifo_type d_tx; /* D-send channel */
       dfifo_type d_rx; /* D-receive channel */
-    } __attribute__((packed)) d_chan; 
+    } d_chan; 
     struct {
-      u8 fill1[0x200];
-      u8 txdat_b1[B_FIFO_SIZE];
+      u_char fill1[0x200];
+      u_char txdat_b1[B_FIFO_SIZE];
       bzfifo_type txbz_b1;
 
       bzfifo_type txbz_b2;
-      u8 txdat_b2[B_FIFO_SIZE];
+      u_char txdat_b2[B_FIFO_SIZE];
 
-      u8 fill2[D_FIFO_SIZE];
+      u_char fill2[D_FIFO_SIZE];
 
-      u8 rxdat_b1[B_FIFO_SIZE];
+      u_char rxdat_b1[B_FIFO_SIZE];
       bzfifo_type rxbz_b1;
 
       bzfifo_type rxbz_b2;
-      u8 rxdat_b2[B_FIFO_SIZE];
-    } __attribute__((packed)) b_chans;  
-    u8 fill[32768]; 
-  } __attribute__((packed)) fifo_area;
+      u_char rxdat_b2[B_FIFO_SIZE];
+    } b_chans;  
+    u_char fill[32768]; 
+  } fifo_area;
 
 
-//#define Write_hfc(a,b,c) (*(((u8 *)a->hw.hfcpci.pci_io)+b) = c) 
-//#define Read_hfc(a,b) (*(((u8 *)a->hw.hfcpci.pci_io)+b))
-#define Write_hfc(a,b,c)	writeb(c, ((u8 *)a->hw.hfcpci.pci_io)+b)
-#define Read_hfc(a,b)		readb(((u8 *)a->hw.hfcpci.pci_io)+b)
+#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c) 
+#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
 
 extern void main_irq_hcpci(struct BCState *bcs);
 extern void inithfcpci(struct IsdnCardState *cs);
--- diff/drivers/isdn/hisax/hfc_sx.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hfc_sx.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,6 +1,6 @@
-/* $Id: hfc_sx.c,v 1.9.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $
  *
- * level driver for CCD´s hfc-s+/sp based cards
+ * level driver for Cologne Chip Designs hfc-s+/sp based cards
  *
  * Author       Werner Cornelius
  *              based on existing driver for CCD HFC PCI cards
@@ -20,7 +20,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcsx_revision = "$Revision: 1.9.6.3 $";
+static const char *hfcsx_revision = "$Revision: 1.12.2.5 $";
 
 /***************************************/
 /* IRQ-table for CCDs demo board       */
@@ -43,11 +43,11 @@
 
 #undef CCD_DEMO_BOARD
 #ifdef CCD_DEMO_BOARD
-static u8 ccd_sp_irqtab[16] = {
+static u_char ccd_sp_irqtab[16] = {
   0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
 };
 #else /* Teles 16.3c */
-static u8 ccd_sp_irqtab[16] = {
+static u_char ccd_sp_irqtab[16] = {
   0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
 };
 #endif
@@ -60,17 +60,16 @@
 /* In/Out access to registers */
 /******************************/
 static inline void
-Write_hfc(struct IsdnCardState *cs, u8 regnum, u8 val)
+Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
 {
-
         byteout(cs->hw.hfcsx.base+1, regnum);
 	byteout(cs->hw.hfcsx.base, val);
 } 
 
-static inline u8
-Read_hfc(struct IsdnCardState *cs, u8 regnum)
+static inline u_char
+Read_hfc(struct IsdnCardState *cs, u_char regnum)
 {
-        u8 ret; 
+        u_char ret; 
 
         byteout(cs->hw.hfcsx.base+1, regnum);
 	ret = bytein(cs->hw.hfcsx.base);
@@ -82,7 +81,7 @@
 /* select a fifo and remember which one for reuse */
 /**************************************************/
 static void
-fifo_select(struct IsdnCardState *cs, u8 fifo)
+fifo_select(struct IsdnCardState *cs, u_char fifo)
 {
         if (fifo == cs->hw.hfcsx.last_fifo) 
 	  return; /* still valid */
@@ -97,10 +96,10 @@
 
 /******************************************/
 /* reset the specified fifo to defaults.  */
-/* If it's a send fifo init needed markers */
+/* If its a send fifo init needed markers */
 /******************************************/
 static void
-reset_fifo(struct IsdnCardState *cs, u8 fifo)
+reset_fifo(struct IsdnCardState *cs, u_char fifo)
 {
 	fifo_select(cs, fifo); /* first select the fifo */
 	byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
@@ -116,10 +115,11 @@
 /* the skb is not released in any way.                       */
 /*************************************************************/
 static int
-write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u8 fifo, int trans_max)
-{       unsigned short *msp;
+write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
+{
+       unsigned short *msp;
         int fifo_size, count, z1, z2;
-	u8 f_msk, f1, f2, *src;
+	u_char f_msk, f1, f2, *src;
 
 	if (skb->len <= 0) return(0);
         if (fifo & 1) return(0); /* no write fifo */
@@ -145,9 +145,9 @@
 	  count = z2 - z1;
 	  if (count <= 0)
 	    count += fifo_size; /* free bytes */
-	  if (count < (int)(skb->len+1)) return(0); /* no room */
+	  if (count < skb->len+1) return(0); /* no room */
 	  count = fifo_size - count; /* bytes still not send */
-	  if (count > 2 * trans_max) return(0); /* delay too long */
+	  if (count > 2 * trans_max) return(0); /* delay to long */
 	  count = skb->len;
 	  src = skb->data;
 	  while (count--)
@@ -182,7 +182,7 @@
 	if (cs->debug & L1_DEB_ISAC_FIFO)
 	  debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
 		  fifo, skb->len, count);
-	if (count < (int)skb->len) {
+	if (count < skb->len) {
 	  if (cs->debug & L1_DEB_ISAC_FIFO)
 	    debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
 	  return(0);
@@ -205,9 +205,9 @@
 /* the skb is not released in any way.                         */
 /***************************************************************/
 static struct sk_buff * 
-read_fifo(struct IsdnCardState *cs, u8 fifo, int trans_max)
+read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
 {       int fifo_size, count, z1, z2;
-	u8 f_msk, f1, f2, *dst;
+	u_char f_msk, f1, f2, *dst;
 	struct sk_buff *skb;
 
         if (!(fifo & 1)) return(NULL); /* no read fifo */
@@ -308,8 +308,8 @@
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
-static void
-hfcsx_release(struct IsdnCardState *cs)
+void
+release_io_hfcsx(struct IsdnCardState *cs)
 {
 	cs->hw.hfcsx.int_m2 = 0;	/* interrupt output off ! */
 	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
@@ -318,7 +318,7 @@
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCSX_CIRM, 0);	/* Reset Off */
 	del_timer(&cs->hw.hfcsx.timer);
-	hisax_release_resources(cs);
+	release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
 	kfree(cs->hw.hfcsx.extra);
 	cs->hw.hfcsx.extra = NULL;
 }
@@ -347,8 +347,8 @@
 /* function called to reset the HFC SX chip. A complete software reset of chip */
 /* and fifos is done.                                                           */
 /********************************************************************************/
-static int
-hfcsx_reset(struct IsdnCardState *cs)
+static void
+reset_hfcsx(struct IsdnCardState *cs)
 {
 	cs->hw.hfcsx.int_m2 = 0;	/* interrupt output off ! */
 	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
@@ -356,11 +356,9 @@
 	printk(KERN_INFO "HFC_SX: resetting card\n");
 	while (1) {
 	  Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
-	  set_current_state(TASK_UNINTERRUPTIBLE);
-	  schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	  mdelay(30);
 	  Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
-	  set_current_state(TASK_UNINTERRUPTIBLE);
-	  schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+	  mdelay(20);
 	  if (Read_hfc(cs, HFCSX_STATUS) & 2)
 	    printk(KERN_WARNING "HFC-SX init bit busy\n");
 	  cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
@@ -415,7 +413,6 @@
 	cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
 	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
 	if (Read_hfc(cs, HFCSX_INT_S2));
-	return 0;
 }
 
 /***************************************************/
@@ -431,7 +428,6 @@
  */
 }
 
-
 /************************************************/
 /* select a b-channel entry matching and active */
 /************************************************/
@@ -450,20 +446,27 @@
 /*******************************/
 /* D-channel receive procedure */
 /*******************************/
-static int
+static
+int
 receive_dmsg(struct IsdnCardState *cs)
 {
 	struct sk_buff *skb;
 	int count = 5;
 
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_dmsg blocked");
+		return (1);
+	}
+
 	do {
 	  skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
 	  if (skb) {
 	    skb_queue_tail(&cs->rq, skb);
-	    sched_d_event(cs, D_RCVBUFREADY);
+	    schedule_event(cs, D_RCVBUFREADY);
 	  }
 	} while (--count && skb);
 
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	return (1);
 }
 
@@ -479,6 +482,10 @@
 
       Begin:
 	count--;
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_data %d blocked", bcs->channel);
+		return;
+	}
 	skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? 
 			HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
 			(bcs->mode == L1_MODE_TRANS) ? 
@@ -486,9 +493,10 @@
 
 	if (skb) {
 	  skb_queue_tail(&bcs->rqueue, skb);
-	  sched_b_event(bcs, B_RCVBUFREADY);
+	  schedule_event(bcs, B_RCVBUFREADY);
 	}
 
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && skb)
 		goto Begin;
 	return;
@@ -509,6 +517,7 @@
 	  dev_kfree_skb_any(cs->tx_skb);
 	  cs->tx_skb = NULL;
 	}
+	return;
 }
 
 /**************************/
@@ -530,9 +539,18 @@
 		       (bcs->mode == L1_MODE_TRANS) ? 
 		       HFCSX_BTRANS_THRESHOLD : 0)) {
 
-		bcs->tx_cnt -= bcs->tx_skb->len;
-		xmit_complete_b(bcs);
-		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	  bcs->tx_cnt -= bcs->tx_skb->len;
+	  if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+		(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+		u_long	flags;
+		spin_lock_irqsave(&bcs->aclock, flags);
+		bcs->ackcnt += bcs->tx_skb->len;
+		spin_unlock_irqrestore(&bcs->aclock, flags);
+		schedule_event(bcs, B_ACKPENDING);
+	  }
+	  dev_kfree_skb_any(bcs->tx_skb);
+	  bcs->tx_skb = NULL;
+	  test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 	}
 }
 
@@ -551,7 +569,7 @@
 			st->l1.l1hw(st, pr, arg);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 			break;
 		case (PH_TESTLOOP | REQUEST):
 			if (1 & (long) arg)
@@ -577,10 +595,12 @@
 static int
 hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
 {
+	unsigned long flags;
 	int i = *(unsigned int *) ic->parm.num;
 
 	if ((ic->arg == 98) &&
 	    (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
+	    	spin_lock_irqsave(&cs->lock, flags);
 		Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0);	/* HFC ST G0 */
 		udelay(10);
 		cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
@@ -592,7 +612,8 @@
 		cs->dc.hfcsx.ph_state = 1;
 		cs->hw.hfcsx.nt_mode = 1;
 		cs->hw.hfcsx.nt_timer = 0;
-		cs->stlist->l1.l2l1 = dch_nt_l2l1;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		cs->stlist->l2.l2l1 = dch_nt_l2l1;
 		debugl1(cs, "NT mode activated");
 		return (0);
 	}
@@ -614,12 +635,14 @@
 	cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
 	cs->hw.hfcsx.conn |= 0x10;	/* B2-IOM -> B2-ST */
 	cs->hw.hfcsx.ctmt &= ~2;
+	spin_lock_irqsave(&cs->lock, flags);
 	Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
 	Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
 	Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
 	Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
 	Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
 	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return (0);
 }				/* hfcsx_auxcmd */
 
@@ -630,9 +653,13 @@
 receive_emsg(struct IsdnCardState *cs)
 {
 	int count = 5;
-	u8 *ptr;
+	u_char *ptr;
 	struct sk_buff *skb;
 
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "echo_rec_data blocked");
+		return;
+	}
 	do {
 	  skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
 	  if (skb) {
@@ -655,6 +682,9 @@
 	    dev_kfree_skb_any(skb);
 	  }
 	} while (--count && skb);
+
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	return;
 }				/* receive_emsg */
 
 
@@ -665,27 +695,28 @@
 hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 exval;
+	u_char exval;
 	struct BCState *bcs;
 	int count = 15;
-	u8 val, stat;
+	u_long flags;
+	u_char val, stat;
 
-	if (!cs) {
-		printk(KERN_WARNING "HFC-SX: Spurious interrupt!\n");
-		return IRQ_NONE;
-	}
 	if (!(cs->hw.hfcsx.int_m2 & 0x08))
 		return IRQ_NONE;		/* not initialised */
 
+	spin_lock_irqsave(&cs->lock, flags);
 	if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
 		val = Read_hfc(cs, HFCSX_INT_S1);
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
-	} else
+	} else {
+		spin_unlock_irqrestore(&cs->lock, flags);
 		return IRQ_NONE;
-
+	}
 	if (cs->debug & L1_DEB_ISAC)
-		debugl1(cs, "HFC-SX irq %x", val);
+		debugl1(cs, "HFC-SX irq %x %s", val,
+			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+			"locked" : "unlocked");
 	val &= cs->hw.hfcsx.int_m1;
 	if (val & 0x40) {	/* state machine irq */
 		exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
@@ -693,18 +724,23 @@
 			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
 				exval);
 		cs->dc.hfcsx.ph_state = exval;
-		sched_d_event(cs, D_L1STATECHANGE);
+		schedule_event(cs, D_L1STATECHANGE);
 		val &= ~0x40;
 	}
 	if (val & 0x80) {	/* timer irq */
 		if (cs->hw.hfcsx.nt_mode) {
 			if ((--cs->hw.hfcsx.nt_timer) < 0)
-				sched_d_event(cs, D_L1STATECHANGE);
+				schedule_event(cs, D_L1STATECHANGE);
 		}
 		val &= ~0x80;
 		Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
 	}
 	while (val) {
+		if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			cs->hw.hfcsx.int_s1 |= val;
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return IRQ_HANDLED;
+		}
 		if (cs->hw.hfcsx.int_s1 & 0x18) {
 			exval = val;
 			val = cs->hw.hfcsx.int_s1;
@@ -731,7 +767,23 @@
 				if (cs->debug)
 					debugl1(cs, "hfcsx spurious 0x01 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcsx_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						schedule_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x02) {
@@ -739,15 +791,60 @@
 				if (cs->debug)
 					debugl1(cs, "hfcsx spurious 0x02 IRQ");
 			} else {
-				xmit_xpr_b(bcs);
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcsx_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						schedule_event(bcs, B_XMTBUFREADY);
+					}
+				}
 			}
 		}
 		if (val & 0x20) {	/* receive dframe */
 			receive_dmsg(cs);
 		}
 		if (val & 0x04) {	/* dframe transmitted */
-			xmit_xpr_d(cs);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				schedule_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) {
+				if (cs->tx_skb->len) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_dfifo(cs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else {
+						debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+					}
+					goto afterXPR;
+				} else {
+					dev_kfree_skb_irq(cs->tx_skb);
+					cs->tx_cnt = 0;
+					cs->tx_skb = NULL;
+				}
+			}
+			if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+				cs->tx_cnt = 0;
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfcsx_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else {
+					debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+				}
+			} else
+				schedule_event(cs, D_XMTBUFREADY);
 		}
+	      afterXPR:
 		if (cs->hw.hfcsx.int_s1 && count--) {
 			val = cs->hw.hfcsx.int_s1;
 			cs->hw.hfcsx.int_s1 = 0;
@@ -756,6 +853,7 @@
 		} else
 			val = 0;
 	}
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -775,38 +873,104 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				        hfcsx_fill_dfifo(cs); 
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else
+					debugl1(cs, "hfcsx_fill_dfifo blocked");
+
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
-		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+		case (PH_PULL | INDICATION):
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				spin_unlock_irqrestore(&cs->lock, flags);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				hfcsx_fill_dfifo(cs); 
+				test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+			} else
+				debugl1(cs, "hfcsx_fill_dfifo blocked");
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3);	/* HFC ST 3 */
 			udelay(6);
 			Write_hfc(cs, HFCSX_STATES, 3);	/* HFC ST 2 */
 			cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
 			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
 			Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 			break;
 		case (HW_ENABLE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
 			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
 			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_TESTLOOP | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			switch ((int) arg) {
 				case (1):
 					Write_hfc(cs, HFCSX_B1_SSL, 0x80);	/* tx slot */
@@ -814,21 +978,21 @@
 					cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
 					Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
 					break;
-
 				case (2):
 					Write_hfc(cs, HFCSX_B2_SSL, 0x81);	/* tx slot */
 					Write_hfc(cs, HFCSX_B2_RSL, 0x81);	/* rx slot */
 					cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
 					Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
 					break;
-
 				default:
+					spin_unlock_irqrestore(&cs->lock, flags);
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
 					return;
 			}
 			cs->hw.hfcsx.trm |= 0x80;	/* enable IOM-loop */
 			Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -840,11 +1004,25 @@
 /***********************************************/
 /* called during init setting l1 stack pointer */
 /***********************************************/
-static int
+void
 setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = HFCSX_l1hw;
-	return 0;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcsx_send_data(struct BCState *bcs)
+{
+	struct IsdnCardState *cs = bcs->cs;
+
+	if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+	  hfcsx_fill_fifo(bcs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		debugl1(cs, "send_data %d blocked", bcs->channel);
 }
 
 /***************************************************************/
@@ -963,31 +1141,57 @@
 static void
 hfcsx_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+//                              test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+			} else {
+//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			mode_hfcsx(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			mode_hfcsx(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			mode_hfcsx(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			mode_hfcsx(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1037,7 +1241,7 @@
 	if (open_hfcsxstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hfcsx_l2l1;
+	st->l2.l2l1 = hfcsx_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -1048,10 +1252,12 @@
 /* handle L1 state changes */
 /***************************/
 static void
-hfcsx_bh(void *data)
+hfcsx_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
+	u_long flags;
 
+	if (!cs)
+		return;
 	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
 		if (!cs->hw.hfcsx.nt_mode)
 			switch (cs->dc.hfcsx.ph_state) {
@@ -1075,6 +1281,7 @@
 		} else {
 			switch (cs->dc.hfcsx.ph_state) {
 				case (2):
+					spin_lock_irqsave(&cs->lock, flags);
 					if (cs->hw.hfcsx.nt_timer < 0) {
 						cs->hw.hfcsx.nt_timer = 0;
 						cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
@@ -1096,13 +1303,16 @@
 						cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
 						Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3);	/* allow G2 -> G3 transition */
 					}
+					spin_unlock_irqrestore(&cs->lock, flags);
 					break;
 				case (1):
 				case (3):
 				case (4):
+					spin_lock_irqsave(&cs->lock, flags);
 					cs->hw.hfcsx.nt_timer = 0;
 					cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
 					Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+					spin_unlock_irqrestore(&cs->lock, flags);
 					break;
 				default:
 					break;
@@ -1115,18 +1325,6 @@
 		DChannel_proc_xmt(cs);
 }
 
-static struct bc_l1_ops hfcsx_bc_l1_ops = {
-	.fill_fifo = hfcsx_fill_fifo,
-	.open      = setstack_2b,
-	.close     = close_hfcsx,
-};
-
-static struct dc_l1_ops hfcsx_dc_l1_ops = {
-	.fill_fifo  = hfcsx_fill_dfifo,
-	.open       = setstack_hfcsx,
-	.bh_func    = hfcsx_bh,
-	.dbusy_func = hfcsx_dbusy_timer,
-};
 
 /********************************/
 /* called for card init message */
@@ -1134,98 +1332,55 @@
 void __devinit
 inithfcsx(struct IsdnCardState *cs)
 {
-	dc_l1_init(cs, &hfcsx_dc_l1_ops);
-	cs->bc_l1_ops = &hfcsx_bc_l1_ops;
+	cs->setstack_d = setstack_hfcsx;
+	cs->BC_Send_Data = &hfcsx_send_data;
+	cs->bcs[0].BC_SetStack = setstack_2b;
+	cs->bcs[1].BC_SetStack = setstack_2b;
+	cs->bcs[0].BC_Close = close_hfcsx;
+	cs->bcs[1].BC_Close = close_hfcsx;
 	mode_hfcsx(cs->bcs, 0, 0);
 	mode_hfcsx(cs->bcs + 1, 0, 1);
 }
 
-static void
-hfcsx_init(struct IsdnCardState *cs)
-{
-	inithfcsx(cs);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
-	/* now switch timer interrupt off */
-	cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
-	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
-	/* reinit mode reg */
-	Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
-}
 
-static struct card_ops hfcsx_ops = {
-	.init     = hfcsx_init,
-	.reset    = hfcsx_reset,
-	.release  = hfcsx_release,
-	.irq_func = hfcsx_interrupt,
-};
 
-static int __init
-hfcsx_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	int rc;
-	char c;
+	u_long flags;
 
-	cs->irq = card->para[0];
-	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
-
-	cs->hw.hfcsx.fifo = 255;
-	cs->hw.hfcsx.int_s1 = 0;
-	cs->dc.hfcsx.ph_state = 0;
-
-	rc = -EBUSY;
-	if (!request_io(&cs->rs, cs->hw.hfcsx.base, 2, "HFCSX isdn"))
-		goto err;
-
-	rc = -ENODEV;
-	byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
-	byteout(cs->hw.hfcsx.base + 1, ((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
-	udelay(10);
-	cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
-	switch (cs->hw.hfcsx.chip >> 4) {
-	case 1: 
-		c ='+';
-		break;
-	case 9: 
-		c ='P';
-		break;
-	default:
-		printk(KERN_WARNING "HFC-SX: invalid chip id 0x%x\n",
-		       cs->hw.hfcsx.chip >> 4);
-		goto err;
-	}  
-	if (!ccd_sp_irqtab[cs->irq & 0xF]) {
-		printk(KERN_WARNING "HFC_SX: invalid irq %d specified\n",
-		       cs->irq & 0xF);
-		goto err;
-	}
-	rc = -ENOMEM;
-	cs->hw.hfcsx.extra = kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC);
-	if (!cs->hw.hfcsx.extra) {
-		printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
-		goto err;
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "HFCSX: card_msg %x", mt);
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_hfcsx(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_RELEASE:
+			release_io_hfcsx(cs);
+			return (0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithfcsx(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
+			/* now switch timer interrupt off */
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+			Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+			/* reinit mode reg */
+			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
 	}
-	printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d\n",
-	       c, (u_int) cs->hw.hfcsx.base, cs->irq);
-
-	cs->hw.hfcsx.int_m2 = 0;	/* disable alle interrupts */
-	cs->hw.hfcsx.int_m1 = 0;
-	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
-	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
-
-	init_timer(&cs->hw.hfcsx.timer);
-	cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
-	cs->hw.hfcsx.timer.data = (long) cs;
-	cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
-	cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not eval. */
-
-	hfcsx_reset(cs);
-	cs->auxcmd = &hfcsx_auxcmd;
-	cs->card_ops = &hfcsx_ops;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
+	return (0);
 }
 
 #ifdef __ISAPNP__
@@ -1236,66 +1391,133 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __devinit
 setup_hfcsx(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, hfcsx_revision);
 	printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev  *pd;
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-		while(hdev->card_vendor) {
-			if ((pb = pnp_find_card(hdev->card_vendor,
-						hdev->card_device,
-						pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       hdev->vendor,
-						       hdev->function,
-						       pd))) {
 					printk(KERN_INFO "HiSax: %s detected\n",
-						(char *)hdev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "HFC PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "HFC PnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) {
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+					if (!card->para[0] || !card->para[1]) {
 						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
-							pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
 						return(0);
 					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
 					break;
 				} else {
 					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
 				}
 			}
-			hdev++;
-			pnp_c=NULL;
+			ipid++;
+			pnp_c = NULL;
 		} 
-		if (!hdev->card_vendor) {
+		if (!ipid->card_vendor) {
 			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
 			return(0);
 		}
 	}
 #endif
-	if (hfcsx_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
+	cs->irq = card->para[0];
+	cs->hw.hfcsx.int_s1 = 0;
+	cs->dc.hfcsx.ph_state = 0;
+	cs->hw.hfcsx.fifo = 255;
+	if ((cs->typ == ISDN_CTYPE_HFC_SX) || 
+	    (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) {
+	        if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) {
+		  printk(KERN_WARNING
+			 "HiSax: HFC-SX io-base %#lx already in use\n",
+		          cs->hw.hfcsx.base);
+		  return(0);
+		}
+		byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
+		byteout(cs->hw.hfcsx.base + 1,
+			((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
+		udelay(10);
+	        cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
+                switch (cs->hw.hfcsx.chip >> 4) {
+		  case 1: 
+		    tmp[0] ='+';
+		    break;
+		  case 9: 
+		    tmp[0] ='P';
+		    break;
+		  default:
+		    printk(KERN_WARNING
+			   "HFC-SX: invalid chip id 0x%x\n",
+			   cs->hw.hfcsx.chip >> 4);
+		    release_region(cs->hw.hfcsx.base, 2);
+		    return(0);
+		}  
+		if (!ccd_sp_irqtab[cs->irq & 0xF]) {
+		  printk(KERN_WARNING 
+			 "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF);
+		  release_region(cs->hw.hfcsx.base, 2);
+		  return(0);
+		}  
+		if (!(cs->hw.hfcsx.extra = (void *)
+		      kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
+		  release_region(cs->hw.hfcsx.base, 2);
+		  printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
+		  return(0);
+		}
+		printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
+			tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ);
+		cs->hw.hfcsx.int_m2 = 0;	/* disable alle interrupts */
+		cs->hw.hfcsx.int_m1 = 0;
+		Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+		Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+	} else
+		return (0);	/* no valid card type */
+
+	cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+	INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs);
+	cs->readisac = NULL;
+	cs->writeisac = NULL;
+	cs->readisacfifo = NULL;
+	cs->writeisacfifo = NULL;
+	cs->BC_Read_Reg = NULL;
+	cs->BC_Write_Reg = NULL;
+	cs->irq_func = &hfcsx_interrupt;
+
+	cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
+	cs->hw.hfcsx.timer.data = (long) cs;
+	cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
+	cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
+	init_timer(&cs->hw.hfcsx.timer);
+
+	reset_hfcsx(cs);
+	cs->cardmsg = &hfcsx_card_msg;
+	cs->auxcmd = &hfcsx_auxcmd;
+	return (1);
 }
--- diff/drivers/isdn/hisax/hfcscard.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/hfcscard.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hfcscard.c,v 1.8.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $
  *
  * low level stuff for hfcs based cards (Teles3c, ACER P10)
  *
@@ -18,33 +18,19 @@
 
 extern const char *CardType[];
 
-static const char *hfcs_revision = "$Revision: 1.8.6.2 $";
-
-static inline u8
-hfcs_read_reg(struct IsdnCardState *cs, int data, u8 reg)
-{
-	return cs->bc_hw_ops->read_reg(cs, data, reg);
-}
-
-static inline void
-hfcs_write_reg(struct IsdnCardState *cs, int data, u8 reg, u8 val)
-{
-	cs->bc_hw_ops->write_reg(cs, data, reg, val);
-}
+static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
 
 static irqreturn_t
 hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val, stat;
+	u_char val, stat;
+	u_long flags;
 
-	if (!cs) {
-		printk(KERN_WARNING "HFCS: Spurious interrupt!\n");
-		return IRQ_NONE;
-	}
+	spin_lock_irqsave(&cs->lock, flags);
 	if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & 
-		(stat = hfcs_read_reg(cs, HFCD_DATA, HFCD_STAT))) {
-		val = hfcs_read_reg(cs, HFCD_DATA, HFCD_INT_S1);
+		(stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
+		val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
 		hfc2bds0_interrupt(cs, val);
@@ -52,6 +38,7 @@
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
 	}
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -65,117 +52,91 @@
 */
 }
 
-static void
-hfcs_release(struct IsdnCardState *cs)
+void
+release_io_hfcs(struct IsdnCardState *cs)
 {
 	release2bds0(cs);
 	del_timer(&cs->hw.hfcD.timer);
-	hisax_release_resources(cs);
+	if (cs->hw.hfcD.addr)
+		release_region(cs->hw.hfcD.addr, 2);
 }
 
-static int
-hfcs_reset(struct IsdnCardState *cs)
+static void
+reset_hfcs(struct IsdnCardState *cs)
 {
 	printk(KERN_INFO "HFCS: resetting card\n");
 	cs->hw.hfcD.cirm = HFCD_RESET;
 	if (cs->typ == ISDN_CTYPE_TELES3C)
 		cs->hw.hfcD.cirm |= HFCD_MEM8K;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30*HZ)/1000);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset On */
+	mdelay(10);
 	cs->hw.hfcD.cirm = 0;
 	if (cs->typ == ISDN_CTYPE_TELES3C)
 		cs->hw.hfcD.cirm |= HFCD_MEM8K;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset Off */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset Off */
+	mdelay(10);
 	if (cs->typ == ISDN_CTYPE_TELES3C)
 		cs->hw.hfcD.cirm |= HFCD_INTB;
 	else if (cs->typ == ISDN_CTYPE_ACERP10)
 		cs->hw.hfcD.cirm |= HFCD_INTA;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
 	cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
 	cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
 	cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
 		HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
 		HFCD_INTS_DREC | HFCD_INTS_L1STATE;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
 	udelay(10);
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
 	cs->hw.hfcD.mst_m = HFCD_MASTER;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
 	cs->hw.hfcD.sctrl = 0;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
-	return 0;
+	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
 }
 
-static void
-hfcs_init(struct IsdnCardState *cs)
-{
-	cs->hw.hfcD.timer.expires = jiffies + 75;
-	add_timer(&cs->hw.hfcD.timer);
-	init2bds0(cs);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((80*HZ)/1000);
-	cs->hw.hfcD.ctmt |= HFCD_TIM800;
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
-	hfcs_write_reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
-}
-
-static struct card_ops hfcs_ops = {
-	.init     = hfcs_init,
-	.reset    = hfcs_reset,
-	.release  = hfcs_release,
-	.irq_func = hfcs_interrupt,
-};
-
-static int __init
-hfcs_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static int
+hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	cs->irq = card->para[0];
-	cs->hw.hfcD.addr = card->para[1];
+	u_long flags;
+	int delay;
 
-	if (!request_io(&cs->rs, cs->hw.hfcD.addr, 2, "HFCS isdn"))
-		goto err;
-
-	printk(KERN_INFO "HFCS: defined at 0x%x IRQ %d\n",
-	       cs->hw.hfcD.addr, cs->irq);
-
-	cs->hw.hfcD.cip = 0;
-	cs->hw.hfcD.int_s1 = 0;
-	cs->hw.hfcD.send = NULL;
-	cs->bcs[0].hw.hfc.send = NULL;
-	cs->bcs[1].hw.hfc.send = NULL;
-	cs->hw.hfcD.dfifosize = 512;
-	cs->dc.hfcd.ph_state = 0;
-	cs->hw.hfcD.fifo = 255;
-
-	if (cs->typ == ISDN_CTYPE_TELES3C) {
-		cs->hw.hfcD.bfifosize = 1024 + 512;
-		/* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
-		outb(0x00, cs->hw.hfcD.addr);
-		outb(0x56, cs->hw.hfcD.addr | 1);
-	} else if (cs->typ == ISDN_CTYPE_ACERP10) {
-		cs->hw.hfcD.bfifosize = 7*1024 + 512;
-		/* Acer P10 IO ADR is 0x300 */
-		outb(0x00, cs->hw.hfcD.addr);
-		outb(0x57, cs->hw.hfcD.addr | 1);
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "HFCS: card_msg %x", mt);
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_hfcs(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_hfcs(cs);
+			return(0);
+		case CARD_INIT:
+			delay = (75*HZ)/100 +1;
+			cs->hw.hfcD.timer.expires = jiffies + delay;
+			add_timer(&cs->hw.hfcD.timer);
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_hfcs(cs);
+			init2bds0(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			delay = (80*HZ)/1000 +1;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout((80*HZ)/1000);
+			spin_lock_irqsave(&cs->lock, flags);
+			cs->hw.hfcD.ctmt |= HFCD_TIM800;
+			cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
+			cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	set_cs_func(cs);
-	init_timer(&cs->hw.hfcD.timer);
-	cs->hw.hfcD.timer.function = (void *) hfcs_Timer;
-	cs->hw.hfcD.timer.data = (long) cs;
-	hfcs_reset(cs);
-	cs->card_ops = &hfcs_ops;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return(0);
 }
 
 #ifdef __ISAPNP__
@@ -204,13 +165,14 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __init
 setup_hfcs(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, hfcs_revision);
@@ -218,54 +180,88 @@
 
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-		while(hdev->card_vendor) {
-			if ((pb = pnp_find_card(hdev->card_vendor,
-						hdev->card_device,
-						pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       hdev->vendor,
-						       hdev->function,
-						       pd))) {
 					printk(KERN_INFO "HiSax: %s detected\n",
-						(char *)hdev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "HFC PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "HFC PnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) {
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+					if (!card->para[0] || !card->para[1]) {
 						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
-							pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
 						return(0);
 					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
 					break;
 				} else {
 					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
 				}
 			}
-			hdev++;
-			pnp_c=NULL;
+			ipid++;
+			pnp_c = NULL;
 		} 
-		if (!hdev->card_vendor) {
+		if (!ipid->card_vendor) {
 			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
 			return(0);
 		}
 	}
 #endif
-	if (hfcs_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
-	
+	cs->hw.hfcD.addr = card->para[1] & 0xfffe;
+	cs->irq = card->para[0];
+	cs->hw.hfcD.cip = 0;
+	cs->hw.hfcD.int_s1 = 0;
+	cs->hw.hfcD.send = NULL;
+	cs->bcs[0].hw.hfc.send = NULL;
+	cs->bcs[1].hw.hfc.send = NULL;
+	cs->hw.hfcD.dfifosize = 512;
+	cs->dc.hfcd.ph_state = 0;
+	cs->hw.hfcD.fifo = 255;
+	if (cs->typ == ISDN_CTYPE_TELES3C) {
+		cs->hw.hfcD.bfifosize = 1024 + 512;
+	} else if (cs->typ == ISDN_CTYPE_ACERP10) {
+		cs->hw.hfcD.bfifosize = 7*1024 + 512;
+	} else
+		return (0);
+	if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.hfcD.addr,
+		       cs->hw.hfcD.addr + 2);
+		return (0);
+	}
+	printk(KERN_INFO
+	       "HFCS: defined at 0x%x IRQ %d HZ %d\n",
+	       cs->hw.hfcD.addr,
+	       cs->irq, HZ);
+	if (cs->typ == ISDN_CTYPE_TELES3C) {
+		/* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
+		outb(0x00, cs->hw.hfcD.addr);
+		outb(0x56, cs->hw.hfcD.addr | 1);
+	} else if (cs->typ == ISDN_CTYPE_ACERP10) {
+		/* Acer P10 IO ADR is 0x300 */
+		outb(0x00, cs->hw.hfcD.addr);
+		outb(0x57, cs->hw.hfcD.addr | 1);
+	}
+	set_cs_func(cs);
+	cs->hw.hfcD.timer.function = (void *) hfcs_Timer;
+	cs->hw.hfcD.timer.data = (long) cs;
+	init_timer(&cs->hw.hfcD.timer);
+	cs->cardmsg = &hfcs_card_msg;
+	cs->irq_func = &hfcs_interrupt;
+	return (1);
 }
--- diff/drivers/isdn/hisax/hisax.h	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hisax.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 1.1.4.1.2.1 2001/12/09 20:18:40 kai Exp $
+/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $
  *
  * Basic declarations, defines and prototypes
  *
@@ -6,14 +6,11 @@
  * of the GNU General Public License, incorporated herein by reference.
  *
  */
-
-#ifndef __HISAX_H__
-#define __HISAX_H__
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
+#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -28,7 +25,6 @@
 #include <linux/tty.h>
 #include <linux/serial_reg.h>
 #include <linux/netdevice.h>
-#include <linux/interrupt.h>
 
 #define ERROR_STATISTIC
 
@@ -51,6 +47,11 @@
 #define HW_INFO4_P10	0x0048
 #define HW_RSYNC	0x0060
 #define HW_TESTLOOP	0x0070
+#define CARD_RESET	0x00F0
+#define CARD_INIT	0x00F2
+#define CARD_RELEASE	0x00F3
+#define CARD_TEST	0x00F4
+#define CARD_AUX_IND	0x00F5
 
 #define PH_ACTIVATE	0x0100
 #define PH_DEACTIVATE	0x0110
@@ -68,9 +69,14 @@
 #define DL_FLUSH	0x0224
 #define DL_UNIT_DATA	0x0230
 
+#define MDL_BC_RELEASE  0x0278  // Formula-n enter:now
+#define MDL_BC_ASSIGN   0x027C  // Formula-n enter:now
 #define MDL_ASSIGN	0x0280
 #define MDL_REMOVE	0x0284
 #define MDL_ERROR	0x0288
+#define MDL_INFO_SETUP	0x02E0
+#define MDL_INFO_CONN	0x02E4
+#define MDL_INFO_REL	0x02E8
 
 #define CC_SETUP	0x0300
 #define CC_RESUME	0x0304
@@ -145,35 +151,6 @@
 /* #define I4L_IRQ_FLAG SA_INTERRUPT */
 #define I4L_IRQ_FLAG    0
 
-struct res {
-	struct list_head node;
-	const char *name;
-	unsigned long start, end;
-	unsigned long flags;
-	union {
-		void *ioremap_addr;
-	} r_u;
-};
-
-struct resources {
-	struct list_head res_head;
-};
-
-void
-resources_init(struct resources *rs);
-
-void
-resources_release(struct resources *rs);
-
-unsigned long
-request_io(struct resources *rs, unsigned long start, int len,
-	   const char *name);
-
-void *
-request_mmio(struct resources *rs, unsigned long start, int len,
-	     const char *name);
-
-
 /*
  * Statemachine
  */
@@ -230,9 +207,9 @@
 	long Flags;
 	struct FsmInst l1m;
 	struct FsmTimer	timer;
+	void (*l1l2) (struct PStack *, int, void *);
 	void (*l1hw) (struct PStack *, int, void *);
 	void (*l1tei) (struct PStack *, int, void *);
-	void (*l2l1) (struct PStack *, int, void *);
 	int mode, bc;
 	int delay;
 };
@@ -265,17 +242,18 @@
 struct Layer2 {
 	int tei;
 	int sap;
-	u_int maxlen;
-	unsigned long flag;
-	unsigned int vs, va, vr;
+	int maxlen;
+	u_long flag;
+	spinlock_t lock;
+	u_int vs, va, vr;
 	int rc;
 	unsigned int window;
 	unsigned int sow;
 	struct sk_buff *windowar[MAX_WINDOW];
 	struct sk_buff_head i_queue;
 	struct sk_buff_head ui_queue;
-	void (*l3l2) (struct PStack *, int, void *);
-	void (*l1l2) (struct PStack *, int, void *);
+	void (*l2l1) (struct PStack *, int, void *);
+	void (*l2l3) (struct PStack *, int, void *);
 	void (*l2tei) (struct PStack *, int, void *);
 	struct FsmInst l2m;
 	struct FsmTimer t200, t203;
@@ -285,10 +263,9 @@
 };
 
 struct Layer3 {
-	void (*l4l3) (struct PStack *, int, void *);
-        int  (*l4l3_proto) (struct PStack *, isdn_ctrl *);
+	void (*l3l4) (struct PStack *, int, void *);
         void (*l3ml3) (struct PStack *, int, void *);
-	void (*l2l3) (struct PStack *, int, void *);
+	void (*l3l2) (struct PStack *, int, void *);
 	struct FsmInst l3m;
         struct FsmTimer l3m_timer;
 	struct sk_buff_head squeue;
@@ -300,10 +277,14 @@
 };
 
 struct LLInterface {
-	void (*l3l4) (struct PStack *, int, void *);
+	void (*l4l3) (struct PStack *, int, void *);
+        int  (*l4l3_proto) (struct PStack *, isdn_ctrl *);
 	void *userdata;
+	u_long flag;
 };
 
+#define	FLG_LLI_L1WAKEUP	1
+#define	FLG_LLI_L2WAKEUP	2
 
 struct Management {
 	int	ri;
@@ -316,14 +297,14 @@
 #define NO_CAUSE 254
 
 struct Param {
-	u8 cause;
-	u8 loc;
-	u8 diag[6];
+	u_char cause;
+	u_char loc;
+	u_char diag[6];
 	int bchannel;
 	int chargeinfo;
 	int spv;		/* SPV Flag */
 	setup_parm setup;	/* from isdnif.h numbers and Serviceindicator */
-	u8 moderate;	/* transfer mode and rate (bearer octet 4) */
+	u_char moderate;	/* transfer mode and rate (bearer octet 4) */
 };
 
 
@@ -338,7 +319,7 @@
 
         /* protocol specific data fields */
         union
-	 { u8 uuuu; /* only as dummy */
+	 { u_char uuuu; /* only as dummy */
 #ifdef CONFIG_HISAX_EURO
            dss1_stk_priv dss1; /* private dss1 data */
 #endif /* CONFIG_HISAX_EURO */              
@@ -362,7 +343,7 @@
 
         /* protocol specific data fields */
         union 
-	 { u8 uuuu; /* only when euro not defined, avoiding empty union */
+	 { u_char uuuu; /* only when euro not defined, avoiding empty union */
 #ifdef CONFIG_HISAX_EURO 
            dss1_proc_priv dss1; /* private dss1 data */
 #endif /* CONFIG_HISAX_EURO */            
@@ -373,50 +354,58 @@
 };
 
 struct hscx_hw {
-	u8 tsaxr0;
-	u8 tsaxr1;
+	int hscx;
+	int rcvidx;
+	int count;              /* Current skb sent count */
+	u_char *rcvbuf;         /* B-Channel receive Buffer */
+	u_char tsaxr0;
+	u_char tsaxr1;
 };
 
 struct w6692B_hw {
 	int bchan;
+	int rcvidx;
+	int count;              /* Current skb sent count */
+	u_char *rcvbuf;         /* B-Channel receive Buffer */
 };
 
 struct isar_reg {
 	unsigned long Flags;
-	volatile u8 bstat;
-	volatile u8 iis;
-	volatile u8 cmsb;
-	volatile u8 clsb;
-	volatile u8 par[8];
+	volatile u_char bstat;
+	volatile u_char iis;
+	volatile u_char cmsb;
+	volatile u_char clsb;
+	volatile u_char par[8];
 };
 
 struct isar_hw {
 	int dpath;
 	int rcvidx;
+	int txcnt;
 	int mml;
-	u8 state;
-	u8 cmd;
-	u8 mod;
-	u8 newcmd;
-	u8 newmod;
+	u_char state;
+	u_char cmd;
+	u_char mod;
+	u_char newcmd;
+	u_char newmod;
 	char try_mod;
 	struct timer_list ftimer;
-	u8 *rcvbuf;         /* B-Channel receive Buffer */
-	u8 conmsg[16];
+	u_char *rcvbuf;         /* B-Channel receive Buffer */
+	u_char conmsg[16];
 	struct isar_reg *reg;
 };
 
 struct hdlc_stat_reg {
 #ifdef __BIG_ENDIAN
-	u8 fill __attribute__((packed));
-	u8 mode __attribute__((packed));
-	u8 xml  __attribute__((packed));
-	u8 cmd  __attribute__((packed));
-#else
-	u8 cmd  __attribute__((packed));
-	u8 xml  __attribute__((packed));
-	u8 mode __attribute__((packed));
-	u8 fill __attribute__((packed));
+	u_char fill __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char cmd  __attribute__((packed));
+#else
+	u_char cmd  __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char fill __attribute__((packed));
 #endif
 };
 
@@ -426,6 +415,9 @@
 		struct hdlc_stat_reg sr;
 	} ctrl;
 	u_int stat;
+	int rcvidx;
+	int count;              /* Current skb sent count */
+	u_char *rcvbuf;         /* B-Channel receive Buffer */
 };
 
 struct hfcB_hw {
@@ -436,36 +428,35 @@
 
 struct tiger_hw {
 	u_int *send;
-	dma_addr_t send_dma;
+	u_int *s_irq;
 	u_int *s_end;
 	u_int *sendp;
 	u_int *rec;
-	dma_addr_t rec_dma;
 	int free;
-	u8 *rcvbuf;
-	u8 *sendbuf;
-	u8 *sp;
+	u_char *rcvbuf;
+	u_char *sendbuf;
+	u_char *sp;
 	int sendcnt;
 	u_int s_tot;
 	u_int r_bitcnt;
 	u_int r_tot;
 	u_int r_err;
 	u_int r_fcs;
-	u8 r_state;
-	u8 r_one;
-	u8 r_val;
-	u8 s_state;
+	u_char r_state;
+	u_char r_one;
+	u_char r_val;
+	u_char s_state;
 };
 
 struct amd7930_hw {
-	u8 *tx_buff;
-	u8 *rv_buff;
+	u_char *tx_buff;
+	u_char *rv_buff;
 	int rv_buff_in;
 	int rv_buff_out;
 	struct sk_buff *rv_skb;
 	struct hdlc_state *hdlc_state;
-	struct work_struct rcv_work;
-	struct work_struct xmt_work;
+	struct work_struct tq_rcv;
+	struct work_struct tq_xmt;
 };
 
 #define BC_FLG_INIT	1
@@ -483,6 +474,8 @@
 #define BC_FLG_FTI_RUN	13
 #define BC_FLG_LL_OK	14
 #define BC_FLG_LL_CONN	15
+#define BC_FLG_FTI_FTS	16
+#define BC_FLG_FRH_WAIT	17
 
 #define L1_MODE_NULL	0
 #define L1_MODE_TRANS	1
@@ -496,29 +489,28 @@
 struct BCState {
 	int channel;
 	int mode;
-	long Flag;
+	u_long Flag;
 	struct IsdnCardState *cs;
-	int unit;                       /* first or second unit (e.g. HSCX) */
-	int rcvidx;
-	u8 *rcvbuf;                     /* B-Channel receive Buffer */
-	int tx_cnt;  		        /* B-Channel transmit counter */
-	struct sk_buff *tx_skb;         /* B-Channel transmit Buffer */
-	struct sk_buff_head rqueue;	/* B-Channel receive queue */
-	struct sk_buff_head squeue;	/* B-Channel send queue */
-	struct sk_buff_head cmpl_queue;	/* B-Channel send complete queue */
+	int tx_cnt;		/* B-Channel transmit counter */
+	struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+	struct sk_buff_head rqueue;	/* B-Channel receive Queue */
+	struct sk_buff_head squeue;	/* B-Channel send Queue */
+	int ackcnt;
+	spinlock_t aclock;
 	struct PStack *st;
-	u8 *blog;
-	u8 *conmsg;
+	u_char *blog;
+	u_char *conmsg;
 	struct timer_list transbusy;
-	struct work_struct work;
-	unsigned long event;
+	struct work_struct tqueue;
+	u_long event;
+	int  (*BC_SetStack) (struct PStack *, struct BCState *);
+	void (*BC_Close) (struct BCState *);
 #ifdef ERROR_STATISTIC
 	int err_crc;
 	int err_tx;
 	int err_rdo;
 	int err_inv;
 #endif
-	int count;
 	union {
 		struct hscx_hw hscx;
 		struct hdlc_hw hdlc;
@@ -545,12 +537,12 @@
 	int data_open;
 	struct l3_process *proc;
 	setup_parm setup;	/* from isdnif.h numbers and Serviceindicator */
-	long Flags;		/* for remembering action done in l4 */
-				/* long req'd for set_bit --RR */
+	u_long Flags;		/* for remembering action done in l4 */
 	int leased;
 };
 
 struct elsa_hw {
+	struct pci_dev *dev;
 	unsigned long base;
 	unsigned int cfg;
 	unsigned int ctrl;
@@ -565,17 +557,17 @@
 	struct timer_list tl;
 	unsigned int MFlag;
 	struct BCState *bcs;
-	u8 *transbuf;
-	u8 *rcvbuf;
+	u_char *transbuf;
+	u_char *rcvbuf;
 	unsigned int transp;
 	unsigned int rcvp;
 	unsigned int transcnt;
 	unsigned int rcvcnt;
-	u8 IER;
-	u8 FCR;
-	u8 LCR;
-	u8 MCR;
-	u8 ctrl_reg;
+	u_char IER;
+	u_char FCR;
+	u_char LCR;
+	u_char MCR;
+	u_char ctrl_reg;
 };
 
 struct teles3_hw {
@@ -588,8 +580,8 @@
 
 struct teles0_hw {
 	unsigned int cfg_reg;
+	unsigned long membase;
 	unsigned long phymem;
-	void *membase;
 };
 
 struct avm_hw {
@@ -599,6 +591,7 @@
 	unsigned int isacfifo;
 	unsigned int hscxfifo[2];
 	unsigned int counter;
+	struct pci_dev *dev;
 };
 
 struct ix1_hw {
@@ -617,8 +610,10 @@
 	unsigned int isac;
 	unsigned long hscx_adr;
 	unsigned int hscx;
+	unsigned int status;
 	struct timer_list tl;
-	u8 ctrl_reg;
+	u_char ctrl_reg;
+	struct pci_dev *dev;
 };
 
 struct asus_hw {
@@ -637,9 +632,9 @@
 	unsigned char cirm;
 	unsigned char ctmt;
 	unsigned char cip;
-	u8 isac_spcr;
+	u_char isac_spcr;
 	struct timer_list timer;
-};
+};	
 
 struct sedl_hw {
 	unsigned int cfg_reg;
@@ -651,6 +646,7 @@
 	struct isar_reg isar;
 	unsigned int chip;
 	unsigned int bus;
+	struct pci_dev *dev;
 };
 
 struct spt_hw {
@@ -677,9 +673,7 @@
 	unsigned char irqmask0;
 	unsigned char irqstat0;
 	unsigned char last_is0;
-	struct pci_dev *pdev;
-	void (*bc_activate)(struct IsdnCardState *cs, int bc);
-	void (*bc_deactivate)(struct IsdnCardState *cs, int bc);
+	struct pci_dev *dev;
 };
 
 struct hfcPCI_hw {
@@ -700,10 +694,10 @@
         unsigned char bswapped;
         unsigned char nt_mode;
         int nt_timer;
+        struct pci_dev *dev;
         unsigned char *pci_io; /* start of PCI IO memory */
+        void *share_start; /* shared memory for Fifos start */
         void *fifos; /* FIFO memory */ 
-        dma_addr_t fifos_dma;
-        struct pci_dev* pdev;
         int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
 	struct timer_list timer;
 };
@@ -756,12 +750,14 @@
 
 struct isurf_hw {
 	unsigned int reset;
-	void *isac;
-	void *isar;
+	unsigned long phymem;
+	unsigned long isac;
+	unsigned long isar;
 	struct isar_reg isar_r;
 };
 
 struct saphir_hw {
+	struct pci_dev *dev;
 	unsigned int cfg_reg;
 	unsigned int ale;
 	unsigned int isac;
@@ -770,6 +766,7 @@
 };
 
 struct bkm_hw {
+	struct pci_dev *dev;
 	unsigned long base;
 	/* A4T stuff */
 	unsigned long isac_adr;
@@ -782,7 +779,9 @@
 };	
 
 struct gazel_hw {
+	struct pci_dev *dev;
 	unsigned int cfg_reg;
+	unsigned int pciaddr[2];
         signed   int ipac;
 	signed   int isac;
 	signed   int hscx[2];
@@ -793,6 +792,7 @@
 };
 
 struct w6692_hw {
+	struct pci_dev *dev;
 	unsigned int iobase;
 	struct timer_list timer;
 };
@@ -812,25 +812,25 @@
 
 struct arcofi_msg {
 	struct arcofi_msg *next;
-	u8 receive;
-	u8 len;
-	u8 msg[10];
+	u_char receive;
+	u_char len;
+	u_char msg[10];
 };
 
 struct isac_chip {
 	int ph_state;
-	u8 *mon_tx;
-	u8 *mon_rx;
+	u_char *mon_tx;
+	u_char *mon_rx;
 	int mon_txp;
 	int mon_txc;
 	int mon_rxp;
 	struct arcofi_msg *arcofi_list;
 	struct timer_list arcofitimer;
 	wait_queue_head_t arcofi_wait;
-	u8 arcofi_bc;
-	u8 arcofi_state;
-	u8 mocr;
-	u8 adf2;
+	u_char arcofi_bc;
+	u_char arcofi_state;
+	u_char mocr;
+	u_char adf2;
 };
 
 struct hfcd_chip {
@@ -850,80 +850,30 @@
 };
 
 struct amd7930_chip {
-	u8 lmr1;
-	u8 ph_state;
-	u8 old_state;
-	u8 flg_t3;
+	u_char lmr1;
+	u_char ph_state;
+	u_char old_state;
+	u_char flg_t3;
 	unsigned int tx_xmtlen;
 	struct timer_list timer3;
-	void (*ph_command) (struct IsdnCardState *, u8, char *);
-	void (*setIrqMask) (struct IsdnCardState *, u8);
+	void (*ph_command) (struct IsdnCardState *, u_char, char *);
+	void (*setIrqMask) (struct IsdnCardState *, u_char);
 };
 
 struct icc_chip {
 	int ph_state;
-	u8 *mon_tx;
-	u8 *mon_rx;
+	u_char *mon_tx;
+	u_char *mon_rx;
 	int mon_txp;
 	int mon_txc;
 	int mon_rxp;
 	struct arcofi_msg *arcofi_list;
 	struct timer_list arcofitimer;
 	wait_queue_head_t arcofi_wait;
-	u8 arcofi_bc;
-	u8 arcofi_state;
-	u8 mocr;
-	u8 adf2;
-};
-
-struct IsdnCardState;
-
-/* Methods provided by driver for a specific card */
-
-struct card_ops {
-	void   (*init)       (struct IsdnCardState *);
-	void   (*test)       (struct IsdnCardState *);
-	int    (*reset)      (struct IsdnCardState *);
-	void   (*release)    (struct IsdnCardState *);
-	void   (*aux_ind)    (struct IsdnCardState *, void *);
-	void   (*led_handler)(struct IsdnCardState *);
-	irqreturn_t (*irq_func)   (int, void *, struct pt_regs *);
-};
-
-/* Card specific drivers provide methods to access the
- * chips to the chip drivers */
-
-struct bc_hw_ops {
-	u8     (*read_reg)   (struct IsdnCardState *, int, u8);
-	void   (*write_reg)  (struct IsdnCardState *, int, u8, u8);
-	void   (*read_fifo)  (struct IsdnCardState *, int, u8 *, int);
-	void   (*write_fifo) (struct IsdnCardState *, int, u8 *, int);
-};
-
-struct dc_hw_ops {
-	u8     (*read_reg)   (struct IsdnCardState *, u8);
-	void   (*write_reg)  (struct IsdnCardState *, u8, u8);
-	void   (*read_fifo)  (struct IsdnCardState *, u8 *, int);
-	void   (*write_fifo) (struct IsdnCardState *, u8 *, int);
-};
-
-/* Methods provided to shared B-channel FIFO handling */
-
-struct bc_l1_ops {
-	void   (*fill_fifo)  (struct BCState *);
-	int    (*open)       (struct PStack *, struct BCState *);
-	void   (*close)      (struct BCState *);
-};
-
-/* Methods provided to shared D-channel FIFO handling */
-
-struct dc_l1_ops {
-	void   (*fill_fifo)  (struct IsdnCardState *);
-	int    (*open)       (struct PStack *, struct IsdnCardState *);
-	void   (*close)      (struct IsdnCardState *);
-
-	void   (*bh_func)    (void *);
-	void   (*dbusy_func) (struct IsdnCardState *);
+	u_char arcofi_bc;
+	u_char arcofi_state;
+	u_char mocr;
+	u_char adf2;
 };
 
 #define HW_IOM1			0
@@ -933,25 +883,22 @@
 #define FLG_TWO_DCHAN		4
 #define FLG_L1_DBUSY		5
 #define FLG_DBUSY_TIMER 	6
+#define FLG_LOCK_ATOMIC 	7
 #define FLG_ARCOFI_TIMER	8
 #define FLG_ARCOFI_ERROR	9
 #define FLG_HW_L1_UINT		10
-#define FLG_BUGGY_PLX9050       11
 
 struct IsdnCardState {
-	unsigned char typ;
-	unsigned char subtyp;
-	spinlock_t lock;
-	struct card_ops *card_ops;
-	int protocol;
-	struct resources rs;
-	unsigned int irq;
-	unsigned long irq_flags;
-	int status;
-	long HW_Flags;
-	int *busy_flag;
-        int chanlimit; /* limited number of B-chans to use */
-        int logecho; /* log echo if supported by card */
+	spinlock_t	lock;
+	u_char		typ;
+	u_char		subtyp;
+	int		protocol;
+	u_int		irq;
+	u_long		irq_flags;
+	u_long		HW_Flags;
+	int		*busy_flag;
+        int		chanlimit; /* limited number of B-chans to use */
+        int		logecho; /* log echo if supported by card */
 	union {
 		struct elsa_hw elsa;
 		struct teles0_hw teles0;
@@ -979,25 +926,32 @@
 		struct w6692_hw w6692;
 		struct hisax_d_if *hisax_d_if;
 	} hw;
-	int myid;
-	isdn_if iif;
-	u8 *status_buf;
-	u8 *status_read;
-	u8 *status_write;
-	u8 *status_end;
-	struct dc_hw_ops *dc_hw_ops;
-	struct bc_hw_ops *bc_hw_ops;
-	struct dc_l1_ops *dc_l1_ops;
-	struct bc_l1_ops *bc_l1_ops;
-	int    (*cardmsg) (struct IsdnCardState *, int, void *);
-	int    (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
-	struct Channel channel[2+MAX_WAITING_CALLS];
-	struct BCState bcs[2+MAX_WAITING_CALLS];
-	struct PStack *stlist;
+	int		myid;
+	isdn_if		iif;
+	spinlock_t	statlock;
+	u_char		*status_buf;
+	u_char		*status_read;
+	u_char		*status_write;
+	u_char		*status_end;
+	u_char		(*readisac) (struct IsdnCardState *, u_char);
+	void		(*writeisac) (struct IsdnCardState *, u_char, u_char);
+	void		(*readisacfifo) (struct IsdnCardState *, u_char *, int);
+	void		(*writeisacfifo) (struct IsdnCardState *, u_char *, int);
+	u_char		(*BC_Read_Reg) (struct IsdnCardState *, int, u_char);
+	void		(*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
+	void		(*BC_Send_Data) (struct BCState *);
+	int		(*cardmsg) (struct IsdnCardState *, int, void *);
+	void		(*setstack_d) (struct PStack *, struct IsdnCardState *);
+	void		(*DC_Close) (struct IsdnCardState *);
+	int		(*irq_func) (int, void *, struct pt_regs *);
+	int		(*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
+	struct Channel	channel[2+MAX_WAITING_CALLS];
+	struct BCState	bcs[2+MAX_WAITING_CALLS];
+	struct PStack	*stlist;
 	struct sk_buff_head rq, sq; /* D-channel queues */
-	int cardnr;
-	char *dlog;
-	int debug;
+	int		cardnr;
+	char		*dlog;
+	int		debug;
 	union {
 		struct isac_chip isac;
 		struct hfcd_chip hfcd;
@@ -1007,83 +961,287 @@
 		struct amd7930_chip amd7930;
 		struct icc_chip icc;
 	} dc;
-	u8 *rcvbuf;
-	int rcvidx;
-	struct sk_buff *tx_skb;
-	int tx_cnt;
-	long event;
-	struct work_struct work;
+	u_char		*rcvbuf;
+	int		rcvidx;
+	struct sk_buff	*tx_skb;
+	int		tx_cnt;
+	u_long		event;
+	struct work_struct tqueue;
 	struct timer_list dbusytimer;
 #ifdef ERROR_STATISTIC
-	int err_crc;
-	int err_tx;
-	int err_rx;
+	int		err_crc;
+	int		err_tx;
+	int		err_rx;
 #endif
 };
 
-void
-hisax_release_resources(struct IsdnCardState *cs);
+
+#define  schedule_event(s, ev)	do {test_and_set_bit(ev, &s->event);schedule_work(&s->tqueue); } while(0)
 
 #define  MON0_RX	1
 #define  MON1_RX	2
 #define  MON0_TX	4
 #define  MON1_TX	8
 
-#define  ISDN_CTYPE_16_0	1
-#define  ISDN_CTYPE_8_0		2
-#define  ISDN_CTYPE_16_3	3
-#define  ISDN_CTYPE_PNP		4
-#define  ISDN_CTYPE_A1		5
-#define  ISDN_CTYPE_ELSA	6
-#define  ISDN_CTYPE_ELSA_PNP	7
-#define  ISDN_CTYPE_TELESPCMCIA	8
-#define  ISDN_CTYPE_IX1MICROR2	9
-#define  ISDN_CTYPE_ELSA_PCMCIA	10
-#define  ISDN_CTYPE_DIEHLDIVA	11
-#define  ISDN_CTYPE_ASUSCOM	12
-#define  ISDN_CTYPE_TELEINT	13
-#define  ISDN_CTYPE_TELES3C	14
-#define  ISDN_CTYPE_SEDLBAUER	15
-#define  ISDN_CTYPE_SPORTSTER	16
-#define  ISDN_CTYPE_MIC		17
-#define  ISDN_CTYPE_ELSA_PCI	18
-#define  ISDN_CTYPE_COMPAQ_ISA	19
-#define  ISDN_CTYPE_NETJET_S	20
-#define  ISDN_CTYPE_TELESPCI	21
-#define  ISDN_CTYPE_SEDLBAUER_PCMCIA	22
-#define  ISDN_CTYPE_AMD7930	23
-#define  ISDN_CTYPE_NICCY	24
-#define  ISDN_CTYPE_S0BOX	25
-#define  ISDN_CTYPE_A1_PCMCIA	26
-#define  ISDN_CTYPE_FRITZPCI	27
-#define  ISDN_CTYPE_SEDLBAUER_FAX     28
-#define  ISDN_CTYPE_ISURF	29
-#define  ISDN_CTYPE_ACERP10	30
-#define  ISDN_CTYPE_HSTSAPHIR	31
-#define	 ISDN_CTYPE_BKM_A4T	32
-#define	 ISDN_CTYPE_SCT_QUADRO	33
-#define  ISDN_CTYPE_GAZEL	34
-#define  ISDN_CTYPE_HFC_PCI	35
-#define  ISDN_CTYPE_W6692	36
-#define  ISDN_CTYPE_HFC_SX      37
-#define  ISDN_CTYPE_NETJET_U	38
-#define  ISDN_CTYPE_HFC_SP_PCMCIA      39
-#define  ISDN_CTYPE_DYNAMIC     40
-#define  ISDN_CTYPE_ENTERNOW	41
-#define  ISDN_CTYPE_COUNT	41
 
+#ifdef ISDN_CHIP_ISAC
+#undef ISDN_CHIP_ISAC
+#endif
+
+#ifdef	CONFIG_HISAX_16_0
+#define  CARD_TELES0 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_TELES0  0
+#endif
+
+#ifdef	CONFIG_HISAX_16_3
+#define  CARD_TELES3 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_TELES3  0
+#endif
+
+#ifdef	CONFIG_HISAX_TELESPCI
+#define  CARD_TELESPCI 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_TELESPCI  0
+#endif
+
+#ifdef	CONFIG_HISAX_AVM_A1
+#define  CARD_AVM_A1 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_AVM_A1  0
+#endif
+
+#ifdef	CONFIG_HISAX_AVM_A1_PCMCIA
+#define  CARD_AVM_A1_PCMCIA 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_AVM_A1_PCMCIA  0
+#endif
+
+#ifdef	CONFIG_HISAX_FRITZPCI
+#define  CARD_FRITZPCI 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_FRITZPCI  0
+#endif
+
+#ifdef	CONFIG_HISAX_ELSA
+#define  CARD_ELSA 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_ELSA  0
+#endif
+
+#ifdef	CONFIG_HISAX_IX1MICROR2
+#define	CARD_IX1MICROR2 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_IX1MICROR2 0
+#endif
+
+#ifdef  CONFIG_HISAX_DIEHLDIVA
+#define CARD_DIEHLDIVA 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_DIEHLDIVA 0
+#endif
+
+#ifdef  CONFIG_HISAX_ASUSCOM
+#define CARD_ASUSCOM 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_ASUSCOM 0
+#endif
+
+#ifdef  CONFIG_HISAX_TELEINT
+#define CARD_TELEINT 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_TELEINT 0
+#endif
+
+#ifdef  CONFIG_HISAX_SEDLBAUER
+#define CARD_SEDLBAUER 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SEDLBAUER 0
+#endif
+
+#ifdef  CONFIG_HISAX_SPORTSTER
+#define CARD_SPORTSTER 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SPORTSTER 0
+#endif
+
+#ifdef  CONFIG_HISAX_MIC
+#define CARD_MIC 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_MIC 0
+#endif
+
+#ifdef  CONFIG_HISAX_NETJET
+#define CARD_NETJET_S 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NETJET_S 0
+#endif
+
+#ifdef	CONFIG_HISAX_HFCS
+#define  CARD_HFCS 1
+#else
+#define  CARD_HFCS 0
+#endif
+
+#ifdef	CONFIG_HISAX_HFC_PCI
+#define  CARD_HFC_PCI 1
+#else
+#define  CARD_HFC_PCI 0
+#endif
+
+#ifdef	CONFIG_HISAX_HFC_SX
+#define  CARD_HFC_SX 1
+#else
+#define  CARD_HFC_SX 0
+#endif
+
+#ifdef  CONFIG_HISAX_AMD7930
+#define CARD_AMD7930 1
+#else
+#define CARD_AMD7930 0
+#endif
+
+#ifdef	CONFIG_HISAX_NICCY
+#define	CARD_NICCY 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NICCY 0
+#endif
+
+#ifdef	CONFIG_HISAX_ISURF
+#define	CARD_ISURF 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_ISURF 0
+#endif
+
+#ifdef	CONFIG_HISAX_S0BOX
+#define	CARD_S0BOX 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_S0BOX 0
+#endif
+
+#ifdef	CONFIG_HISAX_HSTSAPHIR
+#define	CARD_HSTSAPHIR 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_HSTSAPHIR 0
+#endif
 
 #ifdef	CONFIG_HISAX_TESTEMU
+#define	CARD_TESTEMU 1
 #define ISDN_CTYPE_TESTEMU 99
 #undef ISDN_CTYPE_COUNT
 #define  ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU
+#else
+#define CARD_TESTEMU 0
+#endif
+
+#ifdef	CONFIG_HISAX_BKM_A4T
+#define	CARD_BKM_A4T 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_BKM_A4T 0
+#endif
+
+#ifdef	CONFIG_HISAX_SCT_QUADRO
+#define	CARD_SCT_QUADRO 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SCT_QUADRO 0
+#endif
+
+#ifdef	CONFIG_HISAX_GAZEL
+#define  CARD_GAZEL 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_GAZEL  0
+#endif
+
+#ifdef	CONFIG_HISAX_W6692
+#define	CARD_W6692	1
+#ifndef	ISDN_CHIP_W6692
+#define	ISDN_CHIP_W6692	1
+#endif
+#else
+#define	CARD_W6692	0
 #endif
 
 #ifdef  CONFIG_HISAX_NETJET_U
+#define CARD_NETJET_U 1
+#ifndef ISDN_CHIP_ICC
+#define ISDN_CHIP_ICC 1
+#endif
 #ifndef HISAX_UINTERFACE
 #define HISAX_UINTERFACE 1
 #endif
 #else
+#define CARD_NETJET_U 0
+#endif
+
+#ifdef CONFIG_HISAX_ENTERNOW_PCI
+#define CARD_FN_ENTERNOW_PCI 1
 #endif
 
 #define TEI_PER_CARD 1
@@ -1108,12 +1266,7 @@
 extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
 #endif
 
-struct IsdnCard {
-	int typ;
-	int protocol;		/* EDSS1, 1TR6 or NI1 */
-	unsigned long para[4];
-	struct IsdnCardState *cs;
-};
+#include "hisax_cfg.h"
 
 void init_bcstate(struct IsdnCardState *cs, int bc);
 
@@ -1131,13 +1284,14 @@
 void releasestack_isdnl2(struct PStack *st);
 void setstack_transl2(struct PStack *st);
 void releasestack_transl2(struct PStack *st);
+void lli_writewakeup(struct PStack *st, int len);
 
 void setstack_l3dc(struct PStack *st, struct Channel *chanp);
 void setstack_l3bc(struct PStack *st, struct Channel *chanp);
 void releasestack_isdnl3(struct PStack *st);
 
-u8 *findie(u8 * p, int size, u8 ie, int wanted_set);
-int getcallref(u8 * p);
+u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
+int getcallref(u_char * p);
 int newcallref(void);
 
 int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
@@ -1155,12 +1309,15 @@
 int HiSax_command(isdn_ctrl * ic);
 int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
 void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args);
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
 void HiSax_reportcard(int cardnr, int sel);
-int QuickHex(char *txt, u8 * p, int cnt);
-void LogFrame(struct IsdnCardState *cs, u8 * p, int size);
+int QuickHex(char *txt, u_char * p, int cnt);
+void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
 void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
-void iecpy(u8 * dest, u8 * iestart, int ieoffset);
+void iecpy(u_char * dest, u_char * iestart, int ieoffset);
+#ifdef ISDN_CHIP_ISAC
+void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
+#endif	/* ISDN_CHIP_ISAC */
 #endif	/* __KERNEL__ */
 
 #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
@@ -1182,43 +1339,3 @@
 char *HiSax_getrev(const char *revision);
 int TeiNew(void);
 void TeiFree(void);
-int certification_check(int output);
-
-static inline void
-L2L1(struct PStack *st, int pr, void *arg)
-{
-	st->l1.l2l1(st, pr, arg);
-}
-
-static inline void
-L1L2(struct PStack *st, int pr, void *arg)
-{
-	st->l2.l1l2(st, pr, arg);
-}
-
-static inline void
-L3L2(struct PStack *st, int pr, void *arg)
-{
-	st->l2.l3l2(st, pr, arg);
-}
-
-static inline void
-L2L3(struct PStack *st, int pr, void *arg)
-{
-	st->l3.l2l3(st, pr, arg);
-}
-
-static inline void
-L3L4(struct PStack *st, int pr, void *arg)
-{
-	st->lli.l3l4(st, pr, arg);
-}
-
-static inline void
-L4L3(struct PStack *st, int pr, void *arg)
-{
-	st->l3.l4l3(st, pr, arg);
-}
-
-
-#endif
--- diff/drivers/isdn/hisax/hisax_debug.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hisax_debug.h	2004-02-18 09:03:59.000000000 +0000
@@ -39,7 +39,7 @@
 
 
 static void __attribute__((unused))
-dump_packet(const char *name,const u8 *data,int pkt_len)
+dump_packet(const char *name,const u_char *data,int pkt_len)
 {
 #define DUMP_HDR_SIZE 20
 #define DUMP_TLR_SIZE 8
--- diff/drivers/isdn/hisax/hisax_fcpcipnp.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_fcpcipnp.c	2004-02-18 09:03:59.000000000 +0000
@@ -27,22 +27,26 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/pnp.h>
+#include <linux/isapnp.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
 #include "hisax_fcpcipnp.h"
 
 // debugging cruft
 #define __debug_variable debug
 #include "hisax_debug.h"
 
-// #define CONFIG_PNP_CARD	1
-
 #ifdef CONFIG_HISAX_DEBUG
 static int debug = 0;
+/* static int hdlcfifosize = 32; */
 MODULE_PARM(debug, "i");
+/* MODULE_PARM(hdlcfifosize, "i"); */
 #endif
 
 MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
@@ -65,6 +69,17 @@
 
 MODULE_DEVICE_TABLE(pci, fcpci_ids);
 
+#ifdef __ISAPNP__
+static struct pnp_device_id fcpnp_ids[] __devinitdata = {
+	{ 
+		.id		= "AVM0900",
+		.driver_data	= (unsigned long) "Fritz!Card PnP",
+	},
+};
+
+MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
+#endif
+
 static int protocol = 2;       /* EURO-ISDN Default */
 MODULE_PARM(protocol, "i");
 MODULE_LICENSE("GPL");
@@ -115,12 +130,12 @@
 #define  HDLC_STAT_RDO		0x10
 #define  HDLC_STAT_CRCVFRRAB	0x0E
 #define  HDLC_STAT_CRCVFR	0x06
-#define  HDLC_STAT_RML_MASK	0x3f00
+#define  HDLC_STAT_RML_MASK	0xff00
 
 #define  HDLC_CMD_XRS		0x80
 #define  HDLC_CMD_XME		0x01
 #define  HDLC_CMD_RRS		0x20
-#define  HDLC_CMD_XML_MASK	0x3f00
+#define  HDLC_CMD_XML_MASK	0xff00
 
 #define  AVM_HDLC_FIFO_1        0x10
 #define  AVM_HDLC_FIFO_2        0x18
@@ -367,8 +382,7 @@
 {
 	struct fritz_adapter *adapter = bcs->adapter;
 	struct sk_buff *skb = bcs->tx_skb;
-	u_int count;
-	u_int fifo_size = 32;
+	int count;
 	unsigned long flags;
 	unsigned char *p;
 
@@ -378,8 +392,8 @@
 		BUG();
 
 	bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
-	if (bcs->tx_skb->len > fifo_size) {
-		count = fifo_size;
+	if (bcs->tx_skb->len > bcs->fifo_size) {
+		count = bcs->fifo_size;
 	} else {
 		count = bcs->tx_skb->len;
 		if (bcs->mode != L1_MODE_TRANS)
@@ -389,7 +403,7 @@
 	p = bcs->tx_skb->data;
 	skb_pull(bcs->tx_skb, count);
 	bcs->tx_cnt += count;
-	bcs->ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
+	bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count);
 
 	switch (adapter->type) {
 	case AVM_FRITZ_PCI:
@@ -470,7 +484,7 @@
 
 	len = (stat & HDLC_STAT_RML_MASK) >> 8;
 	if (len == 0)
-		len = 32;
+		len = bcs->fifo_size;
 
 	hdlc_empty_fifo(bcs, len);
 
@@ -498,6 +512,7 @@
 static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)
 {
 	struct fritz_adapter *adapter = bcs->adapter;
+	
 
 	/* Here we lost an TX interrupt, so
 	 * restart transmitting the whole frame.
@@ -506,14 +521,17 @@
 	bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;
 	adapter->write_ctrl(bcs, 1);
 	bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
-	adapter->write_ctrl(bcs, 1);
 
 	if (!bcs->tx_skb) {
 		DBG(0x10, "XDU without skb");
+		adapter->write_ctrl(bcs, 1);
 		return;
 	}
-	skb_push(bcs->tx_skb, bcs->tx_cnt);
-	bcs->tx_cnt = 0;
+	/* only hdlc restarts the frame, transparent mode must continue */
+	if (bcs->mode == L1_MODE_HDLC) {
+		skb_push(bcs->tx_skb, bcs->tx_cnt);
+		bcs->tx_cnt = 0;
+	}
 }
 
 static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
@@ -530,7 +548,8 @@
 	}
 	bcs->tx_cnt = 0;
 	bcs->tx_skb = NULL;
-	B_L1L2(bcs, PH_DATA | CONFIRM, skb);
+	B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+	dev_kfree_skb_irq(skb);
 }
 
 static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)
@@ -543,6 +562,8 @@
 	if (stat & HDLC_INT_XDU) {
 		DBG(0x10, "XDU");
 		hdlc_xdu_irq(bcs);
+		hdlc_xpr_irq(bcs);
+		return;
 	}
 	if (stat & HDLC_INT_XPR) {
 		DBG(0x10, "XPR");
@@ -573,6 +594,7 @@
 	if (bcs->mode == mode)
 		return;
 
+	bcs->fifo_size = 32;
 	bcs->ctrl.ctrl = 0;
 	bcs->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
 	switch (mode) {
@@ -585,10 +607,11 @@
 		bcs->rcvidx = 0;
 		bcs->tx_cnt = 0;
 		bcs->tx_skb = NULL;
-		if (mode == L1_MODE_TRANS)
+		if (mode == L1_MODE_TRANS) {
 			bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
-		else
+		} else {
 			bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+		}
 		adapter->write_ctrl(bcs, 5);
 		bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
 		adapter->write_ctrl(bcs, 1);
@@ -631,7 +654,8 @@
 
 // ----------------------------------------------------------------------
 
-static irqreturn_t fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
+static irqreturn_t
+fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
 {
 	struct fritz_adapter *adapter = dev;
 	unsigned char val;
@@ -643,13 +667,15 @@
 	DBG(2, "STATUS0 %#x", val);
 	if (val & AVM_STATUS0_IRQ_ISAC)
 		isacsx_irq(&adapter->isac);
-
 	if (val & AVM_STATUS0_IRQ_HDLC)
 		hdlc_irq(adapter);
+	if (val & AVM_STATUS0_IRQ_ISAC)
+		isacsx_irq(&adapter->isac);
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t fcpci_irq(int intno, void *dev, struct pt_regs *regs)
+static irqreturn_t
+fcpci_irq(int intno, void *dev, struct pt_regs *regs)
 {
 	struct fritz_adapter *adapter = dev;
 	unsigned char sval;
@@ -683,8 +709,7 @@
 
 	outb(AVM_STATUS1_ENA_IOM | adapter->irq, 
 	     adapter->io + AVM_STATUS1);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(50*HZ / 1000); /* Timeout 50ms */
+	mdelay(10);
 }
 
 // ----------------------------------------------------------------------
@@ -767,14 +792,11 @@
 
 	// Reset
 	outb(0, adapter->io + AVM_STATUS0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(50 * HZ / 1000); // 50 msec
+	mdelay(10);
 	outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(50 * HZ / 1000); // 50 msec
+	mdelay(10);
 	outb(0, adapter->io + AVM_STATUS0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(10 * HZ / 1000); // 10 msec
+	mdelay(10);
 
 	switch (adapter->type) {
 	case AVM_FRITZ_PCIV2:
@@ -784,7 +806,7 @@
 	case AVM_FRITZ_PCI:
 	case AVM_FRITZ_PNP:
 		fcpci_init(adapter);
-		hisax_isac_setup(&adapter->isac);
+		isac_setup(&adapter->isac);
 		break;
 	}
 	val = adapter->read_hdlc_status(adapter, 0);
@@ -817,7 +839,7 @@
 // ----------------------------------------------------------------------
 
 static struct fritz_adapter * __devinit 
-new_adapter(struct pci_dev *pdev)
+new_adapter(void)
 {
 	struct fritz_adapter *adapter;
 	struct hisax_b_if *b_if[2];
@@ -840,8 +862,6 @@
 		adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
 	}
 
-	pci_set_drvdata(pdev, adapter);
-
 	for (i = 0; i < 2; i++)
 		b_if[i] = &adapter->bcs[i].b_if;
 
@@ -863,10 +883,12 @@
 	int retval;
 
 	retval = -ENOMEM;
-	adapter = new_adapter(pdev);
+	adapter = new_adapter();
 	if (!adapter)
 		goto err;
 
+	pci_set_drvdata(pdev, adapter);
+
 	if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) 
 		adapter->type = AVM_FRITZ_PCIV2;
 	else
@@ -880,7 +902,7 @@
 	adapter->irq = pdev->irq;
 
 	printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
-	       (char *) ent->driver_data, pci_name(pdev));
+	       (char *) ent->driver_data, pdev->slot_name);
 
 	retval = fcpcipnp_setup(adapter);
 	if (retval)
@@ -894,91 +916,87 @@
 	return retval;
 }
 
-static void __devexit fcpci_remove(struct pci_dev *pdev)
-{
-	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
-
-	fcpcipnp_release(adapter);
-	pci_disable_device(pdev);
-	delete_adapter(adapter);
-}
-
-static struct pci_driver fcpci_driver = {
-	.name     = "fcpci",
-	.probe    = fcpci_probe,
-	.remove   = __devexit_p(fcpci_remove),
-	.id_table = fcpci_ids,
-};
-
-#ifdef CONFIG_PNP_CARD
-
-static int __devinit fcpnp_probe(struct pnp_card *card,
-				 const struct pnp_card_device_id *card_id)
+#ifdef __ISAPNP__
+static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 {
 	struct fritz_adapter *adapter;
-	struct pnp_dev *pnp_dev;
 	int retval;
 
-	retval = -ENODEV;
-	pnp_dev = pnp_request_card_device(card, card_id->devs[0].id, NULL);
-	if (!pnp_dev)
-		goto err;
-
-	if (!pnp_port_valid(pnp_dev, 0) || !pnp_irq_valid(pnp_dev, 0))
-		goto err;
+	if (!pdev)
+		return(-ENODEV);
 
 	retval = -ENOMEM;
-	adapter = new_adapter((struct pci_dev *)pnp_dev); // FIXME
+	adapter = new_adapter();
 	if (!adapter)
 		goto err;
-	
+
+	pnp_set_drvdata(pdev, adapter);
+
 	adapter->type = AVM_FRITZ_PNP;
-	adapter->io = pnp_port_start(pnp_dev, 0);
-	adapter->irq = pnp_irq(pnp_dev, 0);
-	
+
+	pnp_disable_dev(pdev);
+	retval = pnp_activate_dev(pdev);
+	if (retval < 0) {
+		printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
+			(char *)dev_id->driver_data, retval);
+		goto err_free;
+	}
+	adapter->io = pnp_port_start(pdev, 0);
+	adapter->irq = pnp_irq(pdev, 0);
+
 	printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
-	       (char *) card_id->driver_data, adapter->io, adapter->irq);
-	
+	       (char *) dev_id->driver_data, adapter->io, adapter->irq);
+
 	retval = fcpcipnp_setup(adapter);
 	if (retval)
-		goto err_delete;
-	
+		goto err_free;
+
 	return 0;
 	
- err_delete:
+ err_free:
 	delete_adapter(adapter);
  err:
 	return retval;
 }
 
-static void __devexit fcpnp_remove(struct pnp_card *pcard)
+static void __devexit fcpnp_remove(struct pnp_dev *pdev)
 {
-	struct fritz_adapter *adapter = pnpc_get_drvdata(pcard);
+	struct fritz_adapter *adapter = pnp_get_drvdata(pdev);
 
-	fcpcipnp_release(adapter);
-	delete_adapter(adapter);
+	if (adapter) {
+		fcpcipnp_release(adapter);
+		delete_adapter(adapter);
+	}
+	pnp_disable_dev(pdev);
 }
 
-static struct pnp_card_device_id fcpnp_ids[] __devinitdata = {
-	{ .id          = "AVM0900", 
-	  .driver_data = (unsigned long) "Fritz!Card PnP",
-	  .devs        = { { "AVM0900" } },
-	},
-	{}
+static struct pnp_driver fcpnp_driver = {
+	name:     "fcpnp",
+	probe:    fcpnp_probe,
+	remove:   __devexit_p(fcpnp_remove),
+	id_table: fcpnp_ids,
 };
+#endif
 
-static struct pnpc_driver fcpnp_driver = {
-	.name     = "fcpnp",
-	.probe    = fcpnp_probe,
-	.remove   = __devexit_p(fcpnp_remove),
-	.id_table = fcpnp_ids,
-};
+static void __devexit fcpci_remove(struct pci_dev *pdev)
+{
+	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
 
-#endif
+	fcpcipnp_release(adapter);
+	pci_disable_device(pdev);
+	delete_adapter(adapter);
+}
+
+static struct pci_driver fcpci_driver = {
+	name:     "fcpci",
+	probe:    fcpci_probe,
+	remove:   __devexit_p(fcpci_remove),
+	id_table: fcpci_ids,
+};
 
 static int __init hisax_fcpcipnp_init(void)
 {
-	int retval = 0, pci_nr_found;
+	int retval, pci_nr_found;
 
 	printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
 
@@ -986,25 +1004,26 @@
 	if (retval < 0)
 		goto out;
 	pci_nr_found = retval;
+	retval = 0;
 
-#ifdef CONFIG_PNP_CARD
-	retval = pnpc_register_driver(&fcpnp_driver);
-#endif
+#ifdef __ISAPNP__
+	retval = pnp_register_driver(&fcpnp_driver);
 	if (retval < 0)
 		goto out_unregister_pci;
+#endif
 
 #if !defined(CONFIG_HOTPLUG) || defined(MODULE)
 	if (pci_nr_found + retval == 0) {
 		retval = -ENODEV;
-		goto out_unregister_pnp;
+		goto out_unregister_isapnp;
 	}
 #endif
 	return 0;
 
 #if !defined(CONFIG_HOTPLUG) || defined(MODULE)
- out_unregister_pnp:
-#ifdef CONFIG_PNP_CARD
-	pnpc_unregister_driver(&fcpnp_driver);
+ out_unregister_isapnp:
+#ifdef __ISAPNP__
+	pnp_unregister_driver(&fcpnp_driver);
 #endif
 #endif
  out_unregister_pci:
@@ -1015,8 +1034,8 @@
 
 static void __exit hisax_fcpcipnp_exit(void)
 {
-#ifdef CONFIG_PNP_CARD
-	pnpc_unregister_driver(&fcpnp_driver);
+#ifdef __ISAPNP__
+	pnp_unregister_driver(&fcpnp_driver);
 #endif
 	pci_unregister_driver(&fcpci_driver);
 }
--- diff/drivers/isdn/hisax/hisax_fcpcipnp.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hisax_fcpcipnp.h	2004-02-18 09:03:59.000000000 +0000
@@ -12,15 +12,15 @@
 
 struct hdlc_stat_reg {
 #ifdef __BIG_ENDIAN
-	u8 fill __attribute__((packed));
-	u8 mode __attribute__((packed));
-	u8 xml  __attribute__((packed));
-	u8 cmd  __attribute__((packed));
+	u_char fill __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char cmd  __attribute__((packed));
 #else
-	u8 cmd  __attribute__((packed));
-	u8 xml  __attribute__((packed));
-	u8 mode __attribute__((packed));
-	u8 fill __attribute__((packed));
+	u_char cmd  __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char fill __attribute__((packed));
 #endif
 };
 
@@ -36,8 +36,9 @@
 	} ctrl;
 	u_int stat;
 	int rcvidx;
-	u8 rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
-
+	int fifo_size;
+	u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
+	
 	int tx_cnt;		    /* B-Channel transmit counter */
 	struct sk_buff *tx_skb;     /* B-Channel transmit Buffer */
 };
--- diff/drivers/isdn/hisax/hisax_isac.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_isac.c	2004-02-18 09:03:59.000000000 +0000
@@ -450,7 +450,7 @@
 {
 	// this also works for isacsx, since
 	// CMDR(D) register works the same
-	u8 *ptr;
+	u_char *ptr;
 
 	DBG(DBG_IRQ, "count %d", count);
 
@@ -474,7 +474,7 @@
 
 	int count;
 	unsigned char cmd;
-	u8 *ptr;
+	u_char *ptr;
 
 	if (!isac->tx_skb)
 		BUG();
@@ -770,7 +770,7 @@
 	FsmInitTimer(&isac->l1m, &isac->timer);
 }
 
-void hisax_isac_setup(struct isac *isac)
+void isac_setup(struct isac *isac)
 {
 	int val, eval;
 
@@ -890,7 +890,7 @@
 EXPORT_SYMBOL(isacsx_setup);
 EXPORT_SYMBOL(isacsx_irq);
 
-EXPORT_SYMBOL(hisax_isac_setup);
+EXPORT_SYMBOL(isac_setup);
 EXPORT_SYMBOL(isac_irq);
 
 module_init(hisax_isac_init);
--- diff/drivers/isdn/hisax/hisax_isac.h	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_isac.h	2004-02-18 09:03:59.000000000 +0000
@@ -17,26 +17,26 @@
 	struct hisax_d_if hisax_d_if;
 	struct FsmInst l1m;
 	struct FsmTimer timer;
-	u8 mocr;
-	u8 adf2;
+	u_char mocr;
+	u_char adf2;
 	int    type;
 
-	u8 rcvbuf[MAX_DFRAME_LEN_L1];
+	u_char rcvbuf[MAX_DFRAME_LEN_L1];
 	int rcvidx;
 
 	struct sk_buff *tx_skb;
 	int tx_cnt;
 
-	u8 (*read_isac)      (struct isac *, u8);
-	void   (*write_isac)     (struct isac *, u8, u8);
-	void   (*read_isac_fifo) (struct isac *, u8 *, int);
-	void   (*write_isac_fifo)(struct isac *, u8 *, int);
+	u_char (*read_isac)      (struct isac *, u_char);
+	void   (*write_isac)     (struct isac *, u_char, u_char);
+	void   (*read_isac_fifo) (struct isac *, u_char *, int);
+	void   (*write_isac_fifo)(struct isac *, u_char *, int);
 };
 
 void isac_init(struct isac *isac);
 void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
 
-void hisax_isac_setup(struct isac *isac);
+void isac_setup(struct isac *isac);
 void isac_irq(struct isac *isac);
 
 void isacsx_setup(struct isac *isac);
--- diff/drivers/isdn/hisax/hscx.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/hscx.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hscx.c,v 1.21.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $
  *
  * HSCX specific routines
  *
@@ -17,133 +17,136 @@
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
-static char *HSCXVer[] __initdata =
+static char *HSCXVer[] =
 {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
  "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
 
-static inline u8
-hscx_read(struct BCState *bcs, u8 addr)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	return cs->bc_hw_ops->read_reg(cs, bcs->unit, addr);
-}
-
-static inline void
-hscx_write(struct BCState *bcs, u8 addr, u8 val)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	cs->bc_hw_ops->write_reg(cs, bcs->unit, addr, val);
-}
-
-static inline void
-hscx_write_fifo(struct BCState *bcs, u8 *p, int len)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	cs->bc_hw_ops->write_fifo(cs, bcs->unit, p, len);
-}
-
-static int
+int
 HscxVersion(struct IsdnCardState *cs, char *s)
 {
 	int verA, verB;
 
-	verA = cs->bc_hw_ops->read_reg(cs, 0, HSCX_VSTR) & 0xf;
-	verB = cs->bc_hw_ops->read_reg(cs, 1, HSCX_VSTR) & 0xf;
+	verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
+	verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
 	printk(KERN_INFO "%s HSCX version A: %s  B: %s\n", s,
 	       HSCXVer[verA], HSCXVer[verB]);
 	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
-		return 1;
+		return (1);
 	else
-		return 0;
+		return (0);
 }
 
 void
 modehscx(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int hscx = bcs->unit;
+	int hscx = bcs->hw.hscx.hscx;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "hscx %c mode %d ichan %d",
 			'A' + hscx, mode, bc);
 	bcs->mode = mode;
 	bcs->channel = bc;
-	hscx_write(bcs, HSCX_XAD1, 0xFF);
-	hscx_write(bcs, HSCX_XAD2, 0xFF);
-	hscx_write(bcs, HSCX_RAH2, 0xFF);
-	hscx_write(bcs, HSCX_XBCH, 0x0);
-	hscx_write(bcs, HSCX_RLCR, 0x0);
-	hscx_write(bcs, HSCX_CCR1,
+	cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
+	cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
+	cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
+	cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
+	cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
+	cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
 		test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
-	hscx_write(bcs, HSCX_CCR2, 0x30);
-	hscx_write(bcs, HSCX_XCCR, 7);
-	hscx_write(bcs, HSCX_RCCR, 7);
+	cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
+	cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
+	cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
 
 	/* Switch IOM 1 SSI */
 	if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
 		bc = 1 - bc;
 
 	if (bc == 0) {
-		hscx_write(bcs, HSCX_TSAX,
+		cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
 			      test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
-		hscx_write(bcs, HSCX_TSAR,
+		cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
 			      test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
 	} else {
-		hscx_write(bcs, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
-		hscx_write(bcs, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
+		cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
+		cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
 	}
 	switch (mode) {
-	case L1_MODE_NULL:
-		hscx_write(bcs, HSCX_TSAX, 0x1f);
-		hscx_write(bcs, HSCX_TSAR, 0x1f);
-		hscx_write(bcs, HSCX_MODE, 0x84);
-		break;
-	case L1_MODE_TRANS:
-		hscx_write(bcs, HSCX_MODE, 0xe4);
-		break;
-	case L1_MODE_HDLC:
-		hscx_write(bcs, HSCX_CCR1,
-			       test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
-		hscx_write(bcs, HSCX_MODE, 0x8c);
-		break;
+		case (L1_MODE_NULL):
+			cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f);
+			cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
+			cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
+			break;
+		case (L1_MODE_TRANS):
+			cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
+			break;
+		case (L1_MODE_HDLC):
+			cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
+				test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
+			cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
+			break;
 	}
 	if (mode)
-		hscx_write(bcs, HSCX_CMDR, 0x41);
-
-	hscx_write(bcs, HSCX_ISTA, 0x00);
+		cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
+	cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
 }
 
 void
 hscx_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
+	u_long flags;
 	struct sk_buff *skb = arg;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->hw.hscx.count = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+			} else {
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->hw.hscx.count = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			modehscx(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			modehscx(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			modehscx(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			modehscx(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -152,17 +155,50 @@
 close_hscxstate(struct BCState *bcs)
 {
 	modehscx(bcs, 0, bcs->channel);
-	bc_close(bcs);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hscx.rcvbuf) {
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
 }
 
 int
 open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	bc_open(bcs);
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax: No memory for hscx.rcvbuf\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax: No memory for bcs->blog\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
 	bcs->tx_skb = NULL;
 	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 	bcs->event = 0;
-	bcs->rcvidx = 0;
+	bcs->hw.hscx.rcvidx = 0;
 	bcs->tx_cnt = 0;
 	return (0);
 }
@@ -174,80 +210,71 @@
 	if (open_hscxstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = hscx_l2l1;
+	st->l2.l2l1 = hscx_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
 	return (0);
 }
 
-static void hscx_fill_fifo(struct BCState *bcs);
-
-static struct bc_l1_ops hscx_l1_ops = {
-	.fill_fifo = hscx_fill_fifo,
-	.open      = setstack_hscx,
-	.close     = close_hscxstate,
-};
-
-void __init
-inithscx(struct IsdnCardState *cs)
+void
+clear_pending_hscx_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
-	
-	cs->bc_l1_ops = &hscx_l1_ops;
-	cs->bcs[0].unit = 0;
-	cs->bcs[1].unit = 1;
-	cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
-	cs->bcs[0].hw.hscx.tsaxr1 = 3;
-	cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
-	cs->bcs[1].hw.hscx.tsaxr1 = 3;
 
-	val = hscx_read(&cs->bcs[1], HSCX_ISTA);
+	val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
 	debugl1(cs, "HSCX B ISTA %x", val);
 	if (val & 0x01) {
-		eval = hscx_read(&cs->bcs[1], HSCX_EXIR);
+		eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
 		debugl1(cs, "HSCX B EXIR %x", eval);
 	}
 	if (val & 0x02) {
-		eval = hscx_read(&cs->bcs[0], HSCX_EXIR);
+		eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
 		debugl1(cs, "HSCX A EXIR %x", eval);
 	}
-	val = hscx_read(&cs->bcs[0], HSCX_ISTA);
+	val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
 	debugl1(cs, "HSCX A ISTA %x", val);
-	val = hscx_read(&cs->bcs[1], HSCX_STAR);
+	val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
 	debugl1(cs, "HSCX B STAR %x", val);
-	val = hscx_read(&cs->bcs[0], HSCX_STAR);
+	val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
 	debugl1(cs, "HSCX A STAR %x", val);
 	/* disable all IRQ */
-	hscx_write(&cs->bcs[0], HSCX_MASK, 0xFF);
-	hscx_write(&cs->bcs[1], HSCX_MASK, 0xFF);
-
-	modehscx(&cs->bcs[0], 0, 0);
-	modehscx(&cs->bcs[1], 0, 0);
-
-	/* Reenable all IRQ */
-	hscx_write(&cs->bcs[0], HSCX_MASK, 0x0);
-	hscx_write(&cs->bcs[1], HSCX_MASK, 0x0);
+	cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
+	cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
 }
 
 void
-inithscxisac(struct IsdnCardState *cs)
+inithscx(struct IsdnCardState *cs)
 {
-	initisac(cs);
-	inithscx(cs);
+	cs->bcs[0].BC_SetStack = setstack_hscx;
+	cs->bcs[1].BC_SetStack = setstack_hscx;
+	cs->bcs[0].BC_Close = close_hscxstate;
+	cs->bcs[1].BC_Close = close_hscxstate;
+	cs->bcs[0].hw.hscx.hscx = 0;
+	cs->bcs[1].hw.hscx.hscx = 1;
+	cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
+	cs->bcs[0].hw.hscx.tsaxr1 = 3;
+	cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
+	cs->bcs[1].hw.hscx.tsaxr1 = 3;
+	modehscx(cs->bcs, 0, 0);
+	modehscx(cs->bcs + 1, 0, 0);
 }
 
-int
-hscxisac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops,
-	       struct bc_hw_ops *hscx_ops)
+void
+inithscxisac(struct IsdnCardState *cs, int part)
 {
-	isac_setup(cs, isac_ops);
-	cs->bc_hw_ops = hscx_ops;
-	if (HscxVersion(cs, "HiSax:")) {
-		printk(KERN_WARNING "HiSax: invalid HSCX version\n");
-		return -ENODEV;
+	if (part & 1) {
+		clear_pending_isac_ints(cs);
+		clear_pending_hscx_ints(cs);
+		initisac(cs);
+		inithscx(cs);
+	}
+	if (part & 2) {
+		/* Reenable all IRQ */
+		cs->writeisac(cs, ISAC_MASK, 0);
+		cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
+		cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
+		/* RESET Receiver and Transmitter */
+		cs->writeisac(cs, ISAC_CMDR, 0x41);
 	}
-	return 0;
 }
-
-#include "hscx_irq.c"
--- diff/drivers/isdn/hisax/hscx.h	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/hscx.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hscx.h,v 1.6.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * HSCX specific defines
  *
@@ -10,8 +10,6 @@
  *
  */
 
-#include <linux/interrupt.h>
-
 /* All Registers original Siemens Spec  */
 
 #define HSCX_ISTA 0x20
@@ -36,10 +34,8 @@
 #define HSCX_RLCR 0x2e
 #define HSCX_MASK 0x20
 
+extern int HscxVersion(struct IsdnCardState *cs, char *s);
 extern void modehscx(struct BCState *bcs, int mode, int bc);
-extern void inithscxisac(struct IsdnCardState *cs);
-extern void hscx_int_main(struct IsdnCardState *cs, u8 val);
-extern irqreturn_t hscxisac_irq(int intno, void *dev_id, struct pt_regs *regs);
-extern int  hscxisac_setup(struct IsdnCardState *cs,
-			   struct dc_hw_ops *isac_ops,
-			   struct bc_hw_ops *hscx_ops);
+extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
+extern void inithscx(struct IsdnCardState *cs);
+extern void inithscxisac(struct IsdnCardState *cs, int part);
--- diff/drivers/isdn/hisax/hscx_irq.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/hscx_irq.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.16.6.2 2001/09/23 22:24:48 kai Exp $
+/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
  *
  * low level b-channel stuff for Siemens HSCX
  *
@@ -12,12 +12,13 @@
  *
  */
 
-static void
-waitforCEC(struct BCState *bcs)
+
+static inline void
+waitforCEC(struct IsdnCardState *cs, int hscx)
 {
 	int to = 50;
 
-	while ((hscx_read(bcs, HSCX_STAR) & 0x04) && to) {
+	while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
 		udelay(1);
 		to--;
 	}
@@ -26,12 +27,12 @@
 }
 
 
-static void
-waitforXFW(struct BCState *bcs)
+static inline void
+waitforXFW(struct IsdnCardState *cs, int hscx)
 {
 	int to = 50;
 
-	while ((!(hscx_read(bcs, HSCX_STAR) & 0x44) == 0x40) && to) {
+	while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
 		udelay(1);
 		to--;
 	}
@@ -40,18 +41,42 @@
 }
 
 static inline void
-WriteHSCXCMDR(struct BCState *bcs, u8 data)
+WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
 {
-	waitforCEC(bcs);
-	hscx_write(bcs, HSCX_CMDR, data);
+	waitforCEC(cs, hscx);
+	WRITEHSCX(cs, hscx, HSCX_CMDR, data);
 }
 
 
+
 static void
 hscx_empty_fifo(struct BCState *bcs, int count)
 {
-	recv_empty_fifo_b(bcs, count);
-	WriteHSCXCMDR(bcs, 0x80);
+	u_char *ptr;
+	struct IsdnCardState *cs = bcs->cs;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hscx_empty_fifo");
+
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "hscx_empty_fifo: incoming packet too large");
+		WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static void
@@ -60,22 +85,46 @@
 	struct IsdnCardState *cs = bcs->cs;
 	int more, count;
 	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
-	u8 *p;
+	u_char *ptr;
 
-	p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more);
-	if (!p)
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "hscx_fill_fifo");
+
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
 		return;
 
-	waitforXFW(bcs);
-	hscx_write_fifo(bcs, p, count);
-	WriteHSCXCMDR(bcs, more ? 0x8 : 0xa);
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > fifo_size) {
+		more = !0;
+		count = fifo_size;
+	} else
+		count = bcs->tx_skb->len;
+
+	waitforXFW(cs, bcs->hw.hscx.hscx);
+	ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static inline void
-hscx_interrupt(struct IsdnCardState *cs, u8 val, u8 hscx)
+hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
-	u8 r;
+	u_char r;
 	struct BCState *bcs = cs->bcs + hscx;
+	struct sk_buff *skb;
 	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
 	int count;
 
@@ -83,7 +132,7 @@
 		return;
 
 	if (val & 0x80) {	/* RME */
-		r = hscx_read(bcs, HSCX_RSTA);
+		r = READHSCX(cs, hscx, HSCX_RSTA);
 		if ((r & 0xf0) != 0xa0) {
 			if (!(r & 0x80)) {
 				if (cs->debug & L1_DEB_WARN)
@@ -107,46 +156,102 @@
 				bcs->err_crc++;
 #endif
 			}
-			WriteHSCXCMDR(bcs, 0x80);
-			bcs->rcvidx = 0;
+			WriteHSCXCMDR(cs, hscx, 0x80);
 		} else {
-			count = hscx_read(bcs, HSCX_RBCL) & (fifo_size-1);
+			count = READHSCX(cs, hscx, HSCX_RBCL) & (
+				test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
 			if (count == 0)
 				count = fifo_size;
-
 			hscx_empty_fifo(bcs, count);
-			recv_rme_b(bcs);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug & L1_DEB_HSCX_FIFO)
+					debugl1(cs, "HX Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HSCX: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
 		}
+		bcs->hw.hscx.rcvidx = 0;
+		schedule_event(bcs, B_RCVBUFREADY);
 	}
 	if (val & 0x40) {	/* RPF */
 		hscx_empty_fifo(bcs, fifo_size);
-		recv_rpf_b(bcs);
+		if (bcs->mode == L1_MODE_TRANS) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(fifo_size)))
+				printk(KERN_WARNING "HiSax: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			schedule_event(bcs, B_RCVBUFREADY);
+		}
 	}
-	if (val & 0x10) {
-		xmit_xpr_b(bcs);
+	if (val & 0x10) {	/* XPR */
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				hscx_fill_fifo(bcs);
+				return;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.hscx.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_irq(bcs->tx_skb);
+				bcs->hw.hscx.count = 0; 
+				bcs->tx_skb = NULL;
+			}
+		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.hscx.count = 0;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			hscx_fill_fifo(bcs);
+		} else {
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
 	}
 }
 
-static void
-reset_xmit(struct BCState *bcs)
+static inline void
+hscx_int_main(struct IsdnCardState *cs, u_char val)
 {
-	WriteHSCXCMDR(bcs, 0x01);
-}
 
-void
-hscx_int_main(struct IsdnCardState *cs, u8 val)
-{
-	u8 exval;
+	u_char exval;
 	struct BCState *bcs;
 
 	if (val & 0x01) {
 		bcs = cs->bcs + 1;
-		exval = hscx_read(bcs, HSCX_EXIR);
-		if (cs->debug & L1_DEB_HSCX)
-			debugl1(cs, "HSCX B EXIR %x", exval);
+		exval = READHSCX(cs, 1, HSCX_EXIR);
 		if (exval & 0x40) {
-			xmit_xdu_b(bcs, reset_xmit);
-		}
+			if (bcs->mode == 1)
+				hscx_fill_fifo(bcs);
+			else {
+#ifdef ERROR_STATISTIC
+				bcs->err_tx++;
+#endif
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (bcs->tx_skb) {
+					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+					bcs->tx_cnt += bcs->hw.hscx.count;
+					bcs->hw.hscx.count = 0;
+				}
+				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
+			}
+		} else if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX B EXIR %x", exval);
 	}
 	if (val & 0xf8) {
 		if (cs->debug & L1_DEB_HSCX)
@@ -155,72 +260,33 @@
 	}
 	if (val & 0x02) {
 		bcs = cs->bcs;
-		exval = hscx_read(bcs, HSCX_EXIR);
-		if (cs->debug & L1_DEB_HSCX)
-			debugl1(cs, "HSCX A EXIR %x", exval);
+		exval = READHSCX(cs, 0, HSCX_EXIR);
 		if (exval & 0x40) {
-			xmit_xdu_b(bcs, reset_xmit);
-		}
+			if (bcs->mode == L1_MODE_TRANS)
+				hscx_fill_fifo(bcs);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+#ifdef ERROR_STATISTIC
+				bcs->err_tx++;
+#endif
+				if (bcs->tx_skb) {
+					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+					bcs->tx_cnt += bcs->hw.hscx.count;
+					bcs->hw.hscx.count = 0;
+				}
+				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
+			}
+		} else if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX A EXIR %x", exval);
 	}
 	if (val & 0x04) {
-		bcs = cs->bcs;
-		exval = hscx_read(bcs, HSCX_ISTA);
+		exval = READHSCX(cs, 0, HSCX_ISTA);
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A interrupt %x", exval);
 		hscx_interrupt(cs, exval, 0);
 	}
 }
-
-/* ====================================================================== */
-
-static inline u8
-isac_read(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-isac_write(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
-irqreturn_t
-hscxisac_irq(int intno, void *dev_id, struct pt_regs *regs)
-{
-	struct IsdnCardState *cs = dev_id;
-	u8 val;
-	int count = 0;
-
-	spin_lock(&cs->lock);
-	val = hscx_read(&cs->bcs[1], HSCX_ISTA);
-      Start_HSCX:
-	if (val)
-		hscx_int_main(cs, val);
-	val = isac_read(cs, ISAC_ISTA);
-      Start_ISAC:
-	if (val)
-		isac_interrupt(cs, val);
-	count++;
-	val = hscx_read(&cs->bcs[1], HSCX_ISTA);
-	if (val && count < 5) {
-		if (cs->debug & L1_DEB_HSCX)
-			debugl1(cs, "HSCX IntStat after IntRoutine");
-		goto Start_HSCX;
-	}
-	val = isac_read(cs, ISAC_ISTA);
-	if (val && count < 5) {
-		if (cs->debug & L1_DEB_ISAC)
-			debugl1(cs, "ISAC IntStat after IntRoutine");
-		goto Start_ISAC;
-	}
-	hscx_write(&cs->bcs[0], HSCX_MASK, 0xFF);
-	hscx_write(&cs->bcs[1], HSCX_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0x0);
-	hscx_write(&cs->bcs[0], HSCX_MASK, 0x0);
-	hscx_write(&cs->bcs[1], HSCX_MASK, 0x0);
-	spin_unlock(&cs->lock);
-	return IRQ_HANDLED;
-}
-
--- diff/drivers/isdn/hisax/icc.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/icc.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: icc.c,v 1.5.6.4 2001/09/23 22:24:48 kai Exp $
+/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * ICC specific routines
  *
@@ -24,39 +24,15 @@
 #define DBUSY_TIMER_VALUE 80
 #define ARCOFI_USE 0
 
-static inline u8
-icc_read_reg(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-icc_write_reg(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
-static inline void
-icc_read_fifo(struct IsdnCardState *cs, u8 *p, int len)
-{
-	return cs->dc_hw_ops->read_fifo(cs, p, len);
-}
-
-static inline void
-icc_write_fifo(struct IsdnCardState *cs, u8 *p, int len)
-{
-	return cs->dc_hw_ops->write_fifo(cs, p, len);
-}
-
 static char *ICCVer[] __initdata =
 {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
 
-static void
+void
 ICCVersion(struct IsdnCardState *cs, char *s)
 {
 	int val;
 
-	val = icc_read_reg(cs, ICC_RBCH);
+	val = cs->readisac(cs, ICC_RBCH);
 	printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
 }
 
@@ -65,7 +41,7 @@
 {
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "ph_command %x", command);
-	icc_write_reg(cs, ICC_CIX0, (command << 2) | 3);
+	cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
 }
 
 
@@ -101,9 +77,8 @@
 }
 
 static void
-icc_bh(void *data)
+icc_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
 	struct PStack *stptr;
 	
 	if (!cs)
@@ -113,7 +88,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -136,22 +111,58 @@
 void
 icc_empty_fifo(struct IsdnCardState *cs, int count)
 {
-	recv_empty_fifo_d(cs, count);
-	icc_write_reg(cs, ICC_CMDR, 0x80);
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "icc_empty_fifo");
+
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "icc_empty_fifo overrun %d",
+				cs->rcvidx + count);
+		cs->writeisac(cs, ICC_CMDR, 0x80);
+		cs->rcvidx = 0;
+		return;
+	}
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ICC_CMDR, 0x80);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "icc_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 static void
 icc_fill_fifo(struct IsdnCardState *cs)
 {
 	int count, more;
-	unsigned char *p;
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "icc_fill_fifo");
 
-	p = xmit_fill_fifo_d(cs, 32, &count, &more);
-	if (!p)
+	if (!cs->tx_skb)
 		return;
 
-	icc_write_fifo(cs, p, count);
-	icc_write_reg(cs, ICC_CMDR, more ? 0x8 : 0xa);
+	count = cs->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
 	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 		debugl1(cs, "icc_fill_fifo dbusytimer running");
 		del_timer(&cs->dbusytimer);
@@ -159,18 +170,26 @@
 	init_timer(&cs->dbusytimer);
 	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
 	add_timer(&cs->dbusytimer);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "icc_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 void
-icc_interrupt(struct IsdnCardState *cs, u8 val)
+icc_interrupt(struct IsdnCardState *cs, u_char val)
 {
-	u8 exval, v1;
+	u_char exval, v1;
+	struct sk_buff *skb;
 	unsigned int count;
 
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "ICC interrupt %x", val);
 	if (val & 0x80) {	/* RME */
-		exval = icc_read_reg(cs, ICC_RSTA);
+		exval = cs->readisac(cs, ICC_RSTA);
 		if ((exval & 0x70) != 0x20) {
 			if (exval & 0x40) {
 				if (cs->debug & L1_DEB_WARN)
@@ -186,15 +205,24 @@
 				cs->err_crc++;
 #endif
 			}
-			icc_write_reg(cs, ICC_CMDR, 0x80);
-			cs->rcvidx = 0;
+			cs->writeisac(cs, ICC_CMDR, 0x80);
 		} else {
-			count = icc_read_reg(cs, ICC_RBCL) & 0x1f;
+			count = cs->readisac(cs, ICC_RBCL) & 0x1f;
 			if (count == 0)
 				count = 32;
 			icc_empty_fifo(cs, count);
-			recv_rme_d(cs);
+			if ((count = cs->rcvidx) > 0) {
+				cs->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "HiSax: D receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
 		}
+		cs->rcvidx = 0;
+		schedule_event(cs, D_RCVBUFREADY);
 	}
 	if (val & 0x40) {	/* RPF */
 		icc_empty_fifo(cs, 32);
@@ -205,20 +233,39 @@
 			debugl1(cs, "ICC RSC interrupt");
 	}
 	if (val & 0x10) {	/* XPR */
-		xmit_xpr_d(cs);
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			schedule_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len) {
+				icc_fill_fifo(cs);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb_irq(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			}
+		}
+		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+			cs->tx_cnt = 0;
+			icc_fill_fifo(cs);
+		} else
+			schedule_event(cs, D_XMTBUFREADY);
 	}
+      afterXPR:
 	if (val & 0x04) {	/* CISQ */
-		exval = icc_read_reg(cs, ICC_CIR0);
+		exval = cs->readisac(cs, ICC_CIR0);
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ICC CIR0 %02X", exval );
 		if (exval & 2) {
 			cs->dc.icc.ph_state = (exval >> 2) & 0xf;
 			if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
-			sched_d_event(cs, D_L1STATECHANGE);
+			schedule_event(cs, D_L1STATECHANGE);
 		}
 		if (exval & 1) {
-			exval = icc_read_reg(cs, ICC_CIR1);
+			exval = cs->readisac(cs, ICC_CIR1);
 			if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "ICC CIR1 %02X", exval );
 		}
@@ -229,7 +276,7 @@
 			debugl1(cs, "ICC SIN interrupt");
 	}
 	if (val & 0x01) {	/* EXI */
-		exval = icc_read_reg(cs, ICC_EXIR);
+		exval = cs->readisac(cs, ICC_EXIR);
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "ICC EXIR %02x", exval);
 		if (exval & 0x80) {  /* XMR */
@@ -237,10 +284,26 @@
 			printk(KERN_WARNING "HiSax: ICC XMR\n");
 		}
 		if (exval & 0x40) {  /* XDU */
-			xmit_xdu_d(cs, NULL);
+			debugl1(cs, "ICC XDU");
+			printk(KERN_WARNING "HiSax: ICC XDU\n");
+#ifdef ERROR_STATISTIC
+			cs->err_tx++;
+#endif
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				schedule_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) { /* Restart frame */
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+				icc_fill_fifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
+				debugl1(cs, "ICC XDU no skb");
+			}
 		}
 		if (exval & 0x04) {  /* MOS */
-			v1 = icc_read_reg(cs, ICC_MOSR);
+			v1 = cs->readisac(cs, ICC_MOSR);
 			if (cs->debug & L1_DEB_MONITOR)
 				debugl1(cs, "ICC MOSR %02x", v1);
 #if ARCOFI_USE
@@ -251,7 +314,7 @@
 							debugl1(cs, "ICC MON RX out of memory!");
 						cs->dc.icc.mocr &= 0xf0;
 						cs->dc.icc.mocr |= 0x0a;
-						icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+						cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 						goto afterMONR0;
 					} else
 						cs->dc.icc.mon_rxp = 0;
@@ -259,18 +322,18 @@
 				if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
 					cs->dc.icc.mocr &= 0xf0;
 					cs->dc.icc.mocr |= 0x0a;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					cs->dc.icc.mon_rxp = 0;
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "ICC MON RX overflow!");
 					goto afterMONR0;
 				}
-				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = icc_read_reg(cs, ICC_MOR0);
+				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
 				if (cs->dc.icc.mon_rxp == 1) {
 					cs->dc.icc.mocr |= 0x04;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 				}
 			}
 		      afterMONR0:
@@ -281,7 +344,7 @@
 							debugl1(cs, "ICC MON RX out of memory!");
 						cs->dc.icc.mocr &= 0x0f;
 						cs->dc.icc.mocr |= 0xa0;
-						icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+						cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 						goto afterMONR1;
 					} else
 						cs->dc.icc.mon_rxp = 0;
@@ -289,51 +352,51 @@
 				if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
 					cs->dc.icc.mocr &= 0x0f;
 					cs->dc.icc.mocr |= 0xa0;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					cs->dc.icc.mon_rxp = 0;
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "ICC MON RX overflow!");
 					goto afterMONR1;
 				}
-				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = icc_read_reg(cs, ICC_MOR1);
+				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
 				cs->dc.icc.mocr |= 0x40;
-				icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 			}
 		      afterMONR1:
 			if (v1 & 0x04) {
 				cs->dc.icc.mocr &= 0xf0;
-				icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 				cs->dc.icc.mocr |= 0x0a;
-				icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
-				sched_d_event(cs, D_RX_MON0);
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				schedule_event(cs, D_RX_MON0);
 			}
 			if (v1 & 0x40) {
 				cs->dc.icc.mocr &= 0x0f;
-				icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 				cs->dc.icc.mocr |= 0xa0;
-				icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
-				sched_d_event(cs, D_RX_MON1);
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				schedule_event(cs, D_RX_MON1);
 			}
 			if (v1 & 0x02) {
 				if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
 					(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
 					!(v1 & 0x08))) {
 					cs->dc.icc.mocr &= 0xf0;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					cs->dc.icc.mocr |= 0x0a;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					if (cs->dc.icc.mon_txc &&
 						(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
-						sched_d_event(cs, D_TX_MON0);
+						schedule_event(cs, D_TX_MON0);
 					goto AfterMOX0;
 				}
 				if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
-					sched_d_event(cs, D_TX_MON0);
+					schedule_event(cs, D_TX_MON0);
 					goto AfterMOX0;
 				}
-				icc_write_reg(cs, ICC_MOX0,
+				cs->writeisac(cs, ICC_MOX0,
 					cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
@@ -344,19 +407,19 @@
 					(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
 					!(v1 & 0x80))) {
 					cs->dc.icc.mocr &= 0x0f;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					cs->dc.icc.mocr |= 0xa0;
-					icc_write_reg(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
 					if (cs->dc.icc.mon_txc &&
 						(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
-						sched_d_event(cs, D_TX_MON1);
+						schedule_event(cs, D_TX_MON1);
 					goto AfterMOX1;
 				}
 				if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
-					sched_d_event(cs, D_TX_MON1);
+					schedule_event(cs, D_TX_MON1);
 					goto AfterMOX1;
 				}
-				icc_write_reg(cs, ICC_MOX1,
+				cs->writeisac(cs, ICC_MOX1,
 					cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
@@ -372,35 +435,91 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 	int  val;
 
 	switch (pr) {
 		case (PH_DATA |REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				icc_fill_fifo(cs);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			icc_fill_fifo(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
 				(cs->dc.icc.ph_state == ICC_IND_DR))
 			        ph_command(cs, ICC_CMD_DI);
 			else
 				ph_command(cs, ICC_CMD_RES);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_ENABLE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, ICC_CMD_DI);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO1 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, ICC_CMD_AR);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, ICC_CMD_AI);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_TESTLOOP | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			val = 0;
 			if (1 & (long) arg)
 				val |= 0x0c;
@@ -409,20 +528,21 @@
 			if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 				/* IOM 1 Mode */
 				if (!val) {
-					icc_write_reg(cs, ICC_SPCR, 0xa);
-					icc_write_reg(cs, ICC_ADF1, 0x2);
+					cs->writeisac(cs, ICC_SPCR, 0xa);
+					cs->writeisac(cs, ICC_ADF1, 0x2);
 				} else {
-					icc_write_reg(cs, ICC_SPCR, val);
-					icc_write_reg(cs, ICC_ADF1, 0xa);
+					cs->writeisac(cs, ICC_SPCR, val);
+					cs->writeisac(cs, ICC_ADF1, 0xa);
 				}
 			} else {
 				/* IOM 2 Mode */
-				icc_write_reg(cs, ICC_SPCR, val);
+				cs->writeisac(cs, ICC_SPCR, val);
 				if (val)
-					icc_write_reg(cs, ICC_ADF1, 0x8);
+					cs->writeisac(cs, ICC_ADF1, 0x8);
 				else
-					icc_write_reg(cs, ICC_ADF1, 0x0);
+					cs->writeisac(cs, ICC_ADF1, 0x0);
 			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_DEACTIVATE | RESPONSE):
 			skb_queue_purge(&cs->rq);
@@ -434,7 +554,7 @@
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-				sched_d_event(cs, D_CLEARBUSY);
+				schedule_event(cs, D_CLEARBUSY);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -443,11 +563,10 @@
 	}
 }
 
-static int
+void
 setstack_icc(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = ICC_l1hw;
-	return 0;
 }
 
 void 
@@ -469,8 +588,8 @@
 	int	rbch, star;
 
 	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
-		rbch = icc_read_reg(cs, ICC_RBCH);
-		star = icc_read_reg(cs, ICC_STAR);
+		rbch = cs->readisac(cs, ICC_RBCH);
+		star = cs->readisac(cs, ICC_STAR);
 		if (cs->debug) 
 			debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
 				rbch, star);
@@ -478,7 +597,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
@@ -492,77 +611,75 @@
 				printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
 				debugl1(cs, "D-Channel Busy no skb");
 			}
-			icc_write_reg(cs, ICC_CMDR, 0x01); /* Transmitter reset */
-			cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */
+			cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
+			cs->irq_func(cs->irq, cs, NULL);
 		}
 	}
 }
 
-static struct dc_l1_ops icc_l1_ops = {
-	.fill_fifo  = icc_fill_fifo,
-	.open       = setstack_icc,
-	.close      = DC_Close_icc,
-	.bh_func    = icc_bh,
-	.dbusy_func = dbusy_timer_handler,
-};
-
 void __init
 initicc(struct IsdnCardState *cs)
 {
-	int val, eval;
-
-	dc_l1_init(cs, &icc_l1_ops);
+	cs->setstack_d = setstack_icc;
+	cs->DC_Close = DC_Close_icc;
 	cs->dc.icc.mon_tx = NULL;
 	cs->dc.icc.mon_rx = NULL;
+  	cs->writeisac(cs, ICC_MASK, 0xff);
+  	cs->dc.icc.mocr = 0xaa;
+	if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+		/* IOM 1 Mode */
+		cs->writeisac(cs, ICC_ADF2, 0x0);
+		cs->writeisac(cs, ICC_SPCR, 0xa);
+		cs->writeisac(cs, ICC_ADF1, 0x2);
+		cs->writeisac(cs, ICC_STCR, 0x70);
+		cs->writeisac(cs, ICC_MODE, 0xc9);
+	} else {
+		/* IOM 2 Mode */
+		if (!cs->dc.icc.adf2)
+			cs->dc.icc.adf2 = 0x80;
+		cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
+		cs->writeisac(cs, ICC_SQXR, 0xa0);
+		cs->writeisac(cs, ICC_SPCR, 0x20);
+		cs->writeisac(cs, ICC_STCR, 0x70);
+		cs->writeisac(cs, ICC_MODE, 0xca);
+		cs->writeisac(cs, ICC_TIMR, 0x00);
+		cs->writeisac(cs, ICC_ADF1, 0x20);
+	}
+	ph_command(cs, ICC_CMD_RES);
+	cs->writeisac(cs, ICC_MASK, 0x0);
+	ph_command(cs, ICC_CMD_DI);
+}
+
+void __init
+clear_pending_icc_ints(struct IsdnCardState *cs)
+{
+	int val, eval;
 
-	val = icc_read_reg(cs, ICC_STAR);
+	val = cs->readisac(cs, ICC_STAR);
 	debugl1(cs, "ICC STAR %x", val);
-	val = icc_read_reg(cs, ICC_MODE);
+	val = cs->readisac(cs, ICC_MODE);
 	debugl1(cs, "ICC MODE %x", val);
-	val = icc_read_reg(cs, ICC_ADF2);
+	val = cs->readisac(cs, ICC_ADF2);
 	debugl1(cs, "ICC ADF2 %x", val);
-	val = icc_read_reg(cs, ICC_ISTA);
+	val = cs->readisac(cs, ICC_ISTA);
 	debugl1(cs, "ICC ISTA %x", val);
 	if (val & 0x01) {
-		eval = icc_read_reg(cs, ICC_EXIR);
+		eval = cs->readisac(cs, ICC_EXIR);
 		debugl1(cs, "ICC EXIR %x", eval);
 	}
-	val = icc_read_reg(cs, ICC_CIR0);
+	val = cs->readisac(cs, ICC_CIR0);
 	debugl1(cs, "ICC CIR0 %x", val);
 	cs->dc.icc.ph_state = (val >> 2) & 0xf;
-	sched_d_event(cs, D_L1STATECHANGE);
+	schedule_event(cs, D_L1STATECHANGE);
 	/* Disable all IRQ */
-	icc_write_reg(cs, ICC_MASK, 0xFF);
-
-  	cs->dc.icc.mocr = 0xaa;
-	if (test_bit(HW_IOM1, &cs->HW_Flags)) {
-		/* IOM 1 Mode */
-		icc_write_reg(cs, ICC_ADF2, 0x0);
-		icc_write_reg(cs, ICC_SPCR, 0xa);
-		icc_write_reg(cs, ICC_ADF1, 0x2);
-		icc_write_reg(cs, ICC_STCR, 0x70);
-		icc_write_reg(cs, ICC_MODE, 0xc9);
-	} else {
-		/* IOM 2 Mode */
-		if (!cs->dc.icc.adf2)
-			cs->dc.icc.adf2 = 0x80;
-		icc_write_reg(cs, ICC_ADF2, cs->dc.icc.adf2);
-		icc_write_reg(cs, ICC_SQXR, 0xa0);
-		icc_write_reg(cs, ICC_SPCR, 0x20);
-		icc_write_reg(cs, ICC_STCR, 0x70);
-		icc_write_reg(cs, ICC_MODE, 0xca);
-		icc_write_reg(cs, ICC_TIMR, 0x00);
-		icc_write_reg(cs, ICC_ADF1, 0x20);
-	}
-	ph_command(cs, ICC_CMD_RES);
-	icc_write_reg(cs, ICC_MASK, 0x0);
-	ph_command(cs, ICC_CMD_DI);
+	cs->writeisac(cs, ICC_MASK, 0xFF);
 }
 
-int
-icc_setup(struct IsdnCardState *cs, struct dc_hw_ops *icc_ops)
+void __devinit
+setup_icc(struct IsdnCardState *cs)
 {
-	cs->dc_hw_ops = icc_ops;
-	ICCVersion(cs, "HiSax:");
-	return 0;
+	INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs);
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 }
--- diff/drivers/isdn/hisax/icc.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/icc.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: icc.h,v 1.2.6.3 2001/09/23 22:24:48 kai Exp $
+/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * ICC specific routines
  *
@@ -65,6 +65,8 @@
 #define ICC_IND_AIL    0xE
 #define ICC_IND_DC     0xF
 
-extern int  icc_setup(struct IsdnCardState *cs, struct dc_hw_ops *icc_ops);
+extern void ICCVersion(struct IsdnCardState *cs, char *s);
 extern void initicc(struct IsdnCardState *cs);
-extern void icc_interrupt(struct IsdnCardState *cs, u8 val);
+extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
+extern void clear_pending_icc_ints(struct IsdnCardState *cs);
+extern void setup_icc(struct IsdnCardState *);
--- diff/drivers/isdn/hisax/ipac.h	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/ipac.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ipac.h,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $
  *
  * IPAC specific defines
  *
@@ -10,8 +10,6 @@
  *
  */
 
-#include <linux/interrupt.h>
-
 /* All Registers original Siemens Spec  */
 
 #define IPAC_CONF	0xC0
@@ -29,76 +27,3 @@
 #define IPAC_PCFG	0xCA
 #define IPAC_SCFG	0xCB
 #define IPAC_TIMR2	0xCC
-
-void ipac_init(struct IsdnCardState *cs);
-irqreturn_t ipac_irq(int intno, void *dev_id, struct pt_regs *regs);
-int  ipac_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipac_dc_ops,
-		struct bc_hw_ops *ipac_bc_ops);
-
-/* Macro to build the needed D- and B-Channel access routines given
- * access functions for the IPAC */
-
-#define BUILD_IPAC_OPS(ipac)                                                  \
-                                                                              \
-static u8                                                                     \
-ipac ## _dc_read(struct IsdnCardState *cs, u8 offset)                         \
-{                                                                             \
-	return ipac ## _read(cs, offset+0x80);                                \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _dc_write(struct IsdnCardState *cs, u8 offset, u8 value)              \
-{                                                                             \
-	ipac ## _write(cs, offset+0x80, value);                               \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _dc_read_fifo(struct IsdnCardState *cs, u8 * data, int size)          \
-{                                                                             \
-	ipac ## _readfifo(cs, 0x80, data, size);                              \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _dc_write_fifo(struct IsdnCardState *cs, u8 * data, int size)         \
-{                                                                             \
-	ipac ## _writefifo(cs, 0x80, data, size);                             \
-}                                                                             \
-                                                                              \
-static struct dc_hw_ops ipac ## _dc_ops = {                                   \
-	.read_reg   = ipac ## _dc_read,                                       \
-	.write_reg  = ipac ## _dc_write,                                      \
-	.read_fifo  = ipac ## _dc_read_fifo,                                  \
-	.write_fifo = ipac ## _dc_write_fifo,                                 \
-};                                                                            \
-                                                                              \
-static u8                                                                     \
-ipac ## _bc_read(struct IsdnCardState *cs, int hscx, u8 offset)               \
-{                                                                             \
-	return ipac ## _read(cs, offset + (hscx ? 0x40 : 0));                 \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _bc_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)    \
-{                                                                             \
-	ipac ## _write(cs, offset + (hscx ? 0x40 : 0), value);                \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _bc_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size) \
-{                                                                             \
-	ipac ## _readfifo(cs, hscx ? 0x40 : 0, data, size);                   \
-}                                                                             \
-                                                                              \
-static void                                                                   \
-ipac ## _bc_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)\
-{                                                                             \
-	ipac ## _writefifo(cs, hscx ? 0x40 : 0, data, size);                  \
-}                                                                             \
-                                                                              \
-static struct bc_hw_ops ipac ## _bc_ops = {                                   \
-	.read_reg   = ipac ## _bc_read,                                       \
-	.write_reg  = ipac ## _bc_write,                                      \
-	.read_fifo  = ipac ## _bc_read_fifo,                                  \
-	.write_fifo = ipac ## _bc_write_fifo,                                 \
-}
-
--- diff/drivers/isdn/hisax/ipacx.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/ipacx.c	2004-02-18 09:03:59.000000000 +0000
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/workqueue.h>
 #include "hisax_if.h"
 #include "hisax.h"
 #include "isdnl1.h"
@@ -24,6 +23,7 @@
 #define B_FIFO_SIZE       64
 #define D_FIFO_SIZE       32
 
+
 // ipacx interrupt mask values    
 #define _MASK_IMASK     0x2E  // global mask
 #define _MASKB_IMASK    0x0B
@@ -37,13 +37,16 @@
 static void dch_l2l1(struct PStack *st, int pr, void *arg);
 static void dbusy_timer_handler(struct IsdnCardState *cs);
 static void ipacx_new_ph(struct IsdnCardState *cs);
-static void dch_bh(void *data);
+static void dch_bh(struct IsdnCardState *cs);
 static void dch_empty_fifo(struct IsdnCardState *cs, int count);
 static void dch_fill_fifo(struct IsdnCardState *cs);
 static inline void dch_int(struct IsdnCardState *cs);
+static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void __devinit dch_init(struct IsdnCardState *cs);
 static void bch_l2l1(struct PStack *st, int pr, void *arg);
-static void ipacx_bc_empty_fifo(struct BCState *bcs, int count);
-static void bch_int(struct IsdnCardState *cs, u8 hscx);
+static void bch_empty_fifo(struct BCState *bcs, int count);
+static void bch_fill_fifo(struct BCState *bcs);
+static void bch_int(struct IsdnCardState *cs, u_char hscx);
 static void bch_mode(struct BCState *bcs, int mode, int bc);
 static void bch_close_state(struct BCState *bcs);
 static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
@@ -51,45 +54,6 @@
 static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
 static void __init clear_pending_ints(struct IsdnCardState *cs);
 
-static inline u8
-ipacx_bc_read_reg(struct BCState *bcs, u8 addr)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	return cs->bc_hw_ops->read_reg(cs, bcs->unit, addr);
-}
-
-static inline void
-ipacx_bc_write_reg(struct BCState *bcs, u8 addr, u8 val)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	cs->bc_hw_ops->write_reg(cs, bcs->unit, addr, val);
-}
-
-static inline u8
-ipacx_read_reg(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-ipacx_write_reg(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
-static inline void
-ipacx_read_fifo(struct IsdnCardState *cs, u8 *p, int len)
-{
-	return cs->dc_hw_ops->read_fifo(cs, p, len);
-}
-
-static inline void
-ipacx_write_fifo(struct IsdnCardState *cs, u8 *p, int len)
-{
-	return cs->dc_hw_ops->write_fifo(cs, p, len);
-}
 //----------------------------------------------------------
 // Issue Layer 1 command to chip
 //----------------------------------------------------------
@@ -99,7 +63,10 @@
 	if (cs->debug &L1_DEB_ISAC)
 		debugl1(cs, "ph_command (%#x) in (%#x)", command,
 			cs->dc.isac.ph_state);
-	ipacx_write_reg(cs, IPACX_CIX0, (command << 4) | 0x0E);
+//###################################  
+//	printk(KERN_INFO "ph_command (%#x)\n", command);
+//###################################  
+	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
 }
 
 //----------------------------------------------------------
@@ -108,12 +75,15 @@
 static inline void 
 cic_int(struct IsdnCardState *cs)
 {
-	u8 event;
+	u_char event;
 
-	event = ipacx_read_reg(cs, IPACX_CIR0) >> 4;
+	event = cs->readisac(cs, IPACX_CIR0) >> 4;
 	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
-	cs->dc.isac.ph_state = event;
-	sched_d_event(cs, D_L1STATECHANGE);
+//#########################################  
+//	printk(KERN_INFO "cic_int(%x)\n", event);
+//#########################################  
+  cs->dc.isac.ph_state = event;
+  schedule_event(cs, D_L1STATECHANGE);
 }
 
 //==========================================================
@@ -128,21 +98,63 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
-  u8 cda1_cr, cda2_cr;
+  u_char cda1_cr, cda2_cr;
 
 	switch (pr) {
 		case (PH_DATA |REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug &DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				dch_fill_fifo(cs);
+			}
 			break;
+      
 		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			dch_fill_fifo(cs);
 			break;
+      
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
+
 		case (HW_RESET | REQUEST):
 		case (HW_ENABLE | REQUEST):
-			ph_command(cs, IPACX_CMD_TIM);
+			if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
+				(cs->dc.isac.ph_state == IPACX_IND_DR) ||
+				(cs->dc.isac.ph_state == IPACX_IND_DC))
+			        ph_command(cs, IPACX_CMD_TIM);
+			else
+				ph_command(cs, IPACX_CMD_RES);
 			break;
 
 		case (HW_INFO3 | REQUEST):
@@ -150,21 +162,21 @@
 			break;
 
 		case (HW_TESTLOOP | REQUEST):
-      ipacx_write_reg(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
-      ipacx_write_reg(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
-      cda1_cr = ipacx_read_reg(cs, IPACX_CDA1_CR);
-      cda2_cr = ipacx_read_reg(cs, IPACX_CDA2_CR);
+      cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
+      cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
+      cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
+      cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
 			if ((long)arg &1) { // loop B1
-        ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr |0x0a); 
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); 
       }
       else {  // B1 off
-        ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); 
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); 
       }
 			if ((long)arg &2) { // loop B2
-        ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr |0x14); 
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); 
       }
       else {  // B2 off
-        ipacx_write_reg(cs, IPACX_CDA1_CR, cda1_cr &~0x14); 
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); 
       }
 			break;
 
@@ -194,14 +206,14 @@
 	int	rbchd, stard;
 
 	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
-		rbchd = ipacx_read_reg(cs, IPACX_RBCHD);
-		stard = ipacx_read_reg(cs, IPACX_STARD);
+		rbchd = cs->readisac(cs, IPACX_RBCHD);
+		stard = cs->readisac(cs, IPACX_STARD);
 		if (cs->debug) 
       debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
 		if (!(stard &0x40)) { // D-Channel Busy
 			set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
       for (st = cs->stlist; st; st = st->next) {
-				st->l2.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
+				st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
 			}
 		} else {
 			// seems we lost an interrupt; reset transceiver */
@@ -214,7 +226,7 @@
 				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 				debugl1(cs, "D-Channel Busy no skb");
 			}
-			ipacx_write_reg(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
+			cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
 		}
 	}
 }
@@ -268,9 +280,8 @@
 // bottom half handler for D channel
 //----------------------------------------------------------
 static void
-dch_bh(void *data)
+dch_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
 	struct PStack *st;
 	
 	if (!cs) return;
@@ -278,7 +289,7 @@
 	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
 		if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
 		for (st = cs->stlist; st; st = st->next) {
-			st->l2.l1l2(st, PH_PAUSE | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
 		}
 	}
   
@@ -301,8 +312,33 @@
 static void 
 dch_empty_fifo(struct IsdnCardState *cs, int count)
 {
-	recv_empty_fifo_d(cs, count);
-	ipacx_write_reg(cs, IPACX_CMDRD, 0x80); // RMC
+	u_char *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_empty_fifo()");
+
+  // message too large, remove
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "dch_empty_fifo() incoming message too large");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+		cs->rcvidx = 0;
+		return;
+	}
+  
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+  
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_empty_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 //----------------------------------------------------------
@@ -311,21 +347,28 @@
 static void 
 dch_fill_fifo(struct IsdnCardState *cs)
 {
-	int count, more;
-	unsigned char cmd, *p;
+	int count;
+	u_char cmd, *ptr;
 
-	p = xmit_fill_fifo_d(cs, 32, &count, &more);
-	if (!p)
-		return;
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_fill_fifo()");
+    
+	if (!cs->tx_skb) return;
+	count = cs->tx_skb->len;
+	if (count <= 0) return;
 
-	if (more) {
+	if (count > D_FIFO_SIZE) {
+		count = D_FIFO_SIZE;
 		cmd   = 0x08; // XTF
 	} else {
 		cmd   = 0x0A; // XTF | XME
 	}
   
-	ipacx_write_fifo(cs, p, count);
-	ipacx_write_reg(cs, IPACX_CMDRD, cmd);
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, cmd);
   
   // set timeout for transmission contol
 	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
@@ -335,6 +378,14 @@
 	init_timer(&cs->dbusytimer);
 	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
 	add_timer(&cs->dbusytimer);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_fill_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 //----------------------------------------------------------
@@ -343,35 +394,46 @@
 static inline void 
 dch_int(struct IsdnCardState *cs)
 {
-	u8 istad, rstad;
+	struct sk_buff *skb;
+	u_char istad, rstad;
 	int count;
 
-	istad = ipacx_read_reg(cs, IPACX_ISTAD);
+	istad = cs->readisac(cs, IPACX_ISTAD);
+//##############################################  
+//	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
+//##############################################  
   
 	if (istad &0x80) {  // RME
-	  rstad = ipacx_read_reg(cs, IPACX_RSTAD);
+	  rstad = cs->readisac(cs, IPACX_RSTAD);
 		if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
 			if (!(rstad &0x80))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "dch_int(): invalid frame");
+          debugl1(cs, "dch_int(): invalid frame");
 			if ((rstad &0x40))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "dch_int(): RDO");
+          debugl1(cs, "dch_int(): RDO");
 			if (!(rstad &0x20))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "dch_int(): CRC error");
-			ipacx_write_reg(cs, IPACX_CMDRD, 0x80);  // RMC
-			cs->rcvidx = 0;
+          debugl1(cs, "dch_int(): CRC error");
+	    cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC
 		} else {  // received frame ok
-			count = ipacx_read_reg(cs, IPACX_RBCLD);
-			// FIXME this looks flaky
-			if (count) count--; // RSTAB is last byte
+			count = cs->readisac(cs, IPACX_RBCLD);
+      if (count) count--; // RSTAB is last byte
 			count &= D_FIFO_SIZE-1;
-			if (count == 0)
-				count = D_FIFO_SIZE;
+			if (count == 0) count = D_FIFO_SIZE;
 			dch_empty_fifo(cs, count);
-			recv_rme_d(cs);
-		}
+			if ((count = cs->rcvidx) > 0) {
+	      cs->rcvidx = 0;
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
+    }
+	  cs->rcvidx = 0;
+		schedule_event(cs, D_RCVBUFREADY);
 	}
 
 	if (istad &0x40) {  // RPF
@@ -380,34 +442,56 @@
 
 	if (istad &0x20) {  // RFO
 		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
-	  ipacx_write_reg(cs, IPACX_CMDRD, 0x40); //RRES
+	  cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
 	}
   
-	if (istad &0x10) {  // XPR
-		xmit_xpr_d(cs);
-	}  
+  if (istad &0x10) {  // XPR
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			schedule_event(cs, D_CLEARBUSY);
+    if (cs->tx_skb) {
+      if (cs->tx_skb->len) {
+        dch_fill_fifo(cs);
+        goto afterXPR;
+      }
+      else {
+        dev_kfree_skb_irq(cs->tx_skb);
+        cs->tx_skb = NULL;
+        cs->tx_cnt = 0;
+      }
+    }
+    if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+      cs->tx_cnt = 0;
+      dch_fill_fifo(cs);
+    } 
+    else {
+      schedule_event(cs, D_XMTBUFREADY);
+    }  
+  }  
+  afterXPR:
 
 	if (istad &0x0C) {  // XDU or XMR
-		xmit_xdu_d(cs, NULL);
-	}
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
+	  if (cs->tx_skb) {
+	    skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
+	    cs->tx_cnt = 0;
+			dch_fill_fifo(cs);
+		} else {
+			printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+			debugl1(cs, "ISAC XDU no skb");
+		}
+  }
 }
 
 //----------------------------------------------------------
 //----------------------------------------------------------
-static int
+static void __devinit
 dch_setstack(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = dch_l2l1;
-	return 0;
 }
 
-static struct dc_l1_ops ipacx_dc_l1_ops = {
-	.fill_fifo  = dch_fill_fifo,
-	.open       = dch_setstack,
-	.bh_func    = dch_bh,
-	.dbusy_func = dbusy_timer_handler,
-};
-
 //----------------------------------------------------------
 //----------------------------------------------------------
 static void __devinit
@@ -415,12 +499,16 @@
 {
 	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
 
-	dc_l1_init(cs, &ipacx_dc_l1_ops);
+	cs->setstack_d      = dch_setstack;
+  
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 
-	ipacx_write_reg(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
-	ipacx_write_reg(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
-	ipacx_write_reg(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
-	ipacx_write_reg(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
+  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
+  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
+  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
+  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
 }
 
 
@@ -434,31 +522,59 @@
 static void
 bch_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->hw.hscx.count = 0;
+				bch_fill_fifo(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
+			} else {
+				set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->tx_skb = skb;
+				bcs->hw.hscx.count = 0;
+				bch_fill_fifo(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			bch_mode(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			bch_mode(st->l1.bcs, 0, st->l1.bc);
-			st->l2.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			bch_mode(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -467,94 +583,204 @@
 // Read B channel fifo to receive buffer
 //----------------------------------------------------------
 static void
-ipacx_bc_empty_fifo(struct BCState *bcs, int count)
+bch_empty_fifo(struct BCState *bcs, int count)
 {
-	recv_empty_fifo_b(bcs, count);
-	ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x80);  // RMC
+	u_char *ptr, hscx;
+	struct IsdnCardState *cs;
+	int cnt;
+
+	cs = bcs->cs;
+  hscx = bcs->hw.hscx.hscx;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_empty_fifo()");
+
+  // message too large, remove
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "bch_empty_fifo() incoming packet too large");
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+  
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	cnt = count;
+	while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+  
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 //----------------------------------------------------------
 // Fill buffer to transmit FIFO
 //----------------------------------------------------------
 static void
-ipacx_bc_fill_fifo(struct BCState *bcs)
+bch_fill_fifo(struct BCState *bcs)
 {
-	int more, count;
-	unsigned char *p;
-
-	p = xmit_fill_fifo_b(bcs, B_FIFO_SIZE, &count, &more);
-	if (!p)
-		return;
-
-	while (count--)
-		ipacx_bc_write_reg(bcs, IPACX_XFIFOB, *p++); 
-
-	ipacx_bc_write_reg(bcs, IPACX_CMDRB, (more ? 0x08 : 0x0a));
+	struct IsdnCardState *cs;
+	int more, count, cnt;
+	u_char *ptr, *p, hscx;
+
+	cs = bcs->cs;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_fill_fifo()");
+
+	if (!bcs->tx_skb)           return;
+	if (bcs->tx_skb->len <= 0)  return;
+
+	hscx = bcs->hw.hscx.hscx;
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > B_FIFO_SIZE) {
+		more  = 1;
+		count = B_FIFO_SIZE;
+	} else {
+		count = bcs->tx_skb->len;
+	}  
+	cnt = count;
+    
+	p = ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 //----------------------------------------------------------
 // B channel interrupt handler
 //----------------------------------------------------------
-
-static void
-reset_xmit(struct BCState *bcs)
-{
-	ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x01);  // XRES
-}
-
 static void
-bch_int(struct IsdnCardState *cs, u8 hscx)
+bch_int(struct IsdnCardState *cs, u_char hscx)
 {
-	u8 istab;
+	u_char istab;
 	struct BCState *bcs;
+	struct sk_buff *skb;
 	int count;
-	u8 rstab;
+	u_char rstab;
 
 	bcs = cs->bcs + hscx;
-	istab = ipacx_bc_read_reg(bcs, IPACX_ISTAB);
+	istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
+//##############################################  
+//	printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
+//##############################################  
 	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
 
 	if (istab &0x80) {	// RME
-		rstab = ipacx_bc_read_reg(bcs, IPACX_RSTAB);
+		rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
 		if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
 			if (!(rstab &0x80))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
+          debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
 			if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
+          debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
 			if (!(rstab &0x20))
 				if (cs->debug &L1_DEB_WARN) 
-					debugl1(cs, "bch_int() B-%d: CRC error", hscx);
-			ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x80);  // RMC
-			bcs->rcvidx = 0;
-		}  else {  // received frame ok
-			count = ipacx_bc_read_reg(bcs, IPACX_RBCLB) &(B_FIFO_SIZE-1);
-			if (count == 0)
-				count = B_FIFO_SIZE;
-
-			ipacx_bc_empty_fifo(bcs, count);
-			recv_rme_b(bcs);
+          debugl1(cs, "bch_int() B-%d: CRC error", hscx);
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		} 
+    else {  // received frame ok
+			count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
+			if (count == 0) count = B_FIFO_SIZE;
+			bch_empty_fifo(bcs, count);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug &L1_DEB_HSCX_FIFO)
+					debugl1(cs, "bch_int Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
 		}
+		bcs->hw.hscx.rcvidx = 0;
+		schedule_event(bcs, B_RCVBUFREADY);
 	}
   
 	if (istab &0x40) {	// RPF
-		ipacx_bc_empty_fifo(bcs, B_FIFO_SIZE);
-		recv_rpf_b(bcs);
+		bch_empty_fifo(bcs, B_FIFO_SIZE);
+
+		if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
+			// receive transparent audio data
+			if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
+				printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
+			else {
+				memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			schedule_event(bcs, B_RCVBUFREADY);
+		}
 	}
   
 	if (istab &0x20) {	// RFO
 		if (cs->debug &L1_DEB_WARN) 
 			debugl1(cs, "bch_int() B-%d: RFO error", hscx);
-		ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x40);  // RRES
+		cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40);  // RRES
 	}
 
 	if (istab &0x10) {	// XPR
-		xmit_xpr_b(bcs);
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				bch_fill_fifo(bcs);
+				goto afterXPR;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.hscx.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+			}
+			dev_kfree_skb_irq(bcs->tx_skb);
+			bcs->hw.hscx.count = 0;
+			bcs->tx_skb = NULL;
+    		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.hscx.count = 0;
+			set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bch_fill_fifo(bcs);
+		} else {
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
 	}
+  afterXPR:
 
 	if (istab &0x04) {	// XDU
-		xmit_xdu_b(bcs, reset_xmit);
+    if (bcs->mode == L1_MODE_TRANS) {
+			bch_fill_fifo(bcs);
+    }  
+    else {
+      if (bcs->tx_skb) {  // restart transmitting the whole frame
+        skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+        bcs->tx_cnt += bcs->hw.hscx.count;
+        bcs->hw.hscx.count = 0;
+      }
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01);  // XRES
+      if (cs->debug &L1_DEB_WARN)
+        debugl1(cs, "bch_int() B-%d XDU error", hscx);
+    }
 	}
 }
 
@@ -564,7 +790,7 @@
 bch_mode(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int hscx = bcs->unit;
+	int hscx = bcs->hw.hscx.hscx;
 
         bc = bc ? 1 : 0;  // in case bc is greater than 1
 	if (cs->debug & L1_DEB_HSCX)
@@ -575,33 +801,33 @@
   // map controller to according timeslot
   if (!hscx)
   {
-    ipacx_write_reg(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
-    ipacx_write_reg(cs, IPACX_BCHA_CR,       0x88); 
+    cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHA_CR,       0x88); 
   }
   else
   {
-    ipacx_write_reg(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
-    ipacx_write_reg(cs, IPACX_BCHB_CR,       0x88); 
+    cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHB_CR,       0x88); 
   }
 
 	switch (mode) {
 		case (L1_MODE_NULL):
-		    ipacx_bc_write_reg(bcs, IPACX_MODEB, 0xC0);  // rec off
-		    ipacx_bc_write_reg(bcs, IPACX_EXMB,  0x30);  // std adj.
-		    ipacx_bc_write_reg(bcs, IPACX_MASKB, 0xFF);  // ints off
-		    ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0);  // rec off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x30);  // std adj.
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF);  // ints off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
 		    break;
 		case (L1_MODE_TRANS):
-		    ipacx_bc_write_reg(bcs, IPACX_MODEB, 0x88);  // ext transp mode
-		    ipacx_bc_write_reg(bcs, IPACX_EXMB,  0x00);  // xxx00000
-		    ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41);  // validate adjustments
-		    ipacx_bc_write_reg(bcs, IPACX_MASKB, _MASKB_IMASK);
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88);  // ext transp mode
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x00);  // xxx00000
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
 		    break;
 		case (L1_MODE_HDLC):
-		    ipacx_bc_write_reg(bcs, IPACX_MODEB, 0xC8);  // transp mode 0
-		    ipacx_bc_write_reg(bcs, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
-		    ipacx_bc_write_reg(bcs, IPACX_CMDRB, 0x41);  // validate adjustments
-		    ipacx_bc_write_reg(bcs, IPACX_MASKB, _MASKB_IMASK);
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8);  // transp mode 0
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
 		    break;
 	}
 }
@@ -612,7 +838,23 @@
 bch_close_state(struct BCState *bcs)
 {
 	bch_mode(bcs, 0, bcs->channel);
-	bc_close(bcs);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hscx.rcvbuf) {
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
 }
 
 //----------------------------------------------------------
@@ -620,7 +862,30 @@
 static int
 bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	return bc_open(bcs);
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate: No memory for bcs->blog\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hscx.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
 }
 
 //----------------------------------------------------------
@@ -631,7 +896,7 @@
 	bcs->channel = st->l1.bc;
 	if (bch_open_state(st->l1.hardware, bcs)) return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = bch_l2l1;
+	st->l2.l2l1 = bch_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -643,7 +908,9 @@
 static void __devinit
 bch_init(struct IsdnCardState *cs, int hscx)
 {
-	cs->bcs[hscx].unit          = hscx;
+	cs->bcs[hscx].BC_SetStack   = bch_setstack;
+	cs->bcs[hscx].BC_Close      = bch_close_state;
+	cs->bcs[hscx].hw.hscx.hscx  = hscx;
 	cs->bcs[hscx].cs            = cs;
 	bch_mode(cs->bcs + hscx, 0, hscx);
 }
@@ -659,16 +926,18 @@
 void 
 interrupt_ipacx(struct IsdnCardState *cs)
 {
-	u8 ista;
-	
-	spin_lock(&cs->lock);
-	while ((ista = ipacx_read_reg(cs, IPACX_ISTA))) {
-		if (ista &0x80) bch_int(cs, 0); // B channel interrupts
-		if (ista &0x40) bch_int(cs, 1);
-		if (ista &0x01) dch_int(cs);    // D channel
-		if (ista &0x10) cic_int(cs);    // Layer 1 state
-	}  
-	spin_unlock(&cs->lock);
+	u_char ista;
+  
+	while ((ista = cs->readisac(cs, IPACX_ISTA))) {
+//#################################################  
+//		printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
+//#################################################  
+    if (ista &0x80) bch_int(cs, 0); // B channel interrupts
+    if (ista &0x40) bch_int(cs, 1);
+    
+    if (ista &0x01) dch_int(cs);    // D channel
+    if (ista &0x10) cic_int(cs);    // Layer 1 state
+  }  
 }
 
 //----------------------------------------------------------
@@ -680,23 +949,17 @@
 	int ista;
 
   // all interrupts off
-  ipacx_write_reg(cs, IPACX_MASK, 0xff);
-  ipacx_write_reg(cs, IPACX_MASKD, 0xff);
-  cs->bc_hw_ops->write_reg(cs, 0, IPACX_MASKB, 0xff);
-  cs->bc_hw_ops->write_reg(cs, 1, IPACX_MASKB, 0xff);
-  
-  ista = ipacx_read_reg(cs, IPACX_ISTA); 
-  if (ista &0x80) cs->bc_hw_ops->read_reg(cs, 0, IPACX_ISTAB);
-  if (ista &0x40) cs->bc_hw_ops->read_reg(cs, 1, IPACX_ISTAB);
-  if (ista &0x10) ipacx_read_reg(cs, IPACX_CIR0);
-  if (ista &0x01) ipacx_read_reg(cs, IPACX_ISTAD); 
-}
-
-static struct bc_l1_ops ipacx_bc_l1_ops = {
-	.fill_fifo = ipacx_bc_fill_fifo,
-	.open      = bch_setstack,
-	.close     = bch_close_state,
-};
+  cs->writeisac(cs, IPACX_MASK, 0xff);
+	cs->writeisac(cs, IPACX_MASKD, 0xff);
+	cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
+	cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
+  
+  ista = cs->readisac(cs, IPACX_ISTA); 
+  if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
+  if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
+  if (ista &0x10) cs->readisac(cs, IPACX_CIR0);
+  if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); 
+}
 
 //----------------------------------------------------------
 // Does chip configuration work
@@ -706,36 +969,36 @@
 init_ipacx(struct IsdnCardState *cs, int part)
 {
 	if (part &1) {  // initialise chip
-		cs->bc_l1_ops = &ipacx_bc_l1_ops;
+//##################################################  
+//	printk(KERN_INFO "init_ipacx(%x)\n", part);
+//##################################################  
 		clear_pending_ints(cs);
 		bch_init(cs, 0);
 		bch_init(cs, 1);
 		dch_init(cs);
 	}
 	if (part &2) {  // reenable all interrupts and start chip
-		cs->bc_hw_ops->write_reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
-		cs->bc_hw_ops->write_reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
-		ipacx_write_reg(cs, IPACX_MASKD, _MASKD_IMASK);
-		ipacx_write_reg(cs, IPACX_MASK, _MASK_IMASK); // global mask register
-
-    // reset HDLC Transmitters/receivers
-		ipacx_write_reg(cs, IPACX_CMDRD, 0x41); 
-		cs->bc_hw_ops->write_reg(cs, 0, IPACX_CMDRB, 0x41);
-		cs->bc_hw_ops->write_reg(cs, 1, IPACX_CMDRB, 0x41);
+		cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
+		cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
+		cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
+		cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
+
+		// reset HDLC Transmitters/receivers
+		cs->writeisac(cs, IPACX_CMDRD, 0x41); 
+		cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
+		cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
 		ph_command(cs, IPACX_CMD_RES);
 	}
 }
 
-int
-ipacx_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipacx_dc_ops,
-	    struct bc_hw_ops *ipacx_bc_ops)
-{
-	u8 val;
-
-	cs->dc_hw_ops = ipacx_dc_ops;
-	cs->bc_hw_ops = ipacx_bc_ops;
-	val = ipacx_read_reg(cs, IPACX_ID) & 0x3f;
-	printk(KERN_INFO "HiSax: IPACX Design Id: %#x\n", val);
-	return 0;
+
+void __devinit
+setup_ipacx(struct IsdnCardState *cs)
+{
+	INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 }
+//----------------- end of file -----------------------
 
--- diff/drivers/isdn/hisax/ipacx.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/ipacx.h	2004-02-18 09:03:59.000000000 +0000
@@ -155,10 +155,8 @@
 #define IPACX_IND_AIL    0xe
 #define IPACX_IND_DC     0xf
 
-extern void init_ipacx(struct IsdnCardState *cs, int part);
-extern void interrupt_ipacx(struct IsdnCardState *cs);
-extern int  ipacx_setup(struct IsdnCardState *cs,
-			struct dc_hw_ops *ipacx_dc_ops,
-			struct bc_hw_ops *ipacx_bc_ops);
+extern void init_ipacx(struct IsdnCardState *, int);
+extern void interrupt_ipacx(struct IsdnCardState *);
+extern void setup_isac(struct IsdnCardState *);
 
 #endif
--- diff/drivers/isdn/hisax/isac.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/isac.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.28.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * ISAC specific routines
  *
@@ -27,30 +27,12 @@
 {"2086/2186 V1.1", "2085 B1", "2085 B2",
  "2085 V2.3"};
 
-static inline u8
-isac_read(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-isac_write(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
-static inline void
-isac_write_fifo(struct IsdnCardState *cs, u8 *p, int len)
-{
-	return cs->dc_hw_ops->write_fifo(cs, p, len);
-}
-
-static void
+void
 ISACVersion(struct IsdnCardState *cs, char *s)
 {
 	int val;
 
-	val = isac_read(cs, ISAC_RBCH);
+	val = cs->readisac(cs, ISAC_RBCH);
 	printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
 }
 
@@ -59,7 +41,7 @@
 {
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "ph_command %x", command);
-	isac_write(cs, ISAC_CIX0, (command << 2) | 3);
+	cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
 }
 
 
@@ -99,9 +81,8 @@
 }
 
 static void
-isac_bh(void *data)
+isac_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
 	struct PStack *stptr;
 	
 	if (!cs)
@@ -111,7 +92,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -134,22 +115,58 @@
 void
 isac_empty_fifo(struct IsdnCardState *cs, int count)
 {
-	recv_empty_fifo_d(cs, count);
-	isac_write(cs, ISAC_CMDR, 0x80);
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "isac_empty_fifo");
+
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "isac_empty_fifo overrun %d",
+				cs->rcvidx + count);
+		cs->writeisac(cs, ISAC_CMDR, 0x80);
+		cs->rcvidx = 0;
+		return;
+	}
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ISAC_CMDR, 0x80);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 static void
 isac_fill_fifo(struct IsdnCardState *cs)
 {
 	int count, more;
-	unsigned char *p;
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "isac_fill_fifo");
+
+	if (!cs->tx_skb)
+		return;
 
-	p = xmit_fill_fifo_d(cs, 32, &count, &more);
-	if (!p)
+	count = cs->tx_skb->len;
+	if (count <= 0)
 		return;
 
-	isac_write_fifo(cs, p, count);
-	isac_write(cs, ISAC_CMDR, more ? 0x8 : 0xa);
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
 	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 		debugl1(cs, "isac_fill_fifo dbusytimer running");
 		del_timer(&cs->dbusytimer);
@@ -157,18 +174,26 @@
 	init_timer(&cs->dbusytimer);
 	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
 	add_timer(&cs->dbusytimer);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 void
-isac_interrupt(struct IsdnCardState *cs, u8 val)
+isac_interrupt(struct IsdnCardState *cs, u_char val)
 {
-	u8 exval, v1;
+	u_char exval, v1;
+	struct sk_buff *skb;
 	unsigned int count;
 
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "ISAC interrupt %x", val);
 	if (val & 0x80) {	/* RME */
-		exval = isac_read(cs, ISAC_RSTA);
+		exval = cs->readisac(cs, ISAC_RSTA);
 		if ((exval & 0x70) != 0x20) {
 			if (exval & 0x40) {
 				if (cs->debug & L1_DEB_WARN)
@@ -184,17 +209,24 @@
 				cs->err_crc++;
 #endif
 			}
-			isac_write(cs, ISAC_CMDR, 0x80);
-			cs->rcvidx = 0;
+			cs->writeisac(cs, ISAC_CMDR, 0x80);
 		} else {
-			count = isac_read(cs, ISAC_RBCL) & 0x1f;
+			count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
 			if (count == 0)
 				count = 32;
 			isac_empty_fifo(cs, count);
- 			recv_rme_d(cs);
+			if ((count = cs->rcvidx) > 0) {
+				cs->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "HiSax: D receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
 		}
 		cs->rcvidx = 0;
-		sched_d_event(cs, D_RCVBUFREADY);
+		schedule_event(cs, D_RCVBUFREADY);
 	}
 	if (val & 0x40) {	/* RPF */
 		isac_empty_fifo(cs, 32);
@@ -205,20 +237,39 @@
 			debugl1(cs, "ISAC RSC interrupt");
 	}
 	if (val & 0x10) {	/* XPR */
-		xmit_xpr_d(cs);
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			schedule_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len) {
+				isac_fill_fifo(cs);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb_irq(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			}
+		}
+		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+			cs->tx_cnt = 0;
+			isac_fill_fifo(cs);
+		} else
+			schedule_event(cs, D_XMTBUFREADY);
 	}
+      afterXPR:
 	if (val & 0x04) {	/* CISQ */
-		exval = isac_read(cs, ISAC_CIR0);
+		exval = cs->readisac(cs, ISAC_CIR0);
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ISAC CIR0 %02X", exval );
 		if (exval & 2) {
 			cs->dc.isac.ph_state = (exval >> 2) & 0xf;
 			if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
-			sched_d_event(cs, D_L1STATECHANGE);
+			schedule_event(cs, D_L1STATECHANGE);
 		}
 		if (exval & 1) {
-			exval = isac_read(cs, ISAC_CIR1);
+			exval = cs->readisac(cs, ISAC_CIR1);
 			if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "ISAC CIR1 %02X", exval );
 		}
@@ -229,7 +280,7 @@
 			debugl1(cs, "ISAC SIN interrupt");
 	}
 	if (val & 0x01) {	/* EXI */
-		exval = isac_read(cs, ISAC_EXIR);
+		exval = cs->readisac(cs, ISAC_EXIR);
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "ISAC EXIR %02x", exval);
 		if (exval & 0x80) {  /* XMR */
@@ -237,10 +288,26 @@
 			printk(KERN_WARNING "HiSax: ISAC XMR\n");
 		}
 		if (exval & 0x40) {  /* XDU */
-			xmit_xdu_d(cs, NULL);
+			debugl1(cs, "ISAC XDU");
+			printk(KERN_WARNING "HiSax: ISAC XDU\n");
+#ifdef ERROR_STATISTIC
+			cs->err_tx++;
+#endif
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				schedule_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) { /* Restart frame */
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+				isac_fill_fifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+				debugl1(cs, "ISAC XDU no skb");
+			}
 		}
 		if (exval & 0x04) {  /* MOS */
-			v1 = isac_read(cs, ISAC_MOSR);
+			v1 = cs->readisac(cs, ISAC_MOSR);
 			if (cs->debug & L1_DEB_MONITOR)
 				debugl1(cs, "ISAC MOSR %02x", v1);
 #if ARCOFI_USE
@@ -251,7 +318,7 @@
 							debugl1(cs, "ISAC MON RX out of memory!");
 						cs->dc.isac.mocr &= 0xf0;
 						cs->dc.isac.mocr |= 0x0a;
-						isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+						cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 						goto afterMONR0;
 					} else
 						cs->dc.isac.mon_rxp = 0;
@@ -259,18 +326,18 @@
 				if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 					cs->dc.isac.mocr &= 0xf0;
 					cs->dc.isac.mocr |= 0x0a;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					cs->dc.isac.mon_rxp = 0;
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "ISAC MON RX overflow!");
 					goto afterMONR0;
 				}
-				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = isac_read(cs, ISAC_MOR0);
+				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
 				if (cs->dc.isac.mon_rxp == 1) {
 					cs->dc.isac.mocr |= 0x04;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 				}
 			}
 		      afterMONR0:
@@ -281,7 +348,7 @@
 							debugl1(cs, "ISAC MON RX out of memory!");
 						cs->dc.isac.mocr &= 0x0f;
 						cs->dc.isac.mocr |= 0xa0;
-						isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+						cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 						goto afterMONR1;
 					} else
 						cs->dc.isac.mon_rxp = 0;
@@ -289,51 +356,51 @@
 				if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 					cs->dc.isac.mocr &= 0x0f;
 					cs->dc.isac.mocr |= 0xa0;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					cs->dc.isac.mon_rxp = 0;
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "ISAC MON RX overflow!");
 					goto afterMONR1;
 				}
-				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = isac_read(cs, ISAC_MOR1);
+				cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
 				cs->dc.isac.mocr |= 0x40;
-				isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 			}
 		      afterMONR1:
 			if (v1 & 0x04) {
 				cs->dc.isac.mocr &= 0xf0;
-				isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 				cs->dc.isac.mocr |= 0x0a;
-				isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
-				sched_d_event(cs, D_RX_MON0);
+				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+				schedule_event(cs, D_RX_MON0);
 			}
 			if (v1 & 0x40) {
 				cs->dc.isac.mocr &= 0x0f;
-				isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 				cs->dc.isac.mocr |= 0xa0;
-				isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
-				sched_d_event(cs, D_RX_MON1);
+				cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+				schedule_event(cs, D_RX_MON1);
 			}
 			if (v1 & 0x02) {
 				if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && 
 					(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && 
 					!(v1 & 0x08))) {
 					cs->dc.isac.mocr &= 0xf0;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					cs->dc.isac.mocr |= 0x0a;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					if (cs->dc.isac.mon_txc &&
 						(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
-						sched_d_event(cs, D_TX_MON0);
+						schedule_event(cs, D_TX_MON0);
 					goto AfterMOX0;
 				}
 				if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
-					sched_d_event(cs, D_TX_MON0);
+					schedule_event(cs, D_TX_MON0);
 					goto AfterMOX0;
 				}
-				isac_write(cs, ISAC_MOX0,
+				cs->writeisac(cs, ISAC_MOX0,
 					cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
@@ -344,19 +411,19 @@
 					(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && 
 					!(v1 & 0x80))) {
 					cs->dc.isac.mocr &= 0x0f;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					cs->dc.isac.mocr |= 0xa0;
-					isac_write(cs, ISAC_MOCR, cs->dc.isac.mocr);
+					cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 					if (cs->dc.isac.mon_txc &&
 						(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
-						sched_d_event(cs, D_TX_MON1);
+						schedule_event(cs, D_TX_MON1);
 					goto AfterMOX1;
 				}
 				if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
-					sched_d_event(cs, D_TX_MON1);
+					schedule_event(cs, D_TX_MON1);
 					goto AfterMOX1;
 				}
-				isac_write(cs, ISAC_MOX1,
+				cs->writeisac(cs, ISAC_MOX1,
 					cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
@@ -372,33 +439,87 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 	int  val;
 
 	switch (pr) {
 		case (PH_DATA |REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				isac_fill_fifo(cs);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+			} else {
+				if (cs->debug & DEB_DLOG_HEX)
+					LogFrame(cs, skb->data, skb->len);
+				if (cs->debug & DEB_DLOG_VERBOSE)
+					dlogframe(cs, skb, 0);
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+				isac_fill_fifo(cs);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
 				(cs->dc.isac.ph_state == ISAC_IND_DR) ||
 				(cs->dc.isac.ph_state == ISAC_IND_RS))
 			        ph_command(cs, ISAC_CMD_TIM);
 			else
 				ph_command(cs, ISAC_CMD_RS);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_ENABLE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, ISAC_CMD_TIM);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, ISAC_CMD_AR8);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_TESTLOOP | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			val = 0;
 			if (1 & (long) arg)
 				val |= 0x0c;
@@ -407,20 +528,21 @@
 			if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 				/* IOM 1 Mode */
 				if (!val) {
-					isac_write(cs, ISAC_SPCR, 0xa);
-					isac_write(cs, ISAC_ADF1, 0x2);
+					cs->writeisac(cs, ISAC_SPCR, 0xa);
+					cs->writeisac(cs, ISAC_ADF1, 0x2);
 				} else {
-					isac_write(cs, ISAC_SPCR, val);
-					isac_write(cs, ISAC_ADF1, 0xa);
+					cs->writeisac(cs, ISAC_SPCR, val);
+					cs->writeisac(cs, ISAC_ADF1, 0xa);
 				}
 			} else {
 				/* IOM 2 Mode */
-				isac_write(cs, ISAC_SPCR, val);
+				cs->writeisac(cs, ISAC_SPCR, val);
 				if (val)
-					isac_write(cs, ISAC_ADF1, 0x8);
+					cs->writeisac(cs, ISAC_ADF1, 0x8);
 				else
-					isac_write(cs, ISAC_ADF1, 0x0);
+					cs->writeisac(cs, ISAC_ADF1, 0x0);
 			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_DEACTIVATE | RESPONSE):
 			skb_queue_purge(&cs->rq);
@@ -432,7 +554,7 @@
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-				sched_d_event(cs, D_CLEARBUSY);
+				schedule_event(cs, D_CLEARBUSY);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -441,14 +563,13 @@
 	}
 }
 
-static int
+void
 setstack_isac(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = ISAC_l1hw;
-	return 0;
 }
 
-static void 
+void 
 DC_Close_isac(struct IsdnCardState *cs) {
 	if (cs->dc.isac.mon_rx) {
 		kfree(cs->dc.isac.mon_rx);
@@ -467,8 +588,8 @@
 	int	rbch, star;
 
 	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
-		rbch = isac_read(cs, ISAC_RBCH);
-		star = isac_read(cs, ISAC_STAR);
+		rbch = cs->readisac(cs, ISAC_RBCH);
+		star = cs->readisac(cs, ISAC_STAR);
 		if (cs->debug) 
 			debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
 				rbch, star);
@@ -476,7 +597,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
@@ -490,80 +611,74 @@
 				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 				debugl1(cs, "D-Channel Busy no skb");
 			}
-			isac_write(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
-			cs->card_ops->irq_func(cs->irq, cs, NULL);
+			cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
+			cs->irq_func(cs->irq, cs, NULL);
 		}
 	}
 }
 
-static struct dc_l1_ops isac_l1_ops = {
-	.fill_fifo  = isac_fill_fifo,
-	.open       = setstack_isac,
-	.close      = DC_Close_isac,
-	.bh_func    = isac_bh,
-	.dbusy_func = dbusy_timer_handler,
-};
-
 void __devinit
 initisac(struct IsdnCardState *cs)
 {
-	int val, eval;
-
-	dc_l1_init(cs, &isac_l1_ops);
-
-	val = isac_read(cs, ISAC_STAR);
-	debugl1(cs, "ISAC STAR %x", val);
-	val = isac_read(cs, ISAC_MODE);
-	debugl1(cs, "ISAC MODE %x", val);
-	val = isac_read(cs, ISAC_ADF2);
-	debugl1(cs, "ISAC ADF2 %x", val);
-	val = isac_read(cs, ISAC_ISTA);
-	debugl1(cs, "ISAC ISTA %x", val);
-	if (val & 0x01) {
-		eval = isac_read(cs, ISAC_EXIR);
-		debugl1(cs, "ISAC EXIR %x", eval);
-	}
-	/* Disable all IRQ */
-	isac_write(cs, ISAC_MASK, 0xFF);
-
+	cs->setstack_d = setstack_isac;
+	cs->DC_Close = DC_Close_isac;
 	cs->dc.isac.mon_tx = NULL;
 	cs->dc.isac.mon_rx = NULL;
+  	cs->writeisac(cs, ISAC_MASK, 0xff);
   	cs->dc.isac.mocr = 0xaa;
 	if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 		/* IOM 1 Mode */
-		isac_write(cs, ISAC_ADF2, 0x0);
-		isac_write(cs, ISAC_SPCR, 0xa);
-		isac_write(cs, ISAC_ADF1, 0x2);
-		isac_write(cs, ISAC_STCR, 0x70);
-		isac_write(cs, ISAC_MODE, 0xc9);
+		cs->writeisac(cs, ISAC_ADF2, 0x0);
+		cs->writeisac(cs, ISAC_SPCR, 0xa);
+		cs->writeisac(cs, ISAC_ADF1, 0x2);
+		cs->writeisac(cs, ISAC_STCR, 0x70);
+		cs->writeisac(cs, ISAC_MODE, 0xc9);
 	} else {
 		/* IOM 2 Mode */
 		if (!cs->dc.isac.adf2)
 			cs->dc.isac.adf2 = 0x80;
-		isac_write(cs, ISAC_ADF2, cs->dc.isac.adf2);
-		isac_write(cs, ISAC_SQXR, 0x2f);
-		isac_write(cs, ISAC_SPCR, 0x00);
-		isac_write(cs, ISAC_STCR, 0x70);
-		isac_write(cs, ISAC_MODE, 0xc9);
-		isac_write(cs, ISAC_TIMR, 0x00);
-		isac_write(cs, ISAC_ADF1, 0x00);
+		cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
+		cs->writeisac(cs, ISAC_SQXR, 0x2f);
+		cs->writeisac(cs, ISAC_SPCR, 0x00);
+		cs->writeisac(cs, ISAC_STCR, 0x70);
+		cs->writeisac(cs, ISAC_MODE, 0xc9);
+		cs->writeisac(cs, ISAC_TIMR, 0x00);
+		cs->writeisac(cs, ISAC_ADF1, 0x00);
 	}
 	ph_command(cs, ISAC_CMD_RS);
-	isac_write(cs, ISAC_MASK, 0x0);
+	cs->writeisac(cs, ISAC_MASK, 0x0);
+}
 
-	val = isac_read(cs, ISAC_CIR0);
+void __devinit
+clear_pending_isac_ints(struct IsdnCardState *cs)
+{
+	int val, eval;
+
+	val = cs->readisac(cs, ISAC_STAR);
+	debugl1(cs, "ISAC STAR %x", val);
+	val = cs->readisac(cs, ISAC_MODE);
+	debugl1(cs, "ISAC MODE %x", val);
+	val = cs->readisac(cs, ISAC_ADF2);
+	debugl1(cs, "ISAC ADF2 %x", val);
+	val = cs->readisac(cs, ISAC_ISTA);
+	debugl1(cs, "ISAC ISTA %x", val);
+	if (val & 0x01) {
+		eval = cs->readisac(cs, ISAC_EXIR);
+		debugl1(cs, "ISAC EXIR %x", eval);
+	}
+	val = cs->readisac(cs, ISAC_CIR0);
 	debugl1(cs, "ISAC CIR0 %x", val);
 	cs->dc.isac.ph_state = (val >> 2) & 0xf;
-	sched_d_event(cs, D_L1STATECHANGE);
-
-	/* RESET Receiver and Transmitter */
-	isac_write(cs, ISAC_CMDR, 0x41);
+	schedule_event(cs, D_L1STATECHANGE);
+	/* Disable all IRQ */
+	cs->writeisac(cs, ISAC_MASK, 0xFF);
 }
 
-int
-isac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops)
+void __devinit
+setup_isac(struct IsdnCardState *cs)
 {
-	cs->dc_hw_ops = isac_ops;
-	ISACVersion(cs, "HiSax:");
-	return 0;
+	INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs);
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
 }
--- diff/drivers/isdn/hisax/isac.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/isac.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isac.h,v 1.7.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $
  *
  * ISAC specific defines
  *
@@ -63,6 +63,8 @@
 #define ISAC_IND_AI10	0xD
 #define ISAC_IND_DID	0xF
 
-extern void initisac(struct IsdnCardState *cs);
-extern void isac_interrupt(struct IsdnCardState *cs, u8 val);
-extern int  isac_setup(struct IsdnCardState *cs, struct dc_hw_ops *isac_ops);
+extern void ISACVersion(struct IsdnCardState *, char *);
+extern void setup_isac(struct IsdnCardState *);
+extern void initisac(struct IsdnCardState *);
+extern void isac_interrupt(struct IsdnCardState *, u_char);
+extern void clear_pending_isac_ints(struct IsdnCardState *);
--- diff/drivers/isdn/hisax/isar.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/isdn/hisax/isar.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.17.6.5 2001/09/23 11:51:33 keil Exp $
+/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $
  *
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -20,33 +20,22 @@
 #define DLE	0x10
 #define ETX	0x03
 
-
-const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; 
-const u8 faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; 
-#define FAXMODCNT 13
-
-static void __isar_setup(struct IsdnCardState *cs);
-static void isar_pump_cmd(struct BCState *bcs, u8 cmd, u8 para);
-static inline void ll_deliver_faxstat(struct BCState *bcs, u8 status);
-static spinlock_t isar_lock = SPIN_LOCK_UNLOCKED;
-
-static inline u8
-isar_read_reg(struct IsdnCardState *cs, int mode, u8 addr)
-{
-	return cs->bc_hw_ops->read_reg(cs, mode, addr);
-}
-
-static inline void
-isar_write_reg(struct IsdnCardState *cs, int mode, u8 addr, u8 val)
-{
-	cs->bc_hw_ops->write_reg(cs, mode, addr, val);
-}
+#define FAXMODCNT	13
+const	u_char	faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+static	u_int	modmask = 0x1fff;
+static	int	frm_extra_delay = 2;
+static	int	para_TOA = 6;
+const   u_char  *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
+
+void isar_setup(struct IsdnCardState *cs);
+static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
+static void ll_deliver_faxstat(struct BCState *bcs, u_char status);
 
 static inline int
 waitforHIA(struct IsdnCardState *cs, int timeout)
 {
 
-	while ((isar_read_reg(cs, 0, ISAR_HIA) & 1) && timeout) {
+	while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) {
 		udelay(1);
 		timeout--;
 	}
@@ -57,10 +46,9 @@
 
 
 int
-sendmsg(struct IsdnCardState *cs, u8 his, u8 creg, u8 len,
-	u8 *msg)
+sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
+	u_char *msg)
 {
-	unsigned long flags;
 	int i;
 	
 	if (!waitforHIA(cs, 4000))
@@ -69,14 +57,13 @@
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);
 #endif
-	spin_lock_irqsave(&isar_lock, flags);
-	isar_write_reg(cs, 0, ISAR_CTRL_H, creg);
-	isar_write_reg(cs, 0, ISAR_CTRL_L, len);
-	isar_write_reg(cs, 0, ISAR_WADR, 0);
+	cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg);
+	cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len);
+	cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0);
 	if (msg && len) {
-		isar_write_reg(cs, 1, ISAR_MBOX, msg[0]);
+		cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]);
 		for (i=1; i<len; i++)
-			isar_write_reg(cs, 2, ISAR_MBOX, msg[i]);
+			cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]);
 #if DUMP_MBOXFRAME>1
 		if (cs->debug & L1_DEB_HSCX_FIFO) {
 			char tmp[256], *t;
@@ -92,23 +79,22 @@
 		}
 #endif
 	}
-	isar_write_reg(cs, 1, ISAR_HIS, his);
-	spin_unlock_irqrestore(&isar_lock, flags);
+	cs->BC_Write_Reg(cs, 1, ISAR_HIS, his);
 	waitforHIA(cs, 10000);
 	return(1);
 }
 
 /* Call only with IRQ disabled !!! */
 inline void
-rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u8 *msg)
+rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
 {
 	int i;
 
-	isar_write_reg(cs, 1, ISAR_RADR, 0);
+	cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0);
 	if (msg && ireg->clsb) {
-		msg[0] = isar_read_reg(cs, 1, ISAR_MBOX);
+		msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX);
 		for (i=1; i < ireg->clsb; i++)
-			 msg[i] = isar_read_reg(cs, 2, ISAR_MBOX);
+			 msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX);
 #if DUMP_MBOXFRAME>1
 		if (cs->debug & L1_DEB_HSCX_FIFO) {
 			char tmp[256], *t;
@@ -124,85 +110,90 @@
 		}
 #endif
 	}
-	isar_write_reg(cs, 1, ISAR_IIA, 0);
+	cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 }
 
 /* Call only with IRQ disabled !!! */
 inline void
 get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
 {
-	ireg->iis = isar_read_reg(cs, 1, ISAR_IIS);
-	ireg->cmsb = isar_read_reg(cs, 1, ISAR_CTRL_H);
-	ireg->clsb = isar_read_reg(cs, 1, ISAR_CTRL_L);
+	ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
+	ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H);
+	ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
 #if DUMP_MBOXFRAME
 	if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+		debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
 			ireg->clsb);
 #endif
 }
 
 int
-waitrecmsg(struct IsdnCardState *cs, u8 *len,
-	u8 *msg, int maxdelay)
+waitrecmsg(struct IsdnCardState *cs, u_char *len,
+	u_char *msg, int maxdelay)
 {
 	int timeout = 0;
-	unsigned long flags;
 	struct isar_reg *ir = cs->bcs[0].hw.isar.reg;
 	
 	
-	while((!(isar_read_reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
+	while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
 		(timeout++ < maxdelay))
 		udelay(1);
 	if (timeout >= maxdelay) {
 		printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
 		return(0);
 	}
-	spin_lock_irqsave(&isar_lock, flags);
 	get_irq_infos(cs, ir);
 	rcv_mbox(cs, ir, msg);
 	*len = ir->clsb;
-	spin_unlock_irqrestore(&isar_lock, flags);
 	return(1);
 }
 
-static int
+int
 ISARVersion(struct IsdnCardState *cs, char *s)
 {
 	int ver;
-	u8 msg[] = ISAR_MSG_HWVER;
-	u8 tmp[64];
-	u8 len;
+	u_char msg[] = ISAR_MSG_HWVER;
+	u_char tmp[64];
+	u_char len;
+	u_long flags;
 	int debug;
 
-	cs->card_ops->reset(cs);
+	cs->cardmsg(cs, CARD_RESET,  NULL);
+	spin_lock_irqsave(&cs->lock, flags);
 	/* disable ISAR IRQ */
-	isar_write_reg(cs, 0, ISAR_IRQBIT, 0);
+	cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
 	debug = cs->debug;
 	cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
-	if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg))
+	if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) {
+		spin_unlock_irqrestore(&cs->lock, flags);
 		return(-1);
-	if (!waitrecmsg(cs, &len, tmp, 100000))
-		 return(-2);
+	}
+	if (!waitrecmsg(cs, &len, tmp, 100000)) {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return(-2);
+	}
 	cs->debug = debug;
 	if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) {
 		if (len == 1) {
 			ver = tmp[0] & 0xf;
 			printk(KERN_INFO "%s ISAR version %d\n", s, ver);
-			return(ver);
-		}
-		return(-3);
-	}
-	return(-4);
+		} else
+			ver = -3;
+	} else
+		ver = -4;
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return(ver);
 }
 
 int
-isar_load_firmware(struct IsdnCardState *cs, u8 *buf)
+isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
 {
 	int ret, size, cnt, debug;
-	u8 len, nom, noc;
+	u_char len, nom, noc;
 	u_short sadr, left, *sp;
-	u8 *p = buf;
-	u8 *msg, *tmpmsg, *mp, tmp[64];
+	u_char *p = buf;
+	u_char *msg, *tmpmsg, *mp, tmp[64];
+	u_long flags;
 	struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
 	
 	struct {u_short sadr;
@@ -219,16 +210,16 @@
 #if DBG_LOADFIRM<2
 	cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
 #endif
-	printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf);
+	
 	if ((ret = copy_from_user(&size, p, sizeof(int)))) {
 		printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
-		return -EFAULT;
+		return ret;
 	}
 	p += sizeof(int);
 	printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
 	cnt = 0;
 	/* disable ISAR IRQ */
-	isar_write_reg(cs, 0, ISAR_IRQBIT, 0);
+	cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
 	if (!(msg = kmalloc(256, GFP_KERNEL))) {
 		printk(KERN_ERR"isar_load_firmware no buffer\n");
 		return (1);
@@ -238,10 +229,13 @@
 		kfree(msg);
 		return (1);
 	}
+	spin_lock_irqsave(&cs->lock, flags);
+	/* disable ISAR IRQ */
+	cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	while (cnt < size) {
 		if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) {
 			printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
-			ret = -EFAULT;
 			goto reterror;
 		}
 #ifdef __BIG_ENDIAN
@@ -258,19 +252,21 @@
 			blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
 		sadr = blk_head.sadr;
 		left = blk_head.len;
+		spin_lock_irqsave(&cs->lock, flags);
 		if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) {
 			printk(KERN_ERR"isar sendmsg dkey failed\n");
-			ret = 1;goto reterror;
+			ret = 1;goto reterr_unlock;
 		}
 		if (!waitrecmsg(cs, &len, tmp, 100000)) {
 			printk(KERN_ERR"isar waitrecmsg dkey failed\n");
-			ret = 1;goto reterror;
+			ret = 1;goto reterr_unlock;
 		}
 		if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) {
 			printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n",
 				ireg->iis, ireg->cmsb, len);
-			ret = 1;goto reterror;
+			ret = 1;goto reterr_unlock;
 		}
+		spin_unlock_irqrestore(&cs->lock, flags);
 		while (left>0) {
 			if (left > 126)
 				noc = 126;
@@ -284,7 +280,6 @@
 			*mp++ = noc;
 			if ((ret = copy_from_user(tmpmsg, p, nom))) {
 				printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
-				ret = -EFAULT;
 				goto reterror;
 			}
 			p += nom;
@@ -307,19 +302,21 @@
 				sp++;
 				noc--;
 			}
+			spin_lock_irqsave(&cs->lock, flags);
 			if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) {
 				printk(KERN_ERR"isar sendmsg prog failed\n");
-				ret = 1;goto reterror;
+				ret = 1;goto reterr_unlock;
 			}
 			if (!waitrecmsg(cs, &len, tmp, 100000)) {
 				printk(KERN_ERR"isar waitrecmsg prog failed\n");
-				ret = 1;goto reterror;
+				ret = 1;goto reterr_unlock;
 			}
 			if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) {
 				printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n",
 					ireg->iis, ireg->cmsb, len);
-				ret = 1;goto reterror;
+				ret = 1;goto reterr_unlock;
 			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 		}
 		printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
 			blk_head.len);
@@ -331,23 +328,25 @@
 	msg[0] = 0xff;
 	msg[1] = 0xfe;
 	ireg->bstat = 0;
+	spin_lock_irqsave(&cs->lock, flags);
 	if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) {
 		printk(KERN_ERR"isar sendmsg start dsp failed\n");
-		ret = 1;goto reterror;
+		ret = 1;goto reterr_unlock;
 	}
 	if (!waitrecmsg(cs, &len, tmp, 100000)) {
 		printk(KERN_ERR"isar waitrecmsg start dsp failed\n");
-		ret = 1;goto reterror;
+		ret = 1;goto reterr_unlock;
 	}
 	if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) {
 		printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n",
 			ireg->iis, ireg->cmsb, len);
-		ret = 1;goto reterror;
+		ret = 1;goto reterr_unlock;
 	} else
 		printk(KERN_DEBUG"isar start dsp success\n");
 	/* NORMAL mode entered */
 	/* Enable IRQs of ISAR */
-	isar_write_reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
+	cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	cnt = 1000; /* max 1s */
 	while ((!ireg->bstat) && cnt) {
 		udelay(1000);
@@ -364,12 +363,14 @@
 	cnt = 10;
 	while (cnt--)
 		udelay(1000);
+	spin_lock_irqsave(&cs->lock, flags);
 	ireg->iis = 0;
 	if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
 		printk(KERN_ERR"isar sendmsg self tst failed\n");
-		ret = 1;goto reterror;
+		ret = 1;goto reterr_unlock;
 	}
 	cnt = 10000; /* max 100 ms */
+	spin_unlock_irqrestore(&cs->lock, flags);
 	while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
 		udelay(10);
 		cnt--;
@@ -387,11 +388,13 @@
 			ireg->cmsb, ireg->clsb, ireg->par[0]);
 		ret = 1;goto reterror;
 	}
+	spin_lock_irqsave(&cs->lock, flags);
 	ireg->iis = 0;
 	if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
 		printk(KERN_ERR"isar RQST SVN failed\n");
-		ret = 1;goto reterror;
+		ret = 1;goto reterr_unlock;
 	}
+	spin_unlock_irqrestore(&cs->lock, flags);
 	cnt = 30000; /* max 300 ms */
 	while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
 		udelay(10);
@@ -411,26 +414,31 @@
 			ret = 1;goto reterror;
 		}
 	}
+	spin_lock_irqsave(&cs->lock, flags);
 	cs->debug = debug;
-	__isar_setup(cs);
+	isar_setup(cs);
+
 	ret = 0;
+reterr_unlock:
+	spin_unlock_irqrestore(&cs->lock, flags);
 reterror:
 	cs->debug = debug;
 	if (ret)
 		/* disable ISAR IRQ */
-		isar_write_reg(cs, 0, ISAR_IRQBIT, 0);
+		cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
 	kfree(msg);
 	kfree(tmpmsg);
 	return(ret);
 }
 
 extern void BChannel_bh(struct BCState *);
+#define B_LL_NOCARRIER	8
+#define B_LL_CONNECT	9
+#define B_LL_OK		10
 
 static void
-isar_bh(void *data)
+isar_bh(struct BCState *bcs)
 {
-	struct BCState *bcs = data;
-
 	BChannel_bh(bcs);
 	if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
 		ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
@@ -440,16 +448,16 @@
 		ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
 }
 
-static inline void
+static void
 send_DLE_ETX(struct BCState *bcs)
 {
-	u8 dleetx[2] = {DLE,ETX};
+	u_char dleetx[2] = {DLE,ETX};
 	struct sk_buff *skb;
 	
 	if ((skb = dev_alloc_skb(2))) {
 		memcpy(skb_put(skb, 2), dleetx, 2);
 		skb_queue_tail(&bcs->rqueue, skb);
-		sched_b_event(bcs, B_RCVBUFREADY);
+		schedule_event(bcs, B_RCVBUFREADY);
 	} else {
 		printk(KERN_WARNING "HiSax: skb out of memory\n");
 	}
@@ -476,16 +484,16 @@
 	}
 }
  
-static inline void
+static void
 isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	u8 *ptr;
+	u_char *ptr;
 	struct sk_buff *skb;
 	struct isar_reg *ireg = bcs->hw.isar.reg;
 	
 	if (!ireg->clsb) {
 		debugl1(cs, "isar zero len frame");
-		isar_write_reg(cs, 1, ISAR_IIA, 0);
+		cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		return;
 	}
 	switch (bcs->mode) {
@@ -494,24 +502,24 @@
 			ireg->iis, ireg->cmsb, ireg->clsb);
 		printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n",
 			ireg->iis, ireg->cmsb, ireg->clsb);
-		isar_write_reg(cs, 1, ISAR_IIA, 0);
+		cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		break;
 	case L1_MODE_TRANS:
 	case L1_MODE_V32:
 		if ((skb = dev_alloc_skb(ireg->clsb))) {
-			rcv_mbox(cs, ireg, (u8 *)skb_put(skb, ireg->clsb));
+			rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb));
 			skb_queue_tail(&bcs->rqueue, skb);
-			sched_b_event(bcs, B_RCVBUFREADY);
+			schedule_event(bcs, B_RCVBUFREADY);
 		} else {
 			printk(KERN_WARNING "HiSax: skb out of memory\n");
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		}
 		break;
 	case L1_MODE_HDLC:
 		if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: incoming packet too large");
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
 		} else if (ireg->cmsb & HDLC_ERROR) {
 			if (cs->debug & L1_DEB_WARN)
@@ -524,7 +532,7 @@
 				bcs->err_crc++;
 #endif
 			bcs->hw.isar.rcvidx = 0;
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		} else {
 			if (ireg->cmsb & HDLC_FSD)
 				bcs->hw.isar.rcvidx = 0;
@@ -542,7 +550,7 @@
 					memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2),
 						bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2);
 					skb_queue_tail(&bcs->rqueue, skb);
-					sched_b_event(bcs, B_RCVBUFREADY);
+					schedule_event(bcs, B_RCVBUFREADY);
 				}
 				bcs->hw.isar.rcvidx = 0;
 			}
@@ -552,7 +560,7 @@
 		if (bcs->hw.isar.state != STFAX_ACTIV) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: not ACTIV");
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
 			break;
 		}
@@ -564,25 +572,23 @@
 				debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
 					ireg->clsb, bcs->hw.isar.rcvidx);
 			if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
-				insert_dle((u8 *)skb_put(skb, bcs->hw.isar.rcvidx),
+				insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
 					bcs->hw.isar.rcvbuf, ireg->clsb);
 				skb_queue_tail(&bcs->rqueue, skb);
-				sched_b_event(bcs, B_RCVBUFREADY);
+				schedule_event(bcs, B_RCVBUFREADY);
 				if (ireg->cmsb & SART_NMD) { /* ABORT */
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar_rcv_frame: no more data");
-					isar_write_reg(cs, 1, ISAR_IIA, 0);
 					bcs->hw.isar.rcvidx = 0;
 					send_DLE_ETX(bcs);
 					sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
 						ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
 						0, NULL);
 					bcs->hw.isar.state = STFAX_ESCAPE;
-					sched_b_event(bcs, B_LL_NOCARRIER);
+					schedule_event(bcs, B_LL_NOCARRIER);
 				}
 			} else {
 				printk(KERN_WARNING "HiSax: skb out of memory\n");
-				isar_write_reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		}
@@ -590,7 +596,7 @@
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
 					bcs->hw.isar.cmd);
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
 			break;
 		}
@@ -598,17 +604,18 @@
 		if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: incoming packet too large");
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
 		} else if (ireg->cmsb & HDLC_ERROR) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar frame error %x len %d",
 					ireg->cmsb, ireg->clsb);
 			bcs->hw.isar.rcvidx = 0;
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		} else {
-			if (ireg->cmsb & HDLC_FSD)
+			if (ireg->cmsb & HDLC_FSD) {
 				bcs->hw.isar.rcvidx = 0;
+			}
 			ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
 			bcs->hw.isar.rcvidx += ireg->clsb;
 			rcv_mbox(cs, ireg, ptr);
@@ -619,16 +626,19 @@
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar frame to short %d",
 							bcs->hw.isar.rcvidx);
-				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+					printk(KERN_WARNING "ISAR: frame to short %d\n",
+						bcs->hw.isar.rcvidx);
+				} else if (!(skb = dev_alloc_skb(len))) {
 					printk(KERN_WARNING "ISAR: receive out of memory\n");
 				} else {
-					insert_dle((u8 *)skb_put(skb, len),
+					insert_dle((u_char *)skb_put(skb, len),
 						bcs->hw.isar.rcvbuf,
 						bcs->hw.isar.rcvidx);
 					skb_queue_tail(&bcs->rqueue, skb);
-					sched_b_event(bcs, B_RCVBUFREADY);
+					schedule_event(bcs, B_RCVBUFREADY);
 					send_DLE_ETX(bcs);
-					sched_b_event(bcs, B_LL_OK);
+					schedule_event(bcs, B_LL_OK);
+					test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 				}
 				bcs->hw.isar.rcvidx = 0;
 			}
@@ -636,18 +646,19 @@
 		if (ireg->cmsb & SART_NMD) { /* ABORT */
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: no more data");
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
-			send_DLE_ETX(bcs);
 			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
 				ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
 			bcs->hw.isar.state = STFAX_ESCAPE;
-			sched_b_event(bcs, B_LL_NOCARRIER);
+			if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
+				send_DLE_ETX(bcs);
+				schedule_event(bcs, B_LL_NOCARRIER);
+			}
 		}
 		break;
 	default:
 		printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
-		isar_write_reg(cs, 1, ISAR_IIA, 0);
+		cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		break;
 	}
 }
@@ -657,8 +668,8 @@
 {
 	struct IsdnCardState *cs = bcs->cs;
 	int count;
-	u8 msb;
-	u8 *ptr;
+	u_char msb;
+	u_char *ptr;
 
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "isar_fill_fifo");
@@ -669,7 +680,7 @@
 	if (!(bcs->hw.isar.reg->bstat & 
 		(bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
 		return;
-	if (bcs->tx_skb->len > (u_int)bcs->hw.isar.mml) {
+	if (bcs->tx_skb->len > bcs->hw.isar.mml) {
 		msb = 0;
 		count = bcs->hw.isar.mml;
 	} else {
@@ -677,7 +688,7 @@
 		msb = HDLC_FED;
 	}
 	ptr = bcs->tx_skb->data;
-	if (!bcs->count) {
+	if (!bcs->hw.isar.txcnt) {
 		msb |= HDLC_FST;
 		if ((bcs->mode == L1_MODE_FAX) &&
 			(bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
@@ -691,7 +702,7 @@
 	}
 	skb_pull(bcs->tx_skb, count);
 	bcs->tx_cnt -= count;
-	bcs->count += count;
+	bcs->hw.isar.txcnt += count;
 	switch (bcs->mode) {
 		case L1_MODE_NULL:
 			printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
@@ -729,7 +740,7 @@
 }
 
 inline
-struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u8 dpath)
+struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
 {
 	if ((!dpath) || (dpath == 3))
 		return(NULL);
@@ -740,7 +751,7 @@
 	return(NULL);
 }
 
-inline void
+void
 send_frames(struct BCState *bcs)
 {
 	if (bcs->tx_skb) {
@@ -748,7 +759,14 @@
 			isar_fill_fifo(bcs);
 			return;
 		} else {
-			xmit_complete_b(bcs);
+			if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+				(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+				u_long	flags;
+				spin_lock_irqsave(&bcs->aclock, flags);
+				bcs->ackcnt += bcs->hw.isar.txcnt;
+				spin_unlock_irqrestore(&bcs->aclock, flags);
+				schedule_event(bcs, B_ACKPENDING);
+			}
 			if (bcs->mode == L1_MODE_FAX) {
 				if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
 					if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
@@ -761,33 +779,35 @@
 					}
 				}
 			}
-			bcs->count = 0; 
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->hw.isar.txcnt = 0; 
+			bcs->tx_skb = NULL;
 		}
 	}
 	if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
-		bcs->count = 0;
+		bcs->hw.isar.txcnt = 0;
 		test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
 		isar_fill_fifo(bcs);
 	} else {
 		if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
 			if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
 				if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
-					u8 dummy = 0;
+					u_char dummy = 0;
 					sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
 						ISAR_HIS_SDATA, 0x01, 1, &dummy);
 				}
 				test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
 			} else {
-				sched_b_event(bcs, B_LL_CONNECT);
+				schedule_event(bcs, B_LL_CONNECT);
 			}
 		}
 		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-		sched_b_event(bcs, B_XMTBUFREADY);
+		schedule_event(bcs, B_XMTBUFREADY);
 	}
 }
 
 inline void
-check_send(struct IsdnCardState *cs, u8 rdm)
+check_send(struct IsdnCardState *cs, u_char rdm)
 {
 	struct BCState *bcs;
 	
@@ -817,8 +837,8 @@
 static void
 isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 ril = ireg->par[0];
-	u8 rim;
+	u_char ril = ireg->par[0];
+	u_char rim;
 
 	if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags))
 		return; 
@@ -869,9 +889,9 @@
 }
 
 static void
-isar_pump_statev_modem(struct BCState *bcs, u8 devt) {
+isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
 
 	switch(devt) {
 		case PSEV_10MS_TIMER:
@@ -938,8 +958,8 @@
 	}
 }
 
-static inline void
-ll_deliver_faxstat(struct BCState *bcs, u8 status)
+static void
+ll_deliver_faxstat(struct BCState *bcs, u_char status)
 {
         isdn_ctrl ic;
 	struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
@@ -954,10 +974,10 @@
 }
 
 static void
-isar_pump_statev_fax(struct BCState *bcs, u8 devt) {
+isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
-	u8 p1;
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char p1;
 
 	switch(devt) {
 		case PSEV_10MS_TIMER:
@@ -1041,7 +1061,7 @@
 						&bcs->Flag);
 					add_timer(&bcs->hw.isar.ftimer);
 				} else {
-					sched_b_event(bcs, B_LL_CONNECT);
+					schedule_event(bcs, B_LL_CONNECT);
 				}
 			} else {
 				if (cs->debug & L1_DEB_WARN)
@@ -1057,19 +1077,22 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_DISC");
 			if (bcs->hw.isar.state == STFAX_ESCAPE) {
+				p1 = 5;
 				switch(bcs->hw.isar.newcmd) {
 					case 0:
 						bcs->hw.isar.state = STFAX_READY;
 						break;
-					case PCTRL_CMD_FTH:
 					case PCTRL_CMD_FTM:
-						p1 = 10;
+						p1 = 2;
+					case PCTRL_CMD_FTH:
 						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 							PCTRL_CMD_SILON, 1, &p1);
 						bcs->hw.isar.state = STFAX_SILDET;
 						break;
-					case PCTRL_CMD_FRH:
 					case PCTRL_CMD_FRM:
+						if (frm_extra_delay)
+							mdelay(frm_extra_delay);
+					case PCTRL_CMD_FRH:
 						p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 						bcs->hw.isar.newmod = 0;
 						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
@@ -1086,10 +1109,10 @@
 				}
 			} else if (bcs->hw.isar.state == STFAX_ACTIV) {
 				if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
-					sched_b_event(bcs, B_LL_OK);
+					schedule_event(bcs, B_LL_OK);
 				} else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
 					send_DLE_ETX(bcs);
-					sched_b_event(bcs, B_LL_NOCARRIER);
+					schedule_event(bcs, B_LL_NOCARRIER);
 				} else {
 					ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
 				}
@@ -1156,11 +1179,11 @@
 			} else {
 				debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				isar_write_reg(cs, 1, ISAR_IIA, 0);
+				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		case ISAR_IIS_GSTEV:
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			ireg->bstat |= ireg->cmsb;
 			check_send(cs, ireg->cmsb);
 			break;
@@ -1176,15 +1199,18 @@
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "Buffer STEV dpath%d msb(%x)",
 					ireg->iis>>6, ireg->cmsb);
-			isar_write_reg(cs, 1, ISAR_IIA, 0);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			break;
 		case ISAR_IIS_PSTEV:
 			if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
-				rcv_mbox(cs, ireg, (u8 *)ireg->par);
+				rcv_mbox(cs, ireg, (u_char *)ireg->par);
 				if (bcs->mode == L1_MODE_V32) {
 					isar_pump_statev_modem(bcs, ireg->cmsb);
 				} else if (bcs->mode == L1_MODE_FAX) {
 					isar_pump_statev_fax(bcs, ireg->cmsb);
+				} else if (ireg->cmsb == PSEV_10MS_TIMER) {
+					if (cs->debug & L1_DEB_HSCX)
+						debugl1(cs, "pump stev TIMER");
 				} else {
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
@@ -1193,30 +1219,30 @@
 			} else {
 				debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				isar_write_reg(cs, 1, ISAR_IIA, 0);
+				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		case ISAR_IIS_PSTRSP:
 			if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
-				rcv_mbox(cs, ireg, (u8 *)ireg->par);
+				rcv_mbox(cs, ireg, (u_char *)ireg->par);
 				isar_pump_status_rsp(bcs, ireg);
 			} else {
 				debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				isar_write_reg(cs, 1, ISAR_IIA, 0);
+				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		case ISAR_IIS_DIAG:
 		case ISAR_IIS_BSTRSP:
 		case ISAR_IIS_IOM2RSP:
-			rcv_mbox(cs, ireg, (u8 *)ireg->par);
+			rcv_mbox(cs, ireg, (u_char *)ireg->par);
 			if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO))
 				== L1_DEB_HSCX) {
-				u8 *tp=debbuf;
+				u_char *tp=debbuf;
 
 				tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
 					ireg->iis, ireg->cmsb);
-				QuickHex(tp, (u8 *)ireg->par, ireg->clsb);
+				QuickHex(tp, (u_char *)ireg->par, ireg->clsb);
 				debugl1(cs, debbuf);
 			}
 			break;
@@ -1242,15 +1268,18 @@
 			bcs->Flag);
 	test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
 	if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
-		sched_b_event(bcs, B_LL_CONNECT);
+		schedule_event(bcs, B_LL_CONNECT);
+	}
+	if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
+		schedule_event(bcs, B_LL_OK);
 	}
 }
 
 static void
 setup_pump(struct BCState *bcs) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
-	u8 ctrl, param[6];
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char ctrl, param[6];
 
 	switch (bcs->mode) {
 		case L1_MODE_NULL:
@@ -1266,7 +1295,7 @@
 			} else {
 				param[5] = PV32P6_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
 				   PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 
 			param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
@@ -1282,7 +1311,7 @@
 			} else {
 				param[1] = PFAXP2_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
 			bcs->hw.isar.state = STFAX_NULL;
 			bcs->hw.isar.newcmd = 0;
@@ -1298,8 +1327,8 @@
 static void
 setup_sart(struct BCState *bcs) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
-	u8 ctrl, param[2];
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char ctrl, param[2];
 	
 	switch (bcs->mode) {
 		case L1_MODE_NULL:
@@ -1311,7 +1340,6 @@
 				"\0\0");
 			break;
 		case L1_MODE_HDLC:
-		case L1_MODE_FAX:
 			param[0] = 0;
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
 				param);
@@ -1323,6 +1351,9 @@
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
 				param);
 			break;
+		case L1_MODE_FAX:
+			/* SART must not configured with FAX */
+			break;
 	}
 	udelay(1000);
 	sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
@@ -1332,8 +1363,8 @@
 static void
 setup_iom2(struct BCState *bcs) {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
-	u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0};
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0};
 	
 	if (bcs->channel)
 		msg[1] = msg[3] = 1;
@@ -1418,14 +1449,15 @@
 }
 
 static void
-isar_pump_cmd(struct BCState *bcs, u8 cmd, u8 para) 
+isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) 
 {
 	struct IsdnCardState *cs = bcs->cs;
-	u8 dps = SET_DPS(bcs->hw.isar.dpath);
-	u8 ctrl = 0, nom = 0, p1 = 0;
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char ctrl = 0, nom = 0, p1 = 0;
 
 	switch(cmd) {
 		case ISDN_FAX_CLASS1_FTM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTM;
@@ -1449,6 +1481,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FTH:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTH;
@@ -1472,6 +1505,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRM;
@@ -1495,6 +1529,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRH:
+			test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRH;
@@ -1517,15 +1552,20 @@
 				bcs->hw.isar.state = STFAX_ESCAPE; 
 			}
 			break;
+		case ISDN_FAXPUMP_HALT:
+			bcs->hw.isar.state = STFAX_NULL;
+			nom = 0;
+			ctrl = PCTRL_CMD_HALT;
+			break;
 	}
 	if (ctrl)
 		sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
 }
 
 void
-__isar_setup(struct IsdnCardState *cs)
+isar_setup(struct IsdnCardState *cs)
 {
-	u8 msg;
+	u_char msg;
 	int i;
 	
 	/* Dpath 1, 2 */
@@ -1538,57 +1578,105 @@
 		cs->bcs[i].mode = 0;
 		cs->bcs[i].hw.isar.dpath = i + 1;
 		modeisar(&cs->bcs[i], 0, 0);
-		INIT_WORK(&cs->bcs[i].work, isar_bh, &cs->bcs[i]);
+		INIT_WORK(&cs->bcs[i].tqueue, (void *)(void *) isar_bh, &cs->bcs[i]);
 	}
 }
 
 void
 isar_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
+	int ret;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				if (bcs->cs->debug & L1_DEB_HSCX)
+					debugl1(bcs->cs, "DRQ set BC_FLG_BUSY");
+				bcs->hw.isar.txcnt = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n");
+			} else {
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				if (bcs->cs->debug & L1_DEB_HSCX)
+					debugl1(bcs->cs, "PUI set BC_FLG_BUSY");
+				bcs->tx_skb = skb;
+				bcs->hw.isar.txcnt = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			st->l1.bcs->hw.isar.conmsg[0] = 0;
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			bcs->hw.isar.conmsg[0] = 0;
 			if (test_bit(FLG_ORIG, &st->l2.flag))
-				test_and_set_bit(BC_FLG_ORIG, &st->l1.bcs->Flag);
+				test_and_set_bit(BC_FLG_ORIG, &bcs->Flag);
 			else
-				test_and_clear_bit(BC_FLG_ORIG, &st->l1.bcs->Flag);
+				test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag);
 			switch(st->l1.mode) {
 				case L1_MODE_TRANS:
 				case L1_MODE_HDLC:
-					if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
+					ret = modeisar(bcs, st->l1.mode, st->l1.bc);
+					spin_unlock_irqrestore(&bcs->cs->lock, flags);
+					if (ret)
 						l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
 					else
 						l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
 					break;
 				case L1_MODE_V32:
 				case L1_MODE_FAX:
-					if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
+					ret = modeisar(bcs, st->l1.mode, st->l1.bc);
+					spin_unlock_irqrestore(&bcs->cs->lock, flags);
+					if (ret)
 						l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
 					break;
+				default:
+					spin_unlock_irqrestore(&bcs->cs->lock, flags);
+					break;
 			}
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
-				debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY");
-			modeisar(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			switch(st->l1.mode) {
+				case L1_MODE_TRANS:
+				case L1_MODE_HDLC:
+				case L1_MODE_V32:
+					break;
+				case L1_MODE_FAX:
+					isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0);
+					break;
+			}
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			if (bcs->cs->debug & L1_DEB_HSCX)
+				debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY");
+			modeisar(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -1634,9 +1722,6 @@
 	bcs->event = 0;
 	bcs->hw.isar.rcvidx = 0;
 	bcs->tx_cnt = 0;
-	bcs->hw.isar.ftimer.function = (void *) ftimer_handler;
-	bcs->hw.isar.ftimer.data = (long) bcs;
-	init_timer(&bcs->hw.isar.ftimer);
 	return (0);
 }
 
@@ -1647,7 +1732,7 @@
 	if (open_isarstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = isar_l2l1;
+	st->l2.l2l1 = isar_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -1674,6 +1759,51 @@
 						test_and_set_bit(BC_FLG_DLEETX,
 							&bcs->Flag);
 					break;
+				case ISDN_FAX_CLASS1_FTS:
+					if (ic->parm.aux.subcmd == AT_QUERY) {
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+						strcpy(ic->parm.aux.para, "0-255");
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
+						if (bcs->hw.isar.state == STFAX_READY) {
+							if (! ic->parm.aux.para[0]) {
+								ic->command = ISDN_STAT_FAXIND;
+								ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+								cs->iif.statcallb(ic);
+								return(0);
+							}
+							if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
+								/* n*10 ms */
+								bcs->hw.isar.ftimer.expires =
+									jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000);
+								test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
+								add_timer(&bcs->hw.isar.ftimer);
+								return(0);
+							} else {
+								if (cs->debug)
+									debugl1(cs, "isar FTS=%d and FTI busy",
+										ic->parm.aux.para[0]);
+							}
+						} else {
+							if (cs->debug)
+								debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
+									ic->parm.aux.para[0],bcs->hw.isar.state);
+						}
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+						cs->iif.statcallb(ic);
+					}
+					break;
 				case ISDN_FAX_CLASS1_FRM:
 				case ISDN_FAX_CLASS1_FRH:
 				case ISDN_FAX_CLASS1_FTM:
@@ -1686,16 +1816,24 @@
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
-						strcpy(ic->parm.aux.para, faxmodulation_s);
+						char *p = ic->parm.aux.para;
+						for(i=0;i<FAXMODCNT;i++)
+							if ((1<<i) & modmask)
+								p += sprintf(p, "%d,", faxmodulation[i]);
+						p--;
+						*p=0;
 						ic->command = ISDN_STAT_FAXIND;
 						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
 						for(i=0;i<FAXMODCNT;i++)
 							if (faxmodulation[i]==ic->parm.aux.para[0])
 								break;
-						if ((FAXMODCNT > i) && 
+						if ((i < FAXMODCNT) && ((1<<i) & modmask) && 
 							test_bit(BC_FLG_INIT, &bcs->Flag)) {
 							isar_pump_cmd(bcs,
 								ic->parm.aux.cmd,
@@ -1713,16 +1851,36 @@
 			break;
 		case (ISDN_CMD_IOCTL):
 			switch (ic->arg) {
-				case (9): /* load firmware */
+				case 9: /* load firmware */
 					features = ISDN_FEATURE_L2_MODEM |
 						ISDN_FEATURE_L2_FAX |
 						ISDN_FEATURE_L3_FCLASS1;
 					memcpy(&adr, ic->parm.num, sizeof(ulong));
-					if (isar_load_firmware(cs, (u8 *)adr))
+					if (isar_load_firmware(cs, (u_char *)adr))
 						return(1);
 					else 
 						ll_run(cs, features);
 					break;
+				case 20:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
+						modmask, features);
+					modmask = features;
+					break;
+				case 21:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
+						frm_extra_delay, features);
+					if (features >= 0)
+						frm_extra_delay = features;
+					break;
+				case 22:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
+						para_TOA, features);
+					if (features >= 0 && features < 32)
+						para_TOA = features;
+					break;
 				default:
 					printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
 					       (int) ic->arg);
@@ -1735,21 +1893,17 @@
 	return(0);
 }
 
-static struct bc_l1_ops isar_l1_ops = {
-	.fill_fifo = isar_fill_fifo,
-	.open      = setstack_isar,
-	.close     = close_isarstate,
-};
-
 void __devinit
 initisar(struct IsdnCardState *cs)
 {
-	cs->bc_l1_ops = &isar_l1_ops;
-}
-
-int
-isar_setup(struct IsdnCardState *cs, struct bc_hw_ops *isar_ops)
-{
-	cs->bc_hw_ops = isar_ops;
-	return ISARVersion(cs, "HiSax:");
+	cs->bcs[0].BC_SetStack = setstack_isar;
+	cs->bcs[1].BC_SetStack = setstack_isar;
+	cs->bcs[0].BC_Close = close_isarstate;
+	cs->bcs[1].BC_Close = close_isarstate;
+	cs->bcs[0].hw.isar.ftimer.function = (void *) ftimer_handler;
+	cs->bcs[0].hw.isar.ftimer.data = (long) &cs->bcs[0];
+	init_timer(&cs->bcs[0].hw.isar.ftimer);
+	cs->bcs[1].hw.isar.ftimer.function = (void *) ftimer_handler;
+	cs->bcs[1].hw.isar.ftimer.data = (long) &cs->bcs[1];
+	init_timer(&cs->bcs[1].hw.isar.ftimer);
 }
--- diff/drivers/isdn/hisax/isar.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/isar.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isar.h,v 1.9.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $
  *
  * ISAR (Siemens PSB 7110) specific defines
  *
@@ -28,6 +28,8 @@
 #define ISAR_HIS_FIRM		0x1e
 #define ISAR_HIS_STDSP		0x08
 #define ISAR_HIS_DIAG		0x05
+#define ISAR_HIS_WAITSTATE	0x27
+#define ISAR_HIS_TIMERIRQ	0x25
 #define ISAR_HIS_P0CFG		0x3c
 #define ISAR_HIS_P12CFG		0x24
 #define ISAR_HIS_SARTCFG	0x25	
@@ -43,6 +45,10 @@
 #define ISAR_HIS_DPS2		0x80
 #define SET_DPS(x)		((x<<6) & 0xc0)
 
+#define ISAR_CMD_TIMERIRQ_OFF	0x20
+#define ISAR_CMD_TIMERIRQ_ON	0x21
+
+
 #define ISAR_IIS_MSCMSD		0x3f
 #define ISAR_IIS_VNR		0x15
 #define ISAR_IIS_DKEY		0x03
@@ -207,8 +213,10 @@
 #define STFAX_ESCAPE	5
 #define STFAX_SILDET	6
 
+#define ISDN_FAXPUMP_HALT	100
+
+extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
 extern void initisar(struct IsdnCardState *cs);
 extern void isar_fill_fifo(struct BCState *bcs);
 extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic);
-extern int isar_setup(struct IsdnCardState *cs, struct bc_hw_ops *isar_ops);
--- diff/drivers/isdn/hisax/isdnl1.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/isdnl1.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.41.6.5 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $
  *
  * common low level stuff for Siemens Chipsetbased isdn cards
  *
@@ -18,7 +18,7 @@
  *
  */
 
-const char *l1_revision = "$Revision: 2.41.6.5 $";
+const char *l1_revision = "$Revision: 2.46.2.5 $";
 
 #include <linux/init.h>
 #include "hisax.h"
@@ -126,7 +126,7 @@
 };
 
 void
-debugl1(struct IsdnCardState *cs, const char *fmt, ...)
+debugl1(struct IsdnCardState *cs, char *fmt, ...)
 {
 	va_list args;
 	char tmp[8];
@@ -159,9 +159,9 @@
 	st = cs->stlist;
 	while (st) {
 		if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
-			L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 		else
-			L1L2(st, PH_ACTIVATE | INDICATION, NULL);
+			st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
 		st = st->next;
 	}
 }
@@ -174,8 +174,8 @@
 	st = cs->stlist;
 	while (st) {
 		if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-			L1L2(st, PH_PAUSE | CONFIRM, NULL);
-		L1L2(st, PH_DEACTIVATE | INDICATION, NULL);
+			st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
+		st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
 		st = st->next;
 	}
 	test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
@@ -190,12 +190,13 @@
 		return;
 
 	stptr = cs->stlist;
-	while (stptr != NULL)
+	while (stptr != NULL) {
 		if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
-			L1L2(stptr, PH_PULL | CONFIRM, NULL);
+			stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
 			break;
 		} else
 			stptr = stptr->next;
+	}
 }
 
 void
@@ -234,7 +235,7 @@
 			if (sapi == CTRL_SAPI) { /* sapi 0 */
 				while (stptr != NULL) {
 					if ((nskb = skb_clone(skb, GFP_ATOMIC)))
-						L1L2(stptr, PH_DATA | INDICATION, nskb);
+						stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
 					else
 						printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
 					stptr = stptr->next;
@@ -253,7 +254,7 @@
 			found = 0;
 			while (stptr != NULL)
 				if (tei == stptr->l2.tei) {
-					L1L2(stptr, PH_DATA | INDICATION, skb);
+					stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
 					found = !0;
 					break;
 				} else
@@ -276,10 +277,10 @@
 	}
 
 	if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
-		L1L2(st, PH_PULL | CONFIRM, NULL);
+		st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 	if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
 		if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
-			L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
+			st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
 		}
 	}
 }
@@ -294,31 +295,35 @@
 		FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
 	}
 	while ((skb = skb_dequeue(&bcs->rqueue))) {
-		L1L2(bcs->st, PH_DATA | INDICATION, skb);
+		bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
 	}
 }
 
 static void
-BChannel_proc_cmpl(struct BCState *bcs)
+BChannel_proc_ack(struct BCState *bcs)
 {
-	struct sk_buff *skb;
+	u_long	flags;
+	int	ack;
 
-	while ((skb = skb_dequeue(&bcs->cmpl_queue))) {
-		L1L2(bcs->st, PH_DATA | CONFIRM, skb);
-	}
+	spin_lock_irqsave(&bcs->aclock, flags);
+	ack = bcs->ackcnt;
+	bcs->ackcnt = 0;
+	spin_unlock_irqrestore(&bcs->aclock, flags);
+	if (ack)
+		lli_writewakeup(bcs->st, ack);
 }
 
 void
-BChannel_bh(void *data)
+BChannel_bh(struct BCState *bcs)
 {
-	struct BCState *bcs = data;
-
+	if (!bcs)
+		return;
 	if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
 		BChannel_proc_rcv(bcs);
 	if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
 		BChannel_proc_xmt(bcs);
-	if (test_and_clear_bit(B_CMPLREADY, &bcs->event))
-		BChannel_proc_cmpl(bcs);
+	if (test_and_clear_bit(B_ACKPENDING, &bcs->event))
+		BChannel_proc_ack(bcs);
 }
 
 void
@@ -350,21 +355,23 @@
 }
 
 void
-init_bcstate(struct IsdnCardState *cs,
-	     int bc)
+init_bcstate(struct IsdnCardState *cs, int bc)
 {
 	struct BCState *bcs = cs->bcs + bc;
 
 	bcs->cs = cs;
 	bcs->channel = bc;
-	INIT_WORK(&bcs->work, BChannel_bh, bcs);
+	INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs);
+	spin_lock_init(&bcs->aclock);
+	bcs->BC_SetStack = NULL;
+	bcs->BC_Close = NULL;
 	bcs->Flag = 0;
 }
 
 #ifdef L2FRAME_DEBUG		/* psa */
 
 char *
-l2cmd(u8 cmd)
+l2cmd(u_char cmd)
 {
 	switch (cmd & ~0x10) {
 		case 1:
@@ -398,7 +405,7 @@
 static char tmpdeb[32];
 
 char *
-l2frames(u8 * ptr)
+l2frames(u_char * ptr)
 {
 	switch (ptr[2] & ~0x10) {
 		case 1:
@@ -430,7 +437,7 @@
 void
 Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
 {
-	u8 *ptr;
+	u_char *ptr;
 
 	ptr = skb->data;
 
@@ -724,7 +731,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_ACTIV);
-	L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
+	st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 }
 
 static void
@@ -733,7 +740,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_NULL);
-	L2L1(st, PH_DEACTIVATE | CONFIRM, NULL);
+	st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
 }
 
 static struct FsmNode L1BFnList[] __initdata =
@@ -808,7 +815,7 @@
 				debugl1(cs, "PH_ACTIVATE_REQ %s",
 					st->l1.l1m.fsm->strState[st->l1.l1m.state]);
 			if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
-				L1L2(st, PH_ACTIVATE | CONFIRM, NULL);
+				st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 			else {
 				test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
 				FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
@@ -904,19 +911,9 @@
 	setstack_tei(st);
 	setstack_manager(st);
 	st->l1.stlistp = &(cs->stlist);
-	st->l1.l2l1  = dch_l2l1;
-	if (cs->dc_l1_ops->open)
-		cs->dc_l1_ops->open(st, cs);
-}
-
-void
-dc_l1_init(struct IsdnCardState *cs, struct dc_l1_ops *ops)
-{
-	cs->dc_l1_ops = ops;
-	INIT_WORK(&cs->work, ops->bh_func, cs);
-	init_timer(&cs->dbusytimer);
-	cs->dbusytimer.function = (void *)(unsigned long) ops->dbusy_func;
-	cs->dbusytimer.data = (unsigned long) cs;
+	st->l2.l2l1  = dch_l2l1;
+	if (cs->setstack_d)
+		cs->setstack_d(st, cs);
 }
 
 void
--- diff/drivers/isdn/hisax/isdnl1.h	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/isdnl1.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.h,v 2.9.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $
  *
  * Layer 1 defines
  *
@@ -7,9 +7,6 @@
  *
  */
 
-#ifndef __ISDNL1_H__
-#define __ISDNL1_H__
-
 #define D_RCVBUFREADY	0
 #define D_XMTBUFREADY	1
 #define D_L1STATECHANGE	2
@@ -20,578 +17,16 @@
 #define D_TX_MON1	7
 #define E_RCVBUFREADY	8
 
-#define B_RCVBUFREADY   0
-#define B_XMTBUFREADY   1
-#define B_CMPLREADY     2
-
-#define B_LL_NOCARRIER	8
-#define B_LL_CONNECT	9
-#define B_LL_OK		10
+#define B_RCVBUFREADY	0
+#define B_XMTBUFREADY	1
+#define B_ACKPENDING	2
 
-extern void debugl1(struct IsdnCardState *cs, const char *fmt, ...);
+extern void debugl1(struct IsdnCardState *cs, char *fmt, ...);
 extern void DChannel_proc_xmt(struct IsdnCardState *cs);
 extern void DChannel_proc_rcv(struct IsdnCardState *cs);
 extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
 extern void l1_msg_b(struct PStack *st, int pr, void *arg);
 
-void dc_l1_init(struct IsdnCardState *cs, struct dc_l1_ops *ops);
-
-static inline void
-fill_fifo_b(struct BCState *bcs)
-{
-	bcs->cs->bc_l1_ops->fill_fifo(bcs);
-}
-
-static inline void
-fill_fifo_d(struct IsdnCardState *cs)
-{
-	cs->dc_l1_ops->fill_fifo(cs);
-}
-
 #ifdef L2FRAME_DEBUG
 extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
 #endif
-
-static inline void
-sched_b_event(struct BCState *bcs, int event)
-{
-	set_bit(event, &bcs->event);
-	schedule_work(&bcs->work);
-}
-
-static inline void
-sched_d_event(struct IsdnCardState *cs, int event)
-{
-	set_bit(event, &cs->event);
-	schedule_work(&cs->work);
-}
-
-/* called with the card lock held */
-static inline void
-xmit_complete_b(struct BCState *bcs)
-{
-	skb_queue_tail(&bcs->cmpl_queue, bcs->tx_skb);
-	sched_b_event(bcs, B_CMPLREADY);
-	bcs->tx_skb = NULL;
-}
-
-/* called with the card lock held */
-static inline void
-xmit_complete_d(struct IsdnCardState *cs)
-{
-	dev_kfree_skb_irq(cs->tx_skb);
-	cs->tx_skb = NULL;
-}
-
-/* called with the card lock held */
-static inline void
-xmit_ready_b(struct BCState *bcs)
-{
-	bcs->tx_skb = skb_dequeue(&bcs->squeue);
-	if (bcs->tx_skb) {
-		bcs->count = 0;
-		set_bit(BC_FLG_BUSY, &bcs->Flag);
-		fill_fifo_b(bcs);
-	} else {
-		clear_bit(BC_FLG_BUSY, &bcs->Flag);
-		sched_b_event(bcs, B_XMTBUFREADY);
-	}
-}
-
-/* called with the card lock held */
-static inline void
-xmit_ready_d(struct IsdnCardState *cs)
-{
-	cs->tx_skb = skb_dequeue(&cs->sq);
-	if (cs->tx_skb) {
-		cs->tx_cnt = 0;
-		fill_fifo_d(cs);
-	} else {
-		sched_d_event(cs, D_XMTBUFREADY);
-	}
-}
-
-static inline void
-xmit_data_req_b(struct BCState *bcs, struct sk_buff *skb)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cs->lock, flags);
-	if (bcs->tx_skb) {
-		skb_queue_tail(&bcs->squeue, skb);
-	} else {
-		set_bit(BC_FLG_BUSY, &bcs->Flag);
-		bcs->tx_skb = skb;
-		bcs->count = 0;
-		fill_fifo_b(bcs);
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-}
-
-static inline void
-xmit_data_req_d(struct IsdnCardState *cs, struct sk_buff *skb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cs->lock, flags);
-	if (cs->debug & DEB_DLOG_HEX)
-		LogFrame(cs, skb->data, skb->len);
-	if (cs->debug & DEB_DLOG_VERBOSE)
-		dlogframe(cs, skb, 0);
-	if (cs->tx_skb) {
-		skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG
-		if (cs->debug & L1_DEB_LAPD)
-			Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
-	} else {
-		cs->tx_skb = skb;
-		cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG
-		if (cs->debug & L1_DEB_LAPD)
-			Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
-		fill_fifo_d(cs);
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-}
-
-static inline void
-xmit_pull_ind_b(struct BCState *bcs, struct sk_buff *skb)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cs->lock, flags);
-	if (bcs->tx_skb) {
-		WARN_ON(1);
-	} else {
-		set_bit(BC_FLG_BUSY, &bcs->Flag);
-		bcs->tx_skb = skb;
-		bcs->count = 0;
-		fill_fifo_b(bcs);
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-}
-
-static inline void
-xmit_pull_ind_d(struct IsdnCardState *cs, struct sk_buff *skb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cs->lock, flags);
-	if (cs->tx_skb) {
-		WARN_ON(1);
-	} else {
-		if (cs->debug & DEB_DLOG_HEX)
-			LogFrame(cs, skb->data, skb->len);
-		if (cs->debug & DEB_DLOG_VERBOSE)
-			dlogframe(cs, skb, 0);
-#ifdef L2FRAME_DEBUG
-		if (cs->debug & L1_DEB_LAPD)
-			Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
-		cs->tx_skb = skb;
-		cs->tx_cnt = 0;
-		fill_fifo_d(cs);
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-}
-
-/* If busy, the PH_PULL | CONFIRM scheduling is handled under
- * the card lock by xmit_ready_b() above, so no race */
-static inline void
-xmit_pull_req_b(struct PStack *st)
-{
-	struct BCState *bcs = st->l1.bcs;
-	struct IsdnCardState *cs = bcs->cs;
-	unsigned long flags;
-	int busy = 0;
-
-	spin_lock_irqsave(&cs->lock, flags);
-	if (bcs->tx_skb) {
-		set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-		busy = 1;
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-	if (!busy)
-		L1L2(st, PH_PULL | CONFIRM, NULL);
-}
-
-/* If busy, the PH_PULL | CONFIRM scheduling is handled under
- * the card lock by xmit_ready_d() above, so no race */
-static inline void
-xmit_pull_req_d(struct PStack *st)
-{
-	struct IsdnCardState *cs = st->l1.hardware;
-	unsigned long flags;
-	int busy = 0;
-
-#ifdef L2FRAME_DEBUG
-	if (cs->debug & L1_DEB_LAPD)
-		debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
-	spin_lock_irqsave(&cs->lock, flags);
-	if (cs->tx_skb) {
-		set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-		busy = 1;
-	}
-	spin_unlock_irqrestore(&cs->lock, flags);
-	if (!busy)
-		L1L2(st, PH_PULL | CONFIRM, NULL);
-}
-
-/* called with the card lock held */
-static inline void
-xmit_restart_b(struct BCState *bcs)
-{
-#ifdef ERROR_STATISTIC
-	bcs->err_tx++;
-#endif
-	if (!bcs->tx_skb) {
-		WARN_ON(1);
-		return;
-	}
-	skb_push(bcs->tx_skb, bcs->count);
-	bcs->tx_cnt += bcs->count;
-	bcs->count = 0;
-}
-
-/* called with the card lock held */
-static inline void
-xmit_restart_d(struct IsdnCardState *cs)
-{
-#ifdef ERROR_STATISTIC
-	cs->err_tx++;
-#endif
-	if (!cs->tx_skb) {
-		WARN_ON(1);
-		return;
-	}
-	skb_push(cs->tx_skb, cs->tx_cnt);
-	cs->tx_cnt = 0;
-}
-
-/* Useful for HSCX/ISAC work-alike's */
-/* ---------------------------------------------------------------------- */
-
-/* XPR - transmit pool ready */
-/* called with the card lock held */
-static inline void
-xmit_xpr_b(struct BCState *bcs)
-{
-	/* current frame? */
-	if (bcs->tx_skb) {
-		/* last frame not done yet? */
-		if (bcs->tx_skb->len) {
-			fill_fifo_b(bcs);
-			return;
-		}
-		xmit_complete_b(bcs);
-		bcs->count = 0;
-	}
-	xmit_ready_b(bcs);
-}
-
-/* XPR - transmit pool ready */
-/* called with the card lock held */
-static inline void
-xmit_xpr_d(struct IsdnCardState *cs)
-{
-	if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
-		del_timer(&cs->dbusytimer);
-	if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-		sched_d_event(cs, D_CLEARBUSY);
-	/* current frame? */
-	if (cs->tx_skb) {
-		/* last frame not done yet? */
-		if (cs->tx_skb->len) {
-			fill_fifo_d(cs);
-			return;
-		}
-		xmit_complete_d(cs);
-		cs->tx_cnt = 0;
-	}
-	xmit_ready_d(cs);
-}
-
-/* XDU - transmit data underrun */
-/* called with the card lock held */
-static inline void
-xmit_xdu_b(struct BCState *bcs, void (*reset_xmit)(struct BCState *bcs))
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	if (cs->debug & L1_DEB_WARN)
-		debugl1(cs, "HSCX %c EXIR XDU", 'A' + bcs->channel);
-
-	if (bcs->mode == L1_MODE_TRANS) {
-		fill_fifo_b(bcs);
-	} else {
-		xmit_restart_b(bcs);
-		reset_xmit(bcs);
-	}
-}
-
-/* XDU - transmit data underrun */
-/* called with the card lock held */
-static inline void
-xmit_xdu_d(struct IsdnCardState *cs, void (*reset_xmit)(struct IsdnCardState *cs))
-{
-	printk(KERN_WARNING "HiSax: D XDU\n");
-	if (cs->debug & L1_DEB_WARN)
-		debugl1(cs, "D XDU");
-
-	if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
-		del_timer(&cs->dbusytimer);
-	if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-		sched_d_event(cs, D_CLEARBUSY);
-
-	xmit_restart_d(cs);
-	if (reset_xmit)
-		reset_xmit(cs);
-}
-
-static inline unsigned char *
-xmit_fill_fifo_b(struct BCState *bcs, u_int fifo_size, int *count, int *more)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	unsigned char *p;
-
-	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
-		debugl1(cs, __FUNCTION__);
-
-	if (!bcs->tx_skb || bcs->tx_skb->len <= 0) {
-		WARN_ON(1);
-		return NULL;
-	}
-
-	*more = (bcs->mode == L1_MODE_TRANS);
-	if (bcs->tx_skb->len > fifo_size) {
-		*more = 1;
-		*count = fifo_size;
-	} else {
-		*count = bcs->tx_skb->len;
-	}
-	p = bcs->tx_skb->data;
-	skb_pull(bcs->tx_skb, *count);
-	bcs->tx_cnt -= *count;
-	bcs->count += *count;
-
-	if (cs->debug & L1_DEB_HSCX_FIFO) {
-		char *t = bcs->blog;
-
-		t += sprintf(t, "%s %c cnt %d", __FUNCTION__,
-			     bcs->unit ? 'B' : 'A', *count);
-		QuickHex(t, p, *count);
-		debugl1(cs, bcs->blog);
-	}
-	return p;
-}
-
-static inline unsigned char *
-xmit_fill_fifo_d(struct IsdnCardState *cs, u_int fifo_size, int *count, int *more)
-{
-	unsigned char *p;
-
-	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
-		debugl1(cs, __FUNCTION__);
-
-	if (!cs->tx_skb || cs->tx_skb->len <= 0) {
-		WARN_ON(1);
-		return NULL;
-	}
-
-	*more = 0;
-	if (cs->tx_skb->len > fifo_size) {
-		*more = 1;
-		*count = fifo_size;
-	} else {
-		*count = cs->tx_skb->len;
-	}
-
-	p = cs->tx_skb->data;
-	skb_pull(cs->tx_skb, *count);
-	cs->tx_cnt += *count;
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char *t = cs->dlog;
-
-		t += sprintf(t, "%s cnt %d", __FUNCTION__, *count);
-		QuickHex(t, p, *count);
-		debugl1(cs, cs->dlog);
-	}
-	return p;
-}
-
-static inline void
-recv_empty_fifo_d(struct IsdnCardState *cs, int count)
-{
-	u8 *p;
-
-	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
-		debugl1(cs, __FUNCTION__);
-
-	if (cs->rcvidx + count > MAX_DFRAME_LEN_L1) {
-		if (cs->debug & L1_DEB_WARN)
-			debugl1(cs, "%s: incoming packet too large", __FUNCTION__);
-		cs->rcvidx = 0;
-		return;
-	}
-	p = cs->rcvbuf + cs->rcvidx;
-	cs->rcvidx += count;
-	cs->dc_hw_ops->read_fifo(cs, p, count);
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char *t = cs->dlog;
-
-		t += sprintf(t, "%s cnt %d", __FUNCTION__, count);
-		QuickHex(t, p, count);
-		debugl1(cs, cs->dlog);
-	}
-}
-
-static inline void
-recv_empty_fifo_b(struct BCState *bcs, int count)
-{
-	u8 *p;
-	struct IsdnCardState *cs = bcs->cs;
-
-	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
-		debugl1(cs, __FUNCTION__);
-
-	if (bcs->rcvidx + count > HSCX_BUFMAX) {
-		if (cs->debug & L1_DEB_WARN)
-			debugl1(cs, "%s: incoming packet too large", __FUNCTION__);
-		bcs->rcvidx = 0;
-		return;
-	}
-	p = bcs->rcvbuf + bcs->rcvidx;
-	bcs->rcvidx += count;
-	cs->bc_hw_ops->read_fifo(cs, bcs->unit, p, count);
-
-	if (cs->debug & L1_DEB_HSCX_FIFO) {
-		char *t = bcs->blog;
-
-		t += sprintf(t, "%s %c cnt %d", __FUNCTION__,
-			     bcs->unit ? 'B' : 'A', count);
-		QuickHex(t, p, count);
-		debugl1(cs, bcs->blog);
-	}
-}
-
-/* RME - receive message end */
-static inline void
-recv_rme_d(struct IsdnCardState *cs)
-{
-	struct sk_buff *skb;
-	int count;
-
-	count = cs->rcvidx - 1;
-	cs->rcvidx = 0;
-	if (count == 0)
-		return;
-
-	skb = dev_alloc_skb(count);
-	if (!skb) {
-		printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__);
-		return;
-	}
-	memcpy(skb_put(skb, count), cs->rcvbuf, count);
-	skb_queue_tail(&cs->rq, skb);
-	sched_d_event(cs, D_RCVBUFREADY);
-}
-
-static inline void
-recv_rme_b(struct BCState *bcs)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	struct sk_buff *skb;
-	int count;
-
-	count = bcs->rcvidx - 1;
-	bcs->rcvidx = 0;
-	if (count == 0)
-		return;
-
-	if (cs->debug & L1_DEB_HSCX_FIFO)
-		debugl1(cs, "HX Frame %d", count);
-
-	skb = dev_alloc_skb(count);
-	if (!skb) {
-		printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__);
-		return;
-	}
-	memcpy(skb_put(skb, count), bcs->rcvbuf, count);
-	skb_queue_tail(&bcs->rqueue, skb);
-	sched_b_event(bcs, B_RCVBUFREADY);
-}
-
-/* RPF - receive pull full */
-static inline void
-recv_rpf_b(struct BCState *bcs)
-{
-	if (bcs->mode != L1_MODE_TRANS)
-		return;
-
-	recv_rme_b(bcs);
-}
-	
-static inline int
-bc_open(struct BCState *bcs)
-{
-	if (test_and_set_bit(BC_FLG_INIT, &bcs->Flag))
-		return 0;
-
-	bcs->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC);
-	if (!bcs->rcvbuf)
-		goto err;
-
-	bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC);
-	if (!bcs->blog)
-		goto err_rcvbuf;
-	
-	skb_queue_head_init(&bcs->rqueue);
-	skb_queue_head_init(&bcs->squeue);
-	skb_queue_head_init(&bcs->cmpl_queue);
-
-	clear_bit(BC_FLG_BUSY, &bcs->Flag);
-	bcs->tx_skb = NULL;
-	bcs->rcvidx = 0;
-	bcs->tx_cnt = 0;
-	bcs->event = 0;
-
-	return 0;
-
- err_rcvbuf:
-	kfree(bcs->rcvbuf);
- err:
-	clear_bit(BC_FLG_INIT, &bcs->Flag);
-	printk(KERN_WARNING "HiSax: %s: out of memory\n", __FUNCTION__);
-	return -ENOMEM;;
-}
-
-static inline void
-bc_close(struct BCState *bcs)
-{
-	if (!test_and_clear_bit(BC_FLG_INIT, &bcs->Flag))
-		return;
-
-	kfree(bcs->rcvbuf);
-	bcs->rcvbuf = NULL;
-
-	kfree(bcs->blog);
-	bcs->blog = NULL;
-
-	skb_queue_purge(&bcs->rqueue);
-	skb_queue_purge(&bcs->squeue);
-	skb_queue_purge(&bcs->cmpl_queue);
-	if (bcs->tx_skb) {
-		dev_kfree_skb_any(bcs->tx_skb);
-		bcs->tx_skb = NULL;
-		clear_bit(BC_FLG_BUSY, &bcs->Flag);
-	}
-}
-
-#endif
--- diff/drivers/isdn/hisax/isdnl2.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/isdnl2.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 2.25.6.4 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -19,21 +19,21 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.25.6.4 $";
-static spinlock_t isdnl2_lock = SPIN_LOCK_UNLOCKED;
+const char *l2_revision = "$Revision: 2.30.2.4 $";
+
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
 static struct Fsm l2fsm;
 
 enum {
-	ST_L2_1, /* TEI unassigned */
-	ST_L2_2, /* Assign awaiting TEI */
-	ST_L2_3, /* Establish awaiting TEI */
-	ST_L2_4, /* TEI assigned */
-	ST_L2_5, /* Awaiting establishment */
-	ST_L2_6, /* Awaiting release */
-	ST_L2_7, /* Multiple frame established */
-	ST_L2_8, /* Timer recovery */
+	ST_L2_1,
+	ST_L2_2,
+	ST_L2_3,
+	ST_L2_4,
+	ST_L2_5,
+	ST_L2_6,
+	ST_L2_7,
+	ST_L2_8,
 };
 
 #define L2_STATE_COUNT (ST_L2_8+1)
@@ -103,7 +103,7 @@
 	"EV_L2_FRAME_ERROR",
 };
 
-static u_int l2addrsize(struct Layer2 *l2);
+static int l2addrsize(struct Layer2 *l2);
 
 static void
 set_peer_busy(struct Layer2 *l2) {
@@ -178,23 +178,23 @@
 	clear_peer_busy(l2);
 }
 
-inline u_int
+inline int
 l2headersize(struct Layer2 *l2, int ui)
 {
 	return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
 		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
 }
 
-inline u_int
+inline int
 l2addrsize(struct Layer2 *l2)
 {
 	return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
 }
 
 static int
-sethdraddr(struct Layer2 *l2, u8 * header, int rsp)
+sethdraddr(struct Layer2 *l2, u_char * header, int rsp)
 {
-	u8 *ptr = header;
+	u_char *ptr = header;
 	int crbit = rsp;
 
 	if (test_bit(FLG_LAPD, &l2->flag)) {
@@ -218,37 +218,37 @@
 {
 	if (test_bit(FLG_LAPB, &st->l2.flag))
 		st->l1.bcs->tx_cnt += skb->len;
-	L2L1(st, PH_DATA | REQUEST, skb);
+	st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
 #define enqueue_ui(a, b) enqueue_super(a, b)
 
 inline int
-IsUI(u8 * data)
+IsUI(u_char * data)
 {
 	return ((data[0] & 0xef) == UI);
 }
 
 inline int
-IsUA(u8 * data)
+IsUA(u_char * data)
 {
 	return ((data[0] & 0xef) == UA);
 }
 
 inline int
-IsDM(u8 * data)
+IsDM(u_char * data)
 {
 	return ((data[0] & 0xef) == DM);
 }
 
 inline int
-IsDISC(u8 * data)
+IsDISC(u_char * data)
 {
 	return ((data[0] & 0xef) == DISC);
 }
 
 inline int
-IsRR(u8 * data, struct PStack *st)
+IsRR(u_char * data, struct PStack *st)
 {
 	if (test_bit(FLG_MOD128, &st->l2.flag))
 		return (data[0] == RR);
@@ -257,9 +257,9 @@
 }
 
 inline int
-IsSFrame(u8 * data, struct PStack *st)
+IsSFrame(u_char * data, struct PStack *st)
 {
-	register u8 d = *data;
+	register u_char d = *data;
 	
 	if (!test_bit(FLG_MOD128, &st->l2.flag))
 		d &= 0xf;
@@ -267,27 +267,27 @@
 }
 
 inline int
-IsSABME(u8 * data, struct PStack *st)
+IsSABME(u_char * data, struct PStack *st)
 {
-	u8 d = data[0] & ~0x10;
+	u_char d = data[0] & ~0x10;
 
 	return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
 }
 
 inline int
-IsREJ(u8 * data, struct PStack *st)
+IsREJ(u_char * data, struct PStack *st)
 {
 	return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
 }
 
 inline int
-IsFRMR(u8 * data)
+IsFRMR(u_char * data)
 {
 	return ((data[0] & 0xef) == FRMR);
 }
 
 inline int
-IsRNR(u8 * data, struct PStack *st)
+IsRNR(u_char * data, struct PStack *st)
 {
 	return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
 }
@@ -295,7 +295,7 @@
 int
 iframe_error(struct PStack *st, struct sk_buff *skb)
 {
-	u_int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
+	int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
 	int rsp = *skb->data & 0x2;
 
 	if (test_bit(FLG_ORIG, &st->l2.flag))
@@ -360,8 +360,8 @@
 int
 FRMR_error(struct PStack *st, struct sk_buff *skb)
 {
-	u_int headers = l2addrsize(&st->l2) + 1;
-	u8 *datap = skb->data + headers;
+	int headers = l2addrsize(&st->l2) + 1;
+	u_char *datap = skb->data + headers;
 	int rsp = *skb->data & 0x2;
 
 	if (test_bit(FLG_ORIG, &st->l2.flag))
@@ -403,27 +403,35 @@
 setva(struct PStack *st, unsigned int nr)
 {
 	struct Layer2 *l2 = &st->l2;
-	struct sk_buff *skb;
+	int len;
+	u_long flags;
 
+	spin_lock_irqsave(&l2->lock, flags);
 	while (l2->va != nr) {
 		(l2->va)++;
 		if(test_bit(FLG_MOD128, &l2->flag))
 			l2->va %= 128;
 		else
 			l2->va %= 8;
-		skb = l2->windowar[l2->sow];
+		len = l2->windowar[l2->sow]->len;
+		if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type)
+			len = -1;
+		dev_kfree_skb(l2->windowar[l2->sow]);
 		l2->windowar[l2->sow] = NULL;
 		l2->sow = (l2->sow + 1) % l2->window;
-		
-		L2L3(st, DL_DATA | CONFIRM, skb);
+		spin_unlock_irqrestore(&l2->lock, flags);
+		if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >=0))
+			lli_writewakeup(st, len);
+		spin_lock_irqsave(&l2->lock, flags);
 	}
+	spin_unlock_irqrestore(&l2->lock, flags);
 }
 
 static void
-send_uframe(struct PStack *st, u8 cmd, u8 cr)
+send_uframe(struct PStack *st, u_char cmd, u_char cr)
 {
 	struct sk_buff *skb;
-	u8 tmp[MAX_HEADER_LEN];
+	u_char tmp[MAX_HEADER_LEN];
 	int i;
 
 	i = sethdraddr(&st->l2, tmp, cr);
@@ -436,7 +444,7 @@
 	enqueue_super(st, skb);
 }
 
-inline u8
+inline u_char
 get_PollFlag(struct PStack * st, struct sk_buff * skb)
 {
 	return (skb->data[l2addrsize(&(st->l2))] & 0x10);
@@ -449,10 +457,10 @@
 }
 
 
-inline u8
+inline u_char
 get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
 {
-	u8 PF;
+	u_char PF;
 
 	PF = get_PollFlag(st, skb);
 	FreeSkb(skb);
@@ -490,22 +498,22 @@
 		else
 			pr = DL_RELEASE | INDICATION;
 
-		L2L3(st, pr, NULL);
+		st->l2.l2l3(st, pr, NULL);
 }
 
 inline void
 lapb_dl_release_l2l3(struct PStack *st, int f)
 {
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
-		L2L3(st, DL_RELEASE | f, NULL);
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+		st->l2.l2l3(st, DL_RELEASE | f, NULL);
 }
 
 static void
 establishlink(struct FsmInst *fi)
 {
 	struct PStack *st = fi->userdata;
-	u8 cmd;
+	u_char cmd;
 
 	clear_exception(&st->l2);
 	st->l2.rc = 0;
@@ -599,7 +607,7 @@
 tx_ui(struct PStack *st)
 {
 	struct sk_buff *skb;
-	u8 header[MAX_HEADER_LEN];
+	u_char header[MAX_HEADER_LEN];
 	int i;
 
 	i = sethdraddr(&(st->l2), header, CMD);
@@ -627,7 +635,7 @@
 	struct sk_buff *skb = arg;
 
 	skb_pull(skb, l2headersize(&st->l2, 1));
-	L2L3(st, DL_UNIT_DATA | INDICATION, skb);
+	st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
 /*	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *		in states 1-3 for broadcast
  */
@@ -669,7 +677,7 @@
 {
 	struct PStack *st = fi->userdata;
 
-	L2L3(st, DL_RELEASE | CONFIRM, NULL);
+	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
 }
 
 static void
@@ -710,7 +718,7 @@
 	FsmChangeState(fi, ST_L2_7);
 	FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
-	L2L3(st, DL_ESTABLISH | INDICATION, NULL);
+	st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
 }
 
 static void
@@ -759,11 +767,11 @@
 	FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
 	if (est)
-		L2L3(st, DL_ESTABLISH | INDICATION, NULL);
+		st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
 
 	if ((ST_L2_7==state) || (ST_L2_8 == state))
 		if (skb_queue_len(&st->l2.i_queue) && cansend(st))
-			L2L1(st, PH_PULL | REQUEST, NULL);
+			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -816,10 +824,10 @@
 	FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
 
 	if (pr != -1)
-		L2L3(st, pr, NULL);
+		st->l2.l2l3(st, pr, NULL);
 
 	if (skb_queue_len(&st->l2.i_queue) && cansend(st))
-		L2L1(st, PH_PULL | REQUEST, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -862,7 +870,7 @@
 	 	if (!test_bit(FLG_L3_INIT, &st->l2.flag))
 			skb_queue_purge(&st->l2.i_queue);
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
 		st5_dl_release_l2l3(st);
 		FsmChangeState(fi, ST_L2_4);
 	}
@@ -882,11 +890,11 @@
 }
 
 inline void
-enquiry_cr(struct PStack *st, u8 typ, u8 cr, u8 pf)
+enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
 {
 	struct sk_buff *skb;
 	struct Layer2 *l2;
-	u8 tmp[MAX_HEADER_LEN];
+	u_char tmp[MAX_HEADER_LEN];
 	int i;
 
 	l2 = &st->l2;
@@ -940,8 +948,10 @@
 invoke_retransmission(struct PStack *st, unsigned int nr)
 {
 	struct Layer2 *l2 = &st->l2;
-	unsigned int p1;
+	u_int p1;
+	u_long flags;
 
+	spin_lock_irqsave(&l2->lock, flags);
 	if (l2->vs != nr) {
 		while (l2->vs != nr) {
 			(l2->vs)--;
@@ -958,8 +968,11 @@
 			skb_queue_head(&l2->i_queue, l2->windowar[p1]);
 			l2->windowar[p1] = NULL;
 		}
-		L2L1(st, PH_PULL | REQUEST, NULL);
+		spin_unlock_irqrestore(&l2->lock, flags);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+		return;
 	}
+	spin_unlock_irqrestore(&l2->lock, flags);
 }
 
 static void
@@ -1018,7 +1031,7 @@
 			restart_t200(st, 12);
 		}
 		if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
-			L2L1(st, PH_PULL | REQUEST, NULL);
+			st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	} else
 		nrerrorrecovery(fi);
 }
@@ -1046,7 +1059,7 @@
 	if (test_bit(FLG_LAPB, &st->l2.flag))
 		st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
 	skb_queue_tail(&st->l2.i_queue, skb);
-	L2L1(st, PH_PULL | REQUEST, NULL);
+	st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1066,8 +1079,8 @@
 	struct PStack *st = fi->userdata;
 	struct sk_buff *skb = arg;
 	struct Layer2 *l2 = &(st->l2);
-	int PollFlag, i;
-	unsigned int nr, ns;
+	int PollFlag, ns, i;
+	unsigned int nr;
 
 	i = l2addrsize(l2);
 	if (test_bit(FLG_MOD128, &l2->flag)) {
@@ -1095,7 +1108,7 @@
 		else
 			test_and_set_bit(FLG_ACK_PEND, &l2->flag);
 		skb_pull(skb, l2headersize(l2, 0));
-		L2L3(st, DL_DATA | INDICATION, skb);
+		st->l2.l2l3(st, DL_DATA | INDICATION, skb);
 	} else {
 		/* n(s)!=v(r) */
 		FreeSkb(skb);
@@ -1124,7 +1137,7 @@
 	}
 
 	if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
-		L2L1(st, PH_PULL | REQUEST, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 	if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
 		enquiry_cr(st, RR, RSP, 0);
 }
@@ -1159,7 +1172,7 @@
 		skb_queue_purge(&st->l2.i_queue);
 		st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
 		if (test_bit(FLG_LAPB, &st->l2.flag))
-			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
 		st5_dl_release_l2l3(st);
 	} else {
 		st->l2.rc++;
@@ -1250,9 +1263,10 @@
 	struct PStack *st = fi->userdata;
 	struct sk_buff *skb, *oskb;
 	struct Layer2 *l2 = &st->l2;
-	u8 header[MAX_HEADER_LEN];
-	int unsigned p1, i;
-	unsigned long flags;
+	u_char header[MAX_HEADER_LEN];
+	int i;
+	int unsigned p1;
+	u_long flags;
 
 	if (!cansend(st))
 		return;
@@ -1261,7 +1275,7 @@
 	if (!skb)
 		return;
 
-	spin_lock_irqsave(&isdnl2_lock, flags);
+	spin_lock_irqsave(&l2->lock, flags);
 	if(test_bit(FLG_MOD128, &l2->flag))
 		p1 = (l2->vs - l2->va) % 128;
 	else
@@ -1284,8 +1298,7 @@
 		header[i++] = (l2->vr << 5) | (l2->vs << 1);
 		l2->vs = (l2->vs + 1) % 8;
 	}
-	spin_unlock_irqrestore(&isdnl2_lock, flags);
-
+	spin_unlock_irqrestore(&l2->lock, flags);
 	p1 = skb->data - skb->head;
 	if (p1 >= i)
 		memcpy(skb_push(skb, i), header, i);
@@ -1298,14 +1311,14 @@
 		memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
 		FreeSkb(oskb);
 	}
-	L2L1(st, PH_PULL | INDICATION, skb);
+	st->l2.l2l1(st, PH_PULL | INDICATION, skb);
 	test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
 	if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
 		FsmDelTimer(&st->l2.t203, 13);
 		FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
 	}
 	if (skb_queue_len(&l2->i_queue) && cansend(st))
-		L2L1(st, PH_PULL | REQUEST, NULL);
+		st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1351,7 +1364,7 @@
 			invoke_retransmission(st, nr);
 			FsmChangeState(fi, ST_L2_7);
 			if (skb_queue_len(&l2->i_queue) && cansend(st))
-				L2L1(st, PH_PULL | REQUEST, NULL);
+				st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 		} else
 			nrerrorrecovery(fi);
 	} else {
@@ -1398,7 +1411,7 @@
 
 	skb_queue_purge(&st->l2.ui_queue);
 	st->l2.tei = -1;
-	L2L3(st, DL_RELEASE | INDICATION, NULL);
+	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1424,7 +1437,7 @@
 	skb_queue_purge(&st->l2.ui_queue);
 	st->l2.tei = -1;
 	stop_t200(st, 18);
-	L2L3(st, DL_RELEASE | CONFIRM, NULL);
+	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1439,23 +1452,23 @@
 	st->l2.tei = -1;
 	stop_t200(st, 17);
 	FsmDelTimer(&st->l2.t203, 19);
-	L2L3(st, DL_RELEASE | INDICATION, NULL);
+	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_1);
 }
 
 static void
-l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
+l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 	
 	skb_queue_purge(&st->l2.i_queue);
 	skb_queue_purge(&st->l2.ui_queue);
 	if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
-		L2L3(st, DL_RELEASE | INDICATION, NULL);
+		st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 }
 
 static void
-l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
+l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 
@@ -1468,18 +1481,18 @@
 }
 
 static void
-l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
+l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 
 	skb_queue_purge(&st->l2.ui_queue);
 	stop_t200(st, 20);
-	L2L3(st, DL_RELEASE | CONFIRM, NULL);
+	st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
 	FsmChangeState(fi, ST_L2_4);
 }
 
 static void
-l2_persistent_da(struct FsmInst *fi, int event, void *arg)
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 
@@ -1488,7 +1501,7 @@
 	freewin(st);
 	stop_t200(st, 19);
 	FsmDelTimer(&st->l2.t203, 19);
-	L2L3(st, DL_RELEASE | INDICATION, NULL);
+	st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
 	FsmChangeState(fi, ST_L2_4);
 }
 
@@ -1614,14 +1627,14 @@
 	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
 	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
 	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
-	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
+	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
 	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
 	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
-	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
-	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
-	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
-	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
-	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
+	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
+	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
+	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
+	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
 };
 
 #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
@@ -1630,8 +1643,8 @@
 isdnl2_l1l2(struct PStack *st, int pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *datap;
-	u_int ret = 1, len;
+	u_char *datap;
+	int ret = 1, len;
 	int c = 0;
 
 	switch (pr) {
@@ -1682,9 +1695,6 @@
 			if (ret)
 				FreeSkb(skb);
 			break;
-		case (PH_DATA | CONFIRM):
-			dev_kfree_skb(skb);
-			break;
 		case (PH_PULL | CONFIRM):
 			FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
 			break;
@@ -1736,12 +1746,12 @@
 					test_bit(FLG_ORIG, &st->l2.flag)) {
 					test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
 				}
-				L2L1(st, PH_ACTIVATE, NULL);
+				st->l2.l2l1(st, PH_ACTIVATE, NULL);
 			}
 			break;
 		case (DL_RELEASE | REQUEST):
 			if (test_bit(FLG_LAPB, &st->l2.flag)) {
-				L2L1(st, PH_DEACTIVATE, NULL);
+				st->l2.l2l1(st, PH_DEACTIVATE, NULL);
 			}
 			FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
 			break;
@@ -1781,8 +1791,9 @@
 void
 setstack_isdnl2(struct PStack *st, char *debug_id)
 {
-	st->l2.l1l2 = isdnl2_l1l2;
-	st->l2.l3l2 = isdnl2_l3l2;
+	spin_lock_init(&st->l2.lock);
+	st->l1.l1l2 = isdnl2_l1l2;
+	st->l3.l3l2 = isdnl2_l3l2;
 
 	skb_queue_head_init(&st->l2.i_queue);
 	skb_queue_head_init(&st->l2.ui_queue);
@@ -1810,13 +1821,13 @@
 	switch (pr) {
 		case (DL_DATA | REQUEST):
 		case (DL_UNIT_DATA | REQUEST):
-			L2L1(st, PH_DATA | REQUEST, arg);
+			st->l2.l2l1(st, PH_DATA | REQUEST, arg);
 			break;
 		case (DL_ESTABLISH | REQUEST):
-			L2L1(st, PH_ACTIVATE | REQUEST, NULL);
+			st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
 			break;
 		case (DL_RELEASE | REQUEST):
-			L2L1(st, PH_DEACTIVATE | REQUEST, NULL);
+			st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
 			break;
 	}
 }
@@ -1824,7 +1835,7 @@
 void
 setstack_transl2(struct PStack *st)
 {
-	st->l2.l3l2 = transl2_l3l2;
+	st->l3.l3l2 = transl2_l3l2;
 }
 
 void
--- diff/drivers/isdn/hisax/isdnl3.c	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/isdnl3.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.17.6.5 2001/09/23 22:24:49 kai Exp $
+/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -20,7 +20,7 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.17.6.5 $";
+const char *l3_revision = "$Revision: 2.22.2.3 $";
 
 static struct Fsm l3fsm;
 
@@ -77,11 +77,11 @@
 	va_end(args);
 }
 
-u8 *
-findie(u8 * p, int size, u8 ie, int wanted_set)
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
 {
 	int l, codeset, maincodeset;
-	u8 *pend = p + size;
+	u_char *pend = p + size;
 
 	/* skip protocol discriminator, callref and message type */
 	p++;
@@ -123,7 +123,7 @@
 }
 
 int
-getcallref(u8 * p)
+getcallref(u_char * p)
 {
 	int l, cr = 0;
 
@@ -162,7 +162,7 @@
 static void
 L3ExpireTimer(struct L3Timer *t)
 {
-	t->pc->st->l3.l4l3(t->pc->st, t->event, t->pc);
+	t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
 }
 
 void
@@ -354,7 +354,7 @@
 	st->l3.l3m.printdebug = l3m_debug;
         FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
 	strcpy(st->l3.debug_id, "L3DC ");
-	st->l3.l4l3_proto = no_l3_proto_spec;
+	st->lli.l4l3_proto = no_l3_proto_spec;
 
 #ifdef	CONFIG_HISAX_EURO
 	if (st->protocol == ISDN_PTYPE_EURO) {
@@ -372,13 +372,13 @@
 	} else
 #endif
 	if (st->protocol == ISDN_PTYPE_LEASED) {
-		st->l3.l4l3 = no_l3_proto;
-		st->l3.l2l3 = no_l3_proto;
+		st->lli.l4l3 = no_l3_proto;
+		st->l2.l2l3 = no_l3_proto;
                 st->l3.l3ml3 = no_l3_proto;
 		printk(KERN_INFO "HiSax: Leased line mode\n");
 	} else {
-		st->l3.l4l3 = no_l3_proto;
-		st->l3.l2l3 = no_l3_proto;
+		st->lli.l4l3 = no_l3_proto;
+		st->l2.l2l3 = no_l3_proto;
                 st->l3.l3ml3 = no_l3_proto;
 		sprintf(tmp, "protocol %s not supported",
 			(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -392,7 +392,7 @@
 
 void
 isdnl3_trans(struct PStack *st, int pr, void *arg) {
-	L3L2(st, pr, arg);
+	st->l3.l3l2(st, pr, arg);
 }
 
 void
@@ -423,7 +423,7 @@
 	st->l3.l3m.userint = 0;
 	st->l3.l3m.printdebug = l3m_debug;
 	strcpy(st->l3.debug_id, "L3BC ");
-	st->l3.l4l3 = isdnl3_trans;
+	st->lli.l4l3 = isdnl3_trans;
 }
 
 #define DREL_TIMER_VALUE 40000
@@ -434,7 +434,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
-	L3L2(st, DL_ESTABLISH | REQUEST, NULL);
+	st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -446,7 +446,7 @@
 
 	FsmChangeState(fi, ST_L3_LC_ESTAB);
 	while ((skb = skb_dequeue(&st->l3.squeue))) {
-		L3L2(st, DL_DATA | REQUEST, skb);
+		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
 		dequeued++;
 	}
 	if ((!st->l3.proc) &&  dequeued) {
@@ -467,7 +467,7 @@
 	FsmDelTimer(&st->l3.l3m_timer, 51);
 	FsmChangeState(fi, ST_L3_LC_ESTAB);
 	while ((skb = skb_dequeue(&st->l3.squeue))) {
-		L3L2(st, DL_DATA | REQUEST, skb);
+		st->l3.l3l2(st, DL_DATA | REQUEST, skb);
 		dequeued++;
 	}
 	if ((!st->l3.proc) &&  dequeued) {
@@ -511,7 +511,7 @@
 		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
 	} else {
 		FsmChangeState(fi, ST_L3_LC_REL_WAIT);
-		L3L2(st, DL_RELEASE | REQUEST, NULL);
+		st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
 	}
 }
 
@@ -564,7 +564,7 @@
 	switch (pr) {
 		case (DL_DATA | REQUEST):
 			if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
-				L3L2(st, pr, arg);
+				st->l3.l3l2(st, pr, arg);
 			} else {
 				struct sk_buff *skb = arg;
 
--- diff/drivers/isdn/hisax/isurf.c	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/isdn/hisax/isurf.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isurf.c,v 1.10.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
  *
  * low level stuff for Siemens I-Surf/I-Talk cards
  *
@@ -19,7 +19,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.10.6.2 $";
+static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -35,20 +35,20 @@
 #define ISURF_IOMEM_SIZE	0x400
 /* Interface functions */
 
-static u8
-ReadISAC(struct IsdnCardState *cs, u8 offset)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
 	return (readb(cs->hw.isurf.isac + offset));
 }
 
 static void
-WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writeb(value, cs->hw.isurf.isac + offset); mb();
 }
 
 static void
-ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	register int i;
 	for (i = 0; i < size; i++)
@@ -56,7 +56,7 @@
 }
 
 static void
-WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	register int i;
 	for (i = 0; i < size; i++){
@@ -64,44 +64,33 @@
 	}
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = ReadISAC,
-	.write_reg  = WriteISAC,
-	.read_fifo  = ReadISACfifo,
-	.write_fifo = WriteISACfifo,
-};
-
 /* ISAR access routines
  * mode = 0 access with IRQ on
  * mode = 1 access with IRQ off
  * mode = 2 access with IRQ off and using last offset
  */
   
-static u8
-ReadISAR(struct IsdnCardState *cs, int mode, u8 offset)
+static u_char
+ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
 {	
 	return(readb(cs->hw.isurf.isar + offset));
 }
 
 static void
-WriteISAR(struct IsdnCardState *cs, int mode, u8 offset, u8 value)
+WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
 {
 	writeb(value, cs->hw.isurf.isar + offset);mb();
 }
 
-static struct bc_hw_ops isar_ops = {
-	.read_reg  = ReadISAR,
-	.write_reg = WriteISAR,
-};
-
 static irqreturn_t
 isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_char val;
 	int cnt = 5;
+	u_long flags;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
       Start_ISAR:
 	if (val & ISAR_IRQSTA)
@@ -129,151 +118,190 @@
 	writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
 	writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
 	writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
+void
+release_io_isurf(struct IsdnCardState *cs)
+{
+	release_region(cs->hw.isurf.reset, 1);
+	iounmap((unsigned char *)cs->hw.isurf.isar);
+	release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
+}
+
 static void
-reset_isurf(struct IsdnCardState *cs, u8 chips)
+reset_isurf(struct IsdnCardState *cs, u_char chips)
 {
 	printk(KERN_INFO "ISurf: resetting card\n");
 
 	byteout(cs->hw.isurf.reset, chips); /* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
+	mdelay(10);
 	byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
+	mdelay(10);
+}
+
+static int
+ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_isurf(cs, ISURF_RESET);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_isurf(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_isurf(cs, ISURF_RESET);
+			clear_pending_isac_ints(cs);
+			writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
+			initisac(cs);
+			initisar(cs);
+			/* Reenable ISAC IRQ */
+			cs->writeisac(cs, ISAC_MASK, 0);
+			/* RESET Receiver and Transmitter */
+			cs->writeisac(cs, ISAC_CMDR, 0x41);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 static int
 isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
 	int ret;
+	u_long flags;
 
 	if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
 		ret = isar_auxcmd(cs, ic);
+		spin_lock_irqsave(&cs->lock, flags);
 		if (!ret) {
 			reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
 				ISURF_ARCOFI_RESET);
 			initisac(cs);
+			cs->writeisac(cs, ISAC_MASK, 0);
+			cs->writeisac(cs, ISAC_CMDR, 0x41);
 		}
+		spin_unlock_irqrestore(&cs->lock, flags);
 		return(ret);
 	}
 	return(isar_auxcmd(cs, ic));
 }
 
-static void
-isurf_init(struct IsdnCardState *cs)
-{
-	writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT);
-	initisac(cs);
-	initisar(cs);
-}
-
-static int
-isurf_reset(struct IsdnCardState *cs)
-{
-	reset_isurf(cs, ISURF_RESET);
-	return 0;
-}
-
-static struct card_ops isurf_ops = {
-	.init     = isurf_init,
-	.reset    = isurf_reset,
-	.release  = hisax_release_resources,
-	.irq_func = isurf_interrupt,
-};
-
 #ifdef __ISAPNP__
-static struct pnp_card *pnp_surf __devinitdata = NULL;
+static struct pnp_card *pnp_c __initdata = NULL;
 #endif
 
-static int __init
-isurf_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	unsigned long phymem;
-
-	phymem = card->para[2];
-	cs->hw.isurf.reset = card->para[1];
-	cs->irq = card->para[0];
-
-	if (!request_io(&cs->rs, cs->hw.isurf.reset, 1, "isurf isdn"))
-		goto err;
-
-	cs->hw.isurf.isar = request_mmio(&cs->rs, phymem, ISURF_IOMEM_SIZE,
-					 "isurf iomem");
-	if (!cs->hw.isurf.isar)
-		goto err;
-
-	cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
-	printk(KERN_INFO "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
-	       cs->hw.isurf.reset, phymem, cs->irq);
-
-	cs->auxcmd = &isurf_auxcmd;
-	cs->card_ops = &isurf_ops;
-	cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
-	cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
-	reset_isurf(cs, ISURF_RESET);
-	__set_bit(HW_ISAR, &cs->HW_Flags);
-	isac_setup(cs, &isac_ops);
-	if (isar_setup(cs, &isar_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
 int __init
 setup_isurf(struct IsdnCard *card)
 {
+	int ver;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, ISurf_revision);
 	printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
 	
+ 	if (cs->typ != ISDN_CTYPE_ISURF)
+ 		return(0);
+	if (card->para[1] && card->para[2]) {
+		cs->hw.isurf.reset = card->para[1];
+		cs->hw.isurf.phymem = card->para[2];
+		cs->irq = card->para[0];
+	} else {
 #ifdef __ISAPNP__
-	if (!card->para[1] || !card->para[2]) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
-	
-		card->cs->subtyp = 0;
-		if ((pb = pnp_find_card(
-			     ISAPNP_VENDOR('S', 'I', 'E'),
-			     ISAPNP_FUNCTION(0x0010), pnp_surf))) {
-			pnp_surf = pb;
-			pd = NULL;
-			if (!(pd = pnp_find_dev(pnp_surf,
-						ISAPNP_VENDOR('S', 'I', 'E'),
-						ISAPNP_FUNCTION(0x0010), pd))) {
-				printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
-				return (0);
-			}
-			if (pnp_device_attach(pd) < 0) {
-				printk(KERN_ERR "ISurfPnP: attach failed\n");
-				return 0;
-			}
-			if (pnp_activate_dev(pd) < 0) {
-				printk(KERN_ERR "ISurfPnP: activate failed\n");
-				pnp_device_detach(pd);
-				return 0;
-			}
-			if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0) || !pnp_port_valid(pd, 1)) {
-				printk(KERN_ERR "ISurfPnP:some resources are missing %ld/%lx/%lx\n",
-				       pnp_irq(pd, 0), pnp_port_start(pd, 0), pnp_port_start(pd, 1));
-				pnp_device_detach(pd);
+		if (isapnp_present()) {
+			struct pnp_dev *pnp_d = NULL;
+			int err;
+
+			cs->subtyp = 0;
+			if ((pnp_c = pnp_find_card(
+				ISAPNP_VENDOR('S', 'I', 'E'),
+				ISAPNP_FUNCTION(0x0010), pnp_c))) {
+				if (!(pnp_d = pnp_find_dev(pnp_c,
+					ISAPNP_VENDOR('S', 'I', 'E'),
+					ISAPNP_FUNCTION(0x0010), pnp_d))) {
+					printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
+					return (0);
+				}
+				pnp_disable_dev(pnp_d);
+				err = pnp_activate_dev(pnp_d);
+				cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
+				cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
+				cs->irq = pnp_irq(pnp_d, 0);
+				if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
+					printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
+						cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
+					pnp_disable_dev(pnp_d);
+					return(0);
+				}
+			} else {
+				printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
 				return(0);
 			}
-			card->para[1] = pnp_port_start(pd, 0);
-			card->para[2] = pnp_port_start(pd, 1);
-			card->para[0] = pnp_irq(pd, 0);
 		} else {
-			printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
-			return 0;
+			printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
+			return(0);
 		}
-	}
+#else
+		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
+			CardType[card->typ]);
+		return (0);
 #endif
-	if (isurf_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	}
+	if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
+		printk(KERN_WARNING
+			"HiSax: %s config port %x already in use\n",
+			CardType[card->typ],
+			cs->hw.isurf.reset);
+			return (0);
+	}
+	if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
+		printk(KERN_WARNING
+			"HiSax: %s memory region %lx-%lx already in use\n",
+			CardType[card->typ],
+			cs->hw.isurf.phymem,
+			cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
+		release_region(cs->hw.isurf.reset, 1);
+		return (0);
+	}
+	cs->hw.isurf.isar =
+		(unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
+	cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
+	printk(KERN_INFO
+	       "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
+	       cs->hw.isurf.reset,
+	       cs->hw.isurf.phymem,
+	       cs->irq);
+
+	setup_isac(cs);
+	cs->cardmsg = &ISurf_card_msg;
+	cs->irq_func = &isurf_interrupt;
+	cs->auxcmd = &isurf_auxcmd;
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
+	cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
+	test_and_set_bit(HW_ISAR, &cs->HW_Flags);
+	ISACVersion(cs, "ISurf:");
+	cs->BC_Read_Reg = &ReadISAR;
+	cs->BC_Write_Reg = &WriteISAR;
+	cs->BC_Send_Data = &isar_fill_fifo;
+	ver = ISARVersion(cs, "ISurf:");
+	if (ver < 0) {
+		printk(KERN_WARNING
+			"ISurf: wrong ISAR version (ret = %d)\n", ver);
+		release_io_isurf(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/ix1_micro.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/ix1_micro.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 2.10.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for ITK ix1-micro Rev.2 isdn cards
  * derived from the original file teles3.c from Karsten Keil
@@ -25,8 +25,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.10.6.2 $";
-static spinlock_t ix1_micro_lock = SPIN_LOCK_UNLOCKED;
+const char *ix1_revision = "$Revision: 2.12.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -40,107 +39,137 @@
 
 #define TIMEOUT 50
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&ix1_micro_lock, flags);
-	byteout(cs->hw.ix1.isac_ale, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&ix1_micro_lock, flags);
 	return (ret);
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ix1_micro_lock, flags);
-	byteout(cs->hw.ix1.isac_ale, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&ix1_micro_lock, flags);
+	byteout(ale, off);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.ix1.isac_ale, off);
-	insb(adr, data, size);
+	byteout(ale, off);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.ix1.isac_ale, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.ix1.isac, offset);
+	return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.ix1.isac, offset, value);
+	writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.ix1.isac, 0, data, size);
+	readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.ix1.isac, 0, data, size);
+	writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs, cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.ix1.hscx_ale,
+			cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.ix1.hscx_ale,
+		 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	readfifo(cs, cs->hw.ix1.hscx, hscx ? 0x40 : 0, data, size);
+#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
+		cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
+		cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
+		cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
+		cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
+	writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
+	writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+void
+release_io_ix1micro(struct IsdnCardState *cs)
 {
-	writefifo(cs, cs->hw.ix1.hscx, hscx ? 0x40 : 0, data, size);
+	if (cs->hw.ix1.cfg_reg)
+		release_region(cs->hw.ix1.cfg_reg, 4);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static int
+static void
 ix1_reset(struct IsdnCardState *cs)
 {
 	int cnt;
@@ -152,37 +181,32 @@
 		HZDELAY(1);	/* wait >=10 ms */
 	}
 	byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
-	return 0;
 }
 
-static struct card_ops ix1_ops = {
-	.init     = inithscxisac,
-	.reset    = ix1_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static int __init
-ix1_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static int
+ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	cs->irq             = card->para[0];
-	cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
-	cs->hw.ix1.isac     = card->para[1] + ISAC_DATA_OFFSET;
-	cs->hw.ix1.hscx     = card->para[1] + HSCX_DATA_OFFSET;
-	cs->hw.ix1.cfg_reg  = card->para[1];
-	if (!request_io(&cs->rs, cs->hw.ix1.cfg_reg, 4, "ix1micro cfg"))
-		goto err;
-	
-	printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
-	       CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg);
-	ix1_reset(cs);
-	cs->card_ops = &ix1_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			ix1_reset(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_ix1micro(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			ix1_reset(cs);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 #ifdef __ISAPNP__
@@ -196,7 +220,7 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *idev = &itk_ids[0];
+static struct isapnp_device_id *ipid __initdata = &itk_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
@@ -204,64 +228,91 @@
 int __init
 setup_ix1micro(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, ix1_revision);
 	printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_IX1MICROR2)
+		return (0);
 
-	if (card->para[1]) {
-		if (ix1_probe(card->cs, card))
-			return 0;
-		return 1;
-	}
 #ifdef __ISAPNP__
-	if (isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
-
-		while(idev->card_vendor) {
-			if ((pb = pnp_find_card(idev->card_vendor,
-						idev->card_device,
-						pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       idev->vendor,
-						       idev->function,
-						       pd))) {
+	if (!card->para[1] && isapnp_present()) {
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
+
 					printk(KERN_INFO "HiSax: %s detected\n",
-						(char *)idev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "ITK PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "ITK PnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_port_valid(pd, 0) || !pnp_irq_valid(pd, 0)) {
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+					if (!card->para[0] || !card->para[1]) {
 						printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
-							pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
 						return(0);
 					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
-					if (ix1_probe(card->cs, card))
-						return 0;
-					return 1;
+					break;
 				} else {
 					printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
 				}
 			}
-			idev++;
-			pnp_c=NULL;
+			ipid++;
+			pnp_c = NULL;
 		} 
-		if (!idev->card_vendor) {
+		if (!ipid->card_vendor) {
 			printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
+			return(0);
 		}
 	}
 #endif
-	return 0;
+	/* IO-Ports */
+	cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
+	cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
+	cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
+	cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
+	cs->hw.ix1.cfg_reg = card->para[1];
+	cs->irq = card->para[0];
+	if (cs->hw.ix1.cfg_reg) {
+		if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
+			printk(KERN_WARNING
+			  "HiSax: %s config port %x-%x already in use\n",
+			       CardType[card->typ],
+			       cs->hw.ix1.cfg_reg,
+			       cs->hw.ix1.cfg_reg + 4);
+			return (0);
+		}
+	}
+	printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
+		CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg);
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &ix1_card_msg;
+	cs->irq_func = &ix1micro_interrupt;
+	ISACVersion(cs, "ix1-Micro:");
+	if (HscxVersion(cs, "ix1-Micro:")) {
+		printk(KERN_WARNING
+		    "ix1-Micro: wrong HSCX versions check IO address\n");
+		release_io_ix1micro(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/jade.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/jade.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: jade.c,v 1.6.6.3 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $
  *
  * JADE stuff (derived from original hscx.c)
  *
@@ -18,38 +18,17 @@
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
-static spinlock_t jade_lock = SPIN_LOCK_UNLOCKED;
 
-static inline u8
-jade_read_reg(struct IsdnCardState *cs, int jade, u8 addr)
-{
-	return cs->bc_hw_ops->read_reg(cs, jade, addr);
-}
-
-static inline void
-jade_write_reg(struct IsdnCardState *cs, int jade, u8 addr, u8 val)
-{
-	cs->bc_hw_ops->write_reg(cs, jade, addr, val);
-}
-
-static inline void
-jade_write_fifo(struct BCState *bcs, u8 *p, int len)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	cs->bc_hw_ops->write_fifo(cs, bcs->unit, p, len);
-}
-
-static int
+int __init
 JadeVersion(struct IsdnCardState *cs, char *s)
 {
     int ver,i;
     int to = 50;
-    jade_write_reg(cs, -1, 0x50, 0x19);
+    cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
     i=0;
     while (to) {
     	udelay(1);
-	ver = jade_read_reg(cs, -1, 0x60);
+	ver = cs->BC_Read_Reg(cs, -1, 0x60);
 	to--;
 	if (ver)
     	    break;
@@ -61,39 +40,36 @@
     /* Wait for the JADE */
     udelay(10);
     /* Read version */
-    ver = jade_read_reg(cs, -1, 0x60);
+    ver = cs->BC_Read_Reg(cs, -1, 0x60);
     printk(KERN_INFO "%s JADE version: %d\n", s, ver);
     return (1);
 }
 
 /* Write to indirect accessible jade register set */
 static void
-jade_write_indirect(struct IsdnCardState *cs, u8 reg, u8 value)
+jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
 {
     int to = 50;
-    unsigned long flags;
-    u8 ret;
-    spin_lock_irqsave(&jade_lock, flags);
+    u_char ret;
+
     /* Write the data */
-    jade_write_reg(cs, -1, COMM_JADE+1, value);
+    cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value);
     /* Say JADE we wanna write indirect reg 'reg' */
-    jade_write_reg(cs, -1, COMM_JADE, reg);
+    cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
     to = 50;
     /* Wait for RDY goes high */
     while (to) {
     	udelay(1);
-	ret = jade_read_reg(cs, -1, COMM_JADE);
+	ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
 	to--;
 	if (ret & 1)
 	    /* Got acknowledge */
 	    break;
 	if (!to) {
-	    spin_unlock_irqrestore(&jade_lock, flags);
     	    printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
 	    return;
 	}
     }
-    spin_unlock_irqrestore(&jade_lock, flags);
 }
 
 
@@ -102,7 +78,7 @@
 modejade(struct BCState *bcs, int mode, int bc)
 {
     struct IsdnCardState *cs = bcs->cs;
-    int jade = bcs->unit;
+    int jade = bcs->hw.hscx.hscx;
 
     if (cs->debug & L1_DEB_HSCX) {
 	char tmp[40];
@@ -113,75 +89,103 @@
     bcs->mode = mode;
     bcs->channel = bc;
 	
-    jade_write_reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00));
-    jade_write_reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF));
-    jade_write_reg(cs, jade, jade_HDLC_CCR1, 0x00);
+    cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00));
+    cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF));
+    cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
 
     jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
     jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
     jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
     jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
 
-    jade_write_reg(cs, jade, jade_HDLC_XCCR, 0x07);
-    jade_write_reg(cs, jade, jade_HDLC_RCCR, 0x07);
+    cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
+    cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
 
     if (bc == 0) {
-	jade_write_reg(cs, jade, jade_HDLC_TSAX, 0x00);
-	jade_write_reg(cs, jade, jade_HDLC_TSAR, 0x00);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
     } else {
-	jade_write_reg(cs, jade, jade_HDLC_TSAX, 0x04);
-	jade_write_reg(cs, jade, jade_HDLC_TSAR, 0x04);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
     }
     switch (mode) {
 	case (L1_MODE_NULL):
-		jade_write_reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
+		cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
 		break;
 	case (L1_MODE_TRANS):
-		jade_write_reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC));
+		cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC));
 		break;
 	case (L1_MODE_HDLC):
-		jade_write_reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC));
+		cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC));
 		break;
     }
     if (mode) {
-	jade_write_reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC));
-	jade_write_reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC));
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
 	/* Unmask ints */
-	jade_write_reg(cs, jade, jade_HDLC_IMR, 0xF8);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
     }
     else
 	/* Mask ints */
-	jade_write_reg(cs, jade, jade_HDLC_IMR, 0x00);
+	cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
 }
 
 static void
 jade_l2l1(struct PStack *st, int pr, void *arg)
 {
+    struct BCState *bcs = st->l1.bcs;
     struct sk_buff *skb = arg;
+    u_long flags;
 
     switch (pr) {
 	case (PH_DATA | REQUEST):
-		xmit_data_req_b(st->l1.bcs, skb);
+		spin_lock_irqsave(&bcs->cs->lock, flags);
+		if (bcs->tx_skb) {
+			skb_queue_tail(&bcs->squeue, skb);
+		} else {
+			bcs->tx_skb = skb;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bcs->hw.hscx.count = 0;
+			bcs->cs->BC_Send_Data(bcs);
+		}
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
 		break;
 	case (PH_PULL | INDICATION):
-		xmit_pull_ind_b(st->l1.bcs, skb);
+		spin_lock_irqsave(&bcs->cs->lock, flags);
+		if (bcs->tx_skb) {
+			printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
+		} else {
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bcs->tx_skb = skb;
+			bcs->hw.hscx.count = 0;
+			bcs->cs->BC_Send_Data(bcs);
+		}
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
 		break;
 	case (PH_PULL | REQUEST):
-		xmit_pull_req_b(st);
+		if (!bcs->tx_skb) {
+		    test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+		    st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+		} else
+		    test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 		break;
 	case (PH_ACTIVATE | REQUEST):
-		test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-		modejade(st->l1.bcs, st->l1.mode, st->l1.bc);
+		spin_lock_irqsave(&bcs->cs->lock, flags);
+		test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+		modejade(bcs, st->l1.mode, st->l1.bc);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
 		l1_msg_b(st, pr, arg);
 		break;
 	case (PH_DEACTIVATE | REQUEST):
 		l1_msg_b(st, pr, arg);
 		break;
 	case (PH_DEACTIVATE | CONFIRM):
-		test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-		test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-		modejade(st->l1.bcs, 0, st->l1.bc);
-		L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+		spin_lock_irqsave(&bcs->cs->lock, flags);
+		test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		modejade(bcs, 0, st->l1.bc);
+		spin_unlock_irqrestore(&bcs->cs->lock, flags);
+		st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 		break;
     }
 }
@@ -189,14 +193,53 @@
 void
 close_jadestate(struct BCState *bcs)
 {
-	modejade(bcs, 0, bcs->channel);
-	bc_close(bcs);
+    modejade(bcs, 0, bcs->channel);
+    if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+	if (bcs->hw.hscx.rcvbuf) {
+		kfree(bcs->hw.hscx.rcvbuf);
+		bcs->hw.hscx.rcvbuf = NULL;
+	}
+	if (bcs->blog) {
+		kfree(bcs->blog);
+		bcs->blog = NULL;
+	}
+	skb_queue_purge(&bcs->rqueue);
+	skb_queue_purge(&bcs->squeue);
+	if (bcs->tx_skb) {
+		dev_kfree_skb_any(bcs->tx_skb);
+		bcs->tx_skb = NULL;
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	}
+    }
 }
 
 static int
 open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	return bc_open(bcs);;
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+			       "HiSax: No memory for hscx.rcvbuf\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax: No memory for bcs->blog\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hscx.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
 }
 
 
@@ -207,74 +250,69 @@
 	if (open_jadestate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = jade_l2l1;
+	st->l2.l2l1 = jade_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
 	return (0);
 }
 
-static void jade_fill_fifo(struct BCState *bcs);
-
-static struct bc_l1_ops jade_l1_ops = {
-	.fill_fifo = jade_fill_fifo,
-	.open      = setstack_jade,
-	.close     = close_jadestate,
-};
-
 void __init
-initjade(struct IsdnCardState *cs)
+clear_pending_jade_ints(struct IsdnCardState *cs)
 {
 	int val;
+	char tmp[64];
 
-	cs->bc_l1_ops = &jade_l1_ops;
-	cs->bcs[0].unit = 0;
-	cs->bcs[1].unit = 1;
-
-	jade_write_reg(cs, 0, jade_HDLC_IMR, 0x00);
-	jade_write_reg(cs, 1, jade_HDLC_IMR, 0x00);
-
-	val = jade_read_reg(cs, 1, jade_HDLC_ISR);
-	debugl1(cs, "jade B ISTA %x", val);
-	val = jade_read_reg(cs, 0, jade_HDLC_ISR);
-	debugl1(cs, "jade A ISTA %x", val);
-	val = jade_read_reg(cs, 1, jade_HDLC_STAR);
-	debugl1(cs, "jade B STAR %x", val);
-	val = jade_read_reg(cs, 0, jade_HDLC_STAR);
-	debugl1(cs, "jade A STAR %x", val);
+	cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
+	cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
 
+	val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
+	sprintf(tmp, "jade B ISTA %x", val);
+	debugl1(cs, tmp);
+	val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
+	sprintf(tmp, "jade A ISTA %x", val);
+	debugl1(cs, tmp);
+	val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
+	sprintf(tmp, "jade B STAR %x", val);
+	debugl1(cs, tmp);
+	val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
+	sprintf(tmp, "jade A STAR %x", val);
+	debugl1(cs, tmp);
 	/* Unmask ints */
-	jade_write_reg(cs, 0, jade_HDLC_IMR, 0xF8);
-	jade_write_reg(cs, 1, jade_HDLC_IMR, 0xF8);
+	cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
+	cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
+}
+
+void __init
+initjade(struct IsdnCardState *cs)
+{
+	cs->bcs[0].BC_SetStack = setstack_jade;
+	cs->bcs[1].BC_SetStack = setstack_jade;
+	cs->bcs[0].BC_Close = close_jadestate;
+	cs->bcs[1].BC_Close = close_jadestate;
+	cs->bcs[0].hw.hscx.hscx = 0;
+	cs->bcs[1].hw.hscx.hscx = 1;
 
 	/* Stop DSP audio tx/rx */
 	jade_write_indirect(cs, 0x11, 0x0f);
 	jade_write_indirect(cs, 0x17, 0x2f);
 
 	/* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
-	jade_write_reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
-	jade_write_reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
+	cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
+	cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
 	/* Power down, 1-Idle, RxTx least significant bit first */
-	jade_write_reg(cs, 0, jade_HDLC_CCR0, 0x00);
-	jade_write_reg(cs, 1, jade_HDLC_CCR0, 0x00);
+	cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
+	cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
 	/* Mask all interrupts */
-	jade_write_reg(cs, 0, jade_HDLC_IMR,  0x00);
-	jade_write_reg(cs, 1, jade_HDLC_IMR,  0x00);
+	cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR,  0x00);
+	cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR,  0x00);
 	/* Setup host access to hdlc controller */
 	jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2));
 	/* Unmask HDLC int (don´t forget DSP int later on)*/
-	jade_write_reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
+	cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
 
 	/* once again TRANSPARENT */	
 	modejade(cs->bcs, 0, 0);
 	modejade(cs->bcs + 1, 0, 0);
 }
 
-int
-jade_setup(struct IsdnCardState *cs, struct bc_hw_ops *jade_ops)
-{
-	cs->bc_hw_ops = jade_ops;
-	return JadeVersion(cs, "HiSax:");
-}
-
-#include "jade_irq.c"
--- diff/drivers/isdn/hisax/jade.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/jade.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: jade.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $
  *
  * JADE specific defines
  *
@@ -127,10 +127,9 @@
 #define	jade_TXAUDIOCH1CFG				0x17
 #define	jade_TXAUDIOCH2CFG				0x1A
 
-extern void jade_sched_event(struct BCState *bcs, int event);
+extern int JadeVersion(struct IsdnCardState *cs, char *s);
 extern void modejade(struct BCState *bcs, int mode, int bc);
+extern void clear_pending_jade_ints(struct IsdnCardState *cs);
 extern void initjade(struct IsdnCardState *cs);
-extern void jade_int_main(struct IsdnCardState *cs, u8 val, int jade);
-extern int  jade_setup(struct IsdnCardState *cs, struct bc_hw_ops *jade_ops);
 
 #endif	/* __JADE_H__ */
--- diff/drivers/isdn/hisax/jade_irq.c	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/jade_irq.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: jade_irq.c,v 1.5.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
  *
  * Low level JADE IRQ stuff (derived from original hscx_irq.c)
  *
@@ -15,7 +15,7 @@
 {
   	int to = 50;
   	int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
-  	while ((jade_read_reg(cs, jade, jade_HDLC_STAR) & mask) && to) {
+  	while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
   		udelay(1);
   		to--;
   	}
@@ -25,17 +25,16 @@
 
 
 static inline void
-waitforXFW(struct BCState *bcs)
+waitforXFW(struct IsdnCardState *cs, int jade)
 {
+  	/* Does not work on older jade versions, don't care */
 }
 
 static inline void
-WriteJADECMDR(struct BCState *bcs, int reg, u8 data)
+WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
 {
-	int jade = bcs->unit;
-
-	waitforCEC(bcs->cs, jade, reg);
-	jade_write_reg(bcs->cs, jade, reg, data);
+	waitforCEC(cs, jade, reg);
+	WRITEJADE(cs, jade, reg, data);
 }
 
 
@@ -43,33 +42,80 @@
 static void
 jade_empty_fifo(struct BCState *bcs, int count)
 {
-	recv_empty_fifo_b(bcs, count);
-	WriteJADECMDR(bcs, jade_HDLC_RCMD, jadeRCMD_RMC);
+	u_char *ptr;
+	struct IsdnCardState *cs = bcs->cs;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "jade_empty_fifo");
+
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "jade_empty_fifo: incoming packet too large");
+		WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+	WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "jade_empty_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static void
 jade_fill_fifo(struct BCState *bcs)
 {
+	struct IsdnCardState *cs = bcs->cs;
 	int more, count;
 	int fifo_size = 32;
-	unsigned char *p;
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "jade_fill_fifo");
 
-	p = xmit_fill_fifo_b(bcs, fifo_size, &count, &more);
-	if (!p)
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
 		return;
 
-	waitforXFW(bcs);
-	jade_write_fifo(bcs, p, count);
-	WriteJADECMDR(bcs, jade_HDLC_XCMD,
-		      more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > fifo_size) {
+		more = !0;
+		count = fifo_size;
+	} else
+		count = bcs->tx_skb->len;
+
+	waitforXFW(cs, bcs->hw.hscx.hscx);
+	ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+	WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "jade_fill_fifo %c cnt %d",
+			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 
 static inline void
-jade_interrupt(struct IsdnCardState *cs, u8 val, u8 jade)
+jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
 {
-	u8 r;
+	u_char r;
 	struct BCState *bcs = cs->bcs + jade;
+	struct sk_buff *skb;
 	int fifo_size = 32;
 	int count;
 	int i_jade = (int) jade; /* To satisfy the compiler */
@@ -78,7 +124,7 @@
 		return;
 
 	if (val & 0x80) {	/* RME */
-		r = jade_read_reg(cs, i_jade, jade_HDLC_RSTA);
+		r = READJADE(cs, i_jade, jade_HDLC_RSTA);
 		if ((r & 0xf0) != 0xa0) {
 			if (!(r & 0x80))
 				if (cs->debug & L1_DEB_WARN)
@@ -89,34 +135,72 @@
 			if (!(r & 0x20))
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "JADE %c CRC error", 'A'+jade);
-			WriteJADECMDR(bcs, jade_HDLC_RCMD, jadeRCMD_RMC);
-			bcs->rcvidx = 0;
+			WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
 		} else {
-			count = jade_read_reg(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
+			count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
 			if (count == 0)
 				count = fifo_size;
-
 			jade_empty_fifo(bcs, count);
-			recv_rme_b(bcs);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug & L1_DEB_HSCX_FIFO)
+					debugl1(cs, "HX Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
 		}
+		bcs->hw.hscx.rcvidx = 0;
+		schedule_event(bcs, B_RCVBUFREADY);
 	}
 	if (val & 0x40) {	/* RPF */
 		jade_empty_fifo(bcs, fifo_size);
-		recv_rpf_b(bcs);
+		if (bcs->mode == L1_MODE_TRANS) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(fifo_size)))
+				printk(KERN_WARNING "HiSax: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			schedule_event(bcs, B_RCVBUFREADY);
+		}
 	}
 	if (val & 0x10) {	/* XPR */
-		xmit_xpr_b(bcs);
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				jade_fill_fifo(bcs);
+				return;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.hscx.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_irq(bcs->tx_skb);
+				bcs->hw.hscx.count = 0;
+				bcs->tx_skb = NULL;
+			}
+		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.hscx.count = 0;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			jade_fill_fifo(bcs);
+		} else {
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
 	}
 }
 
-static void
-reset_xmit(struct BCState *bcs)
-{
-	WriteJADECMDR(bcs, jade_HDLC_XCMD, jadeXCMD_XRES);
-}
-
-void
-jade_int_main(struct IsdnCardState *cs, u8 val, int jade)
+static inline void
+jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
 {
 	struct BCState *bcs;
 	bcs = cs->bcs + jade;
@@ -126,7 +210,23 @@
 		val &= ~jadeISR_RFO;
 	}
 	if (val & jadeISR_XDU) {
-		xmit_xdu_b(bcs, reset_xmit);
+		/* relevant in HDLC mode only */
+		/* don't reset XPR here */
+		if (bcs->mode == 1)
+			jade_fill_fifo(bcs);
+		else {
+			/* Here we lost an TX interrupt, so
+			   * restart transmitting the whole frame.
+			 */
+			if (bcs->tx_skb) {
+			   	skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+				bcs->tx_cnt += bcs->hw.hscx.count;
+				bcs->hw.hscx.count = 0;
+			}
+			WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
+		}
 	}
 	if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
 		if (cs->debug & L1_DEB_HSCX)
--- diff/drivers/isdn/hisax/l3_1tr6.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/l3_1tr6.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.13.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * German 1TR6 D-channel protocol
  *
@@ -19,7 +19,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.13.6.2 $";
+const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
 	*ptr++ = dis; \
@@ -28,10 +28,10 @@
 	*ptr++ = mty
 
 static void
-l3_1TR6_message(struct l3_process *pc, u8 mt, u8 pd)
+l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
 {
 	struct sk_buff *skb;
-	u8 *p;
+	u_char *p;
 
 	if (!(skb = l3_alloc_skb(4)))
 		return;
@@ -41,7 +41,7 @@
 }
 
 static void
-l3_1tr6_release_req(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	StopAllL3Timer(pc);
 	newl3state(pc, 19);
@@ -50,7 +50,7 @@
 }
 
 static void
-l3_1tr6_invalid(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
@@ -59,7 +59,7 @@
 }
 
 static void
-l3_1tr6_error(struct l3_process *pc, u8 *msg, struct sk_buff *skb)
+l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
 {
 	dev_kfree_skb(skb);
 	if (pc->st->l3.debug & L3_DEB_WARN)
@@ -68,14 +68,14 @@
 }
 
 static void
-l3_1tr6_setup_req(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[128];
-	u8 *p = tmp;
-	u8 *teln;
-	u8 *eaz;
-	u8 channel = 0;
+	u_char tmp[128];
+	u_char *p = tmp;
+	u_char *teln;
+	u_char *eaz;
+	u_char channel = 0;
 	int l;
 
 	MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
@@ -157,9 +157,9 @@
 }
 
 static void
-l3_1tr6_setup(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	int bcfound = 0;
 	char tmp[80];
 	struct sk_buff *skb = arg;
@@ -222,15 +222,15 @@
 			l3_debug(pc->st, tmp);
 		}
 		newl3state(pc, 6);
-		L3L4(pc->st, CC_SETUP | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
 	} else
 		release_l3_process(pc);
 }
 
 static void
-l3_1tr6_setup_ack(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 
 	L3DelTimer(&pc->timer);
@@ -252,13 +252,13 @@
 	}
 	dev_kfree_skb(skb);
 	L3AddTimer(&pc->timer, T304, CC_T304);
-	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
-l3_1tr6_call_sent(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 
 	L3DelTimer(&pc->timer);
@@ -284,26 +284,25 @@
 	dev_kfree_skb(skb);
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	newl3state(pc, 3);
-	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
-l3_1tr6_alert(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
 	dev_kfree_skb(skb);
 	L3DelTimer(&pc->timer);	/* T304 */
 	newl3state(pc, 4);
-	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
-l3_1tr6_info(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
-	u_int i;
-	int tmpcharge = 0;
+	u_char *p;
+	int i, tmpcharge = 0;
 	char a_charge[8], tmp[32];
 	struct sk_buff *skb = arg;
 
@@ -316,7 +315,7 @@
 		}
 		if (tmpcharge > pc->para.chargeinfo) {
 			pc->para.chargeinfo = tmpcharge;
-			L3L4(pc->st, CC_CHARGE | INDICATION, pc);
+			pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
 		}
 		if (pc->st->l3.debug & L3_DEB_CHARGE) {
 			sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -329,7 +328,7 @@
 }
 
 static void
-l3_1tr6_info_s2(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
@@ -337,7 +336,7 @@
 }
 
 static void
-l3_1tr6_connect(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
@@ -349,14 +348,14 @@
 	newl3state(pc, 10);
 	dev_kfree_skb(skb);
 	pc->para.chargeinfo = 0;
-	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
-l3_1tr6_rel(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 
 	p = skb->data;
 	if ((p = findie(p, skb->len, WE0_cause, 0))) {
@@ -379,12 +378,12 @@
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
 	l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	release_l3_process(pc);
 }
 
 static void
-l3_1tr6_rel_ack(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
@@ -392,17 +391,16 @@
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
 	release_l3_process(pc);
 }
 
 static void
-l3_1tr6_disc(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
-	u_int i;
-	int tmpcharge = 0;
+	u_char *p;
+	int i, tmpcharge = 0;
 	char a_charge[8], tmp[32];
 
 	StopAllL3Timer(pc);
@@ -415,7 +413,7 @@
 		}
 		if (tmpcharge > pc->para.chargeinfo) {
 			pc->para.chargeinfo = tmpcharge;
-			L3L4(pc->st, CC_CHARGE | INDICATION, pc);
+			pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
 		}
 		if (pc->st->l3.debug & L3_DEB_CHARGE) {
 			sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -448,12 +446,12 @@
 	}
 	dev_kfree_skb(skb);
 	newl3state(pc, 12);
-	L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 
 static void
-l3_1tr6_connect_ack(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 
@@ -465,22 +463,22 @@
 	newl3state(pc, 10);
 	pc->para.chargeinfo = 0;
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
-l3_1tr6_alert_req(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	newl3state(pc, 7);
 	l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
 }
 
 static void
-l3_1tr6_setup_rsp(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[24];
-	u8 *p = tmp;
+	u_char tmp[24];
+	u_char *p = tmp;
 	int l;
 
 	MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
@@ -510,20 +508,20 @@
 }
 
 static void
-l3_1tr6_reset(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
 {
 	release_l3_process(pc);
 }
 
 static void
-l3_1tr6_disconnect_req(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 0x10;
-	u8 clen = 1;
+	u_char cause = 0x10;
+	u_char clen = 1;
 
 	if (pc->para.cause > 0)
 		cause = pc->para.cause;
@@ -555,7 +553,7 @@
 }
 
 static void
-l3_1tr6_t303(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
 {
 	if (pc->N303 > 0) {
 		pc->N303--;
@@ -569,23 +567,23 @@
 }
 
 static void
-l3_1tr6_t304(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3_1tr6_t305(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 0x90;
-	u8 clen = 1;
+	u_char cause = 0x90;
+	u_char clen = 1;
 
 	L3DelTimer(&pc->timer);
 	if (pc->para.cause != NO_CAUSE)
@@ -614,25 +612,25 @@
 }
 
 static void
-l3_1tr6_t310(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3_1tr6_t313(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 0xE6;
 	l3_1tr6_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_CONNECT_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
-l3_1tr6_t308_1(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
@@ -641,28 +639,28 @@
 }
 
 static void
-l3_1tr6_t308_2(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RELEASE_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
 	release_l3_process(pc);
 }
 
 static void
-l3_1tr6_dl_reset(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
 {
         pc->para.cause = CAUSE_LocalProcErr;
         l3_1tr6_disconnect_req(pc, pr, NULL);
-        L3L4(pc->st, CC_SETUP_ERR, pc);
+        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3_1tr6_dl_release(struct l3_process *pc, u8 pr, void *arg)
+l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
 {
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
@@ -755,8 +753,7 @@
 static void
 up1tr6(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	int mt, cr;
+	int i, mt, cr;
 	struct l3_process *proc;
 	struct sk_buff *skb = arg;
 	char tmp[80];
@@ -871,8 +868,7 @@
 static void
 down1tr6(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	int cr;
+	int i, cr;
 	struct l3_process *proc;
 	struct Channel *chan;
 	char tmp[80];
@@ -919,7 +915,7 @@
 static void
 man1tr6(struct PStack *st, int pr, void *arg)
 {
-        u_int i;
+        int i;
         struct l3_process *proc = arg;
  
         if (!proc) {
@@ -949,8 +945,8 @@
 {
 	char tmp[64];
 
-	st->l3.l4l3 = down1tr6;
-	st->l3.l2l3 = up1tr6;
+	st->lli.l4l3 = down1tr6;
+	st->l2.l2l3 = up1tr6;
 	st->l3.l3ml3 = man1tr6;
 	st->l3.N303 = 0;
 
--- diff/drivers/isdn/hisax/l3dss1.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/l3dss1.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.30.6.2 2001/09/23 22:24:49 kai Exp $
+/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * EURO/DSS1 D-channel protocol
  *
@@ -26,8 +26,7 @@
 #include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.30.6.2 $";
-static spinlock_t l3dss1_lock = SPIN_LOCK_UNLOCKED;
+const char *dss1_revision = "$Revision: 2.32.2.3 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -49,13 +48,10 @@
 static unsigned char new_invoke_id(struct PStack *p)
 {
 	unsigned char retval;
-	unsigned long flags;
 	int i;
   
 	i = 32; /* maximum search depth */
 
-	spin_lock_irqsave(&l3dss1_lock, flags);
-
 	retval = p->prot.dss1.last_invoke_id + 1; /* try new id */
 	while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) {
 		p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8;
@@ -68,8 +64,6 @@
 		retval = 0;
 	p->prot.dss1.last_invoke_id = retval;
 	p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7));
-	spin_unlock_irqrestore(&l3dss1_lock, flags);
-
 	return(retval);  
 } /* new_invoke_id */
 
@@ -77,13 +71,11 @@
 /* free a used invoke id */
 /*************************/
 static void free_invoke_id(struct PStack *p, unsigned char id)
-{ unsigned long flags;
+{
 
   if (!id) return; /* 0 = invalid value */
 
-  spin_lock_irqsave(&l3dss1_lock, flags);
   p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7));
-  spin_unlock_irqrestore(&l3dss1_lock, flags);
 } /* free_invoke_id */  
 
 
@@ -136,7 +128,7 @@
 /* and a return result is delivered. id specifies the invoke id.   */
 /*******************************************************************/ 
 static void 
-l3dss1_dummy_return_result(struct PStack *st, int id, u8 *p, u8 nlen)
+l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
 { isdn_ctrl ic;
   struct IsdnCardState *cs;
   struct l3_process *pc = NULL; 
@@ -203,7 +195,7 @@
 /*******************************************************************/ 
 static void 
 l3dss1_dummy_invoke(struct PStack *st, int cr, int id, 
-                    int ident, u8 *p, u8 nlen)
+                    int ident, u_char *p, u_char nlen)
 { isdn_ctrl ic;
   struct IsdnCardState *cs;
   
@@ -227,7 +219,7 @@
 
 static void
 l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
-                      int cr, u8 * p)
+                      int cr, u_char * p)
 {
 	int qd_len = 0;
 	unsigned char nlen = 0, ilen, cp_tag;
@@ -447,7 +439,7 @@
                             pc->prot.dss1.remote_result = 0; /* success */     
                             pc->prot.dss1.invoke_id = 0;
                             pc->redir_result = pc->prot.dss1.remote_result; 
-                            L3L4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -492,7 +484,7 @@
                             pc->prot.dss1.remote_result = err_ret; /* result */
                             pc->prot.dss1.invoke_id = 0; 
                             pc->redir_result = pc->prot.dss1.remote_result; 
-                            L3L4(st, CC_REDIR | INDICATION, pc);  
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);  
                           } /* Deflection error */
                         else
                           l3_debug(st,"return result unknown identifier");
@@ -504,10 +496,10 @@
 }
 
 static void
-l3dss1_message(struct l3_process *pc, u8 mt)
+l3dss1_message(struct l3_process *pc, u_char mt)
 {
 	struct sk_buff *skb;
-	u8 *p;
+	u_char *p;
 
 	if (!(skb = l3_alloc_skb(4)))
 		return;
@@ -517,11 +509,11 @@
 }
 
 static void
-l3dss1_message_cause(struct l3_process *pc, u8 mt, u8 cause)
+l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 
 	MsgHead(p, pc->callref, mt);
@@ -538,10 +530,10 @@
 }
 
 static void
-l3dss1_status_send(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
 
@@ -564,14 +556,14 @@
 }
 
 static void
-l3dss1_msg_without_setup(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
 {
 	/* This routine is called if here was no SETUP made (checks in dss1up and in
 	 * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
 	 * MT_STATUS_ENQUIRE in the NULL state is handled too
 	 */
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
 
@@ -690,7 +682,7 @@
 };
 
 static int
-getmax_ie_len(u8 ie) {
+getmax_ie_len(u_char ie) {
 	int i = 0;
 	while (max_ie_len[i].ie != -1) {
 		if (max_ie_len[i].ie == ie)
@@ -701,7 +693,7 @@
 }
 
 static int
-ie_in_set(struct l3_process *pc, u8 ie, int *checklist) {
+ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
 	int ret = 1;
 
 	while (*checklist != -1) {
@@ -721,13 +713,13 @@
 check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
 {
 	int *cl = checklist;
-	u8 mt;
-	u8 *p, ie;
+	u_char mt;
+	u_char *p, ie;
 	int l, newpos, oldpos;
 	int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
-	u8 codeset = 0;
-	u8 old_codeset = 0;
-	u8 codelock = 1;
+	u_char codeset = 0;
+	u_char old_codeset = 0;
+	u_char codelock = 1;
 	
 	p = skb->data;
 	/* skip cr */
@@ -736,7 +728,7 @@
 	p += l;
 	mt = *p++;
 	oldpos = 0;
-	while ((p - skb->data) < (int)skb->len) {
+	while ((p - skb->data) < skb->len) {
 		if ((*p & 0xf0) == 0x90) { /* shift codeset */
 			old_codeset = codeset;
 			codeset = *p & 7;
@@ -870,7 +862,7 @@
 
 static int
 l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
-	u8 *p;
+	u_char *p;
 
 	p = skb->data;
 	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
@@ -893,8 +885,8 @@
 
 static int
 l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
-	u8 l, i=0;
-	u8 *p;
+	u_char l, i=0;
+	u_char *p;
 
 	p = skb->data;
 	pc->para.cause = 31;
@@ -931,11 +923,11 @@
 }
 
 static void
-l3dss1_msg_with_uus(struct l3_process *pc, u8 cmd)
+l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd)
 {
 	struct sk_buff *skb;
-	u8 tmp[16+40];
-	u8 *p = tmp;
+	u_char tmp[16+40];
+	u_char *p = tmp;
 	int l;
 
 	MsgHead(p, pc->callref, cmd);
@@ -957,7 +949,7 @@
 } /* l3dss1_msg_with_uus */
 
 static void
-l3dss1_release_req(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	StopAllL3Timer(pc);
 	newl3state(pc, 19);
@@ -969,7 +961,7 @@
 }
 
 static void
-l3dss1_release_cmpl(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -981,14 +973,14 @@
 		pc->para.cause = NO_CAUSE;
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
-	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
 	dss1_release_l3_process(pc);
 }
 
 #if EXT_BEARER_CAPS
 
-static u8 *
-EncodeASyncParams(u8 * p, u8 si2)
+static u_char *
+EncodeASyncParams(u_char * p, u_char si2)
 {				// 7c 06 88  90 21 42 00 bb
 
 	p[0] = 0;
@@ -1052,8 +1044,8 @@
 	return p + 3;
 }
 
-static  u8
-EncodeSyncParams(u8 si2, u8 ai)
+static  u_char
+EncodeSyncParams(u_char si2, u_char ai)
 {
 
 	switch (si2) {
@@ -1097,10 +1089,10 @@
 }
 
 
-static u8
-DecodeASyncParams(u8 si2, u8 * p)
+static u_char
+DecodeASyncParams(u_char si2, u_char * p)
 {
-	u8 info;
+	u_char info;
 
 	switch (p[5]) {
 		case 66:	// 1200 bit/s
@@ -1154,8 +1146,8 @@
 }
 
 
-static u8
-DecodeSyncParams(u8 si2, u8 info)
+static u_char
+DecodeSyncParams(u_char si2, u_char info)
 {
 	info &= 0x7f;
 	switch (info) {
@@ -1195,10 +1187,10 @@
 	}
 }
 
-static u8
+static u_char
 DecodeSI2(struct sk_buff *skb)
 {
-	u8 *p;		//, *pend=skb->data + skb->len;
+	u_char *p;		//, *pend=skb->data + skb->len;
 
 	if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
 		switch (p[4] & 0x0f) {
@@ -1225,20 +1217,20 @@
 
 
 static void
-l3dss1_setup_req(struct l3_process *pc, u8 pr,
+l3dss1_setup_req(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[128];
-	u8 *p = tmp;
-	u8 channel = 0;
-
-        u8 send_keypad;
-	u8 screen = 0x80;
-	u8 *teln;
-	u8 *msn;
-	u8 *sub;
-	u8 *sp;
+	u_char tmp[128];
+	u_char *p = tmp;
+	u_char channel = 0;
+
+        u_char send_keypad;
+	u_char screen = 0x80;
+	u_char *teln;
+	u_char *msn;
+	u_char *sub;
+	u_char *sp;
 	int l;
 
 	MsgHead(p, pc->callref, MT_SETUP);
@@ -1436,7 +1428,7 @@
 }
 
 static void
-l3dss1_call_proc(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -1471,11 +1463,11 @@
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
-l3dss1_setup_ack(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -1510,16 +1502,16 @@
 	L3AddTimer(&pc->timer, T304, CC_T304);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
-l3dss1_disconnect(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	int ret;
-	u8 cause = 0;
+	u_char cause = 0;
 
 	StopAllL3Timer(pc);
 	if ((ret = l3dss1_get_cause(pc, skb))) {
@@ -1542,7 +1534,7 @@
 	if (cause)
 		newl3state(pc, 19);
        	if (11 != ret)
-		L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
        	else if (!cause)
 		   l3dss1_release_req(pc, pr, NULL);
 	if (cause) {
@@ -1552,7 +1544,7 @@
 }
 
 static void
-l3dss1_connect(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1568,11 +1560,11 @@
 	/* here should inserted COLP handling KKe */
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
-l3dss1_alerting(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1586,13 +1578,13 @@
 	newl3state(pc, 4);
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
-l3dss1_setup(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	int bcfound = 0;
 	char tmp[80];
 	struct sk_buff *skb = arg;
@@ -1603,7 +1595,7 @@
 	 * Bearer Capabilities
 	 */
 	p = skb->data;
-	/* only the first occurrence 'll be detected ! */
+	/* only the first occurence 'll be detected ! */
 	if ((p = findie(p, skb->len, 0x04, 0))) {
 		if ((p[1] < 2) || (p[1] > 11))
 			err = 1;
@@ -1752,23 +1744,23 @@
 	newl3state(pc, 6);
 	if (err) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, err);
-	L3L4(pc->st, CC_SETUP | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
 }
 
 static void
-l3dss1_reset(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
 {
 	dss1_release_l3_process(pc);
 }
 
 static void
-l3dss1_disconnect_req(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16+40];
-	u8 *p = tmp;
+	u_char tmp[16+40];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 16;
+	u_char cause = 16;
 
 	if (pc->para.cause != NO_CAUSE)
 		cause = pc->para.cause;
@@ -1801,7 +1793,7 @@
 }
 
 static void
-l3dss1_setup_rsp(struct l3_process *pc, u8 pr,
+l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
         if (!pc->para.bchannel) 
@@ -1817,7 +1809,7 @@
 }
 
 static void
-l3dss1_connect_ack(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1831,17 +1823,17 @@
 	L3DelTimer(&pc->timer);
 	if (ret)
 		l3dss1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
-l3dss1_reject_req(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 21;
+	u_char cause = 21;
 
 	if (pc->para.cause != NO_CAUSE)
 		cause = pc->para.cause;
@@ -1858,16 +1850,16 @@
 		return;
 	memcpy(skb_put(skb, l), tmp, l);
 	l3_msg(pc->st, DL_DATA | REQUEST, skb);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	dss1_release_l3_process(pc);
 }
 
 static void
-l3dss1_release(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	int ret, cause=0;
 
 	StopAllL3Timer(pc);
@@ -1892,13 +1884,13 @@
 		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
 	else
 		l3dss1_message(pc, MT_RELEASE_COMPLETE);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	dss1_release_l3_process(pc);
 }
 
 static void
-l3dss1_alert_req(struct l3_process *pc, u8 pr,
+l3dss1_alert_req(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
 	newl3state(pc, 7);
@@ -1909,16 +1901,16 @@
 }
 
 static void
-l3dss1_proceed_req(struct l3_process *pc, u8 pr,
+l3dss1_proceed_req(struct l3_process *pc, u_char pr,
 		   void *arg)
 {
 	newl3state(pc, 9);
 	l3dss1_message(pc, MT_CALL_PROCEEDING);
-	L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
+	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
 }
 
 static void
-l3dss1_setup_ack_req(struct l3_process *pc, u8 pr,
+l3dss1_setup_ack_req(struct l3_process *pc, u_char pr,
 		   void *arg)
 {
 	newl3state(pc, 25);
@@ -1931,8 +1923,8 @@
 /* deliver a incoming display message to HL */
 /********************************************/
 static void
-l3dss1_deliver_display(struct l3_process *pc, int pr, u8 *infp)
-{       u8 len;
+l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
+{       u_char len;
         isdn_ctrl ic; 
 	struct IsdnCardState *cs;
         char *p; 
@@ -1954,11 +1946,11 @@
 
 
 static void
-l3dss1_progress(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int err = 0;
-	u8 *p;
+	u_char *p;
 
 	if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
 		if (p[1] != 2) {
@@ -2007,15 +1999,15 @@
 	if (err)
 		l3dss1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
 }
 
 static void
-l3dss1_notify(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_notify(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int err = 0;
-	u8 *p;
+	u_char *p;
 
 	if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
 		if (p[1] != 1) {
@@ -2048,11 +2040,11 @@
 	if (err)
 		l3dss1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
 }
 
 static void
-l3dss1_status_enq(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
 {
 	int ret;
 	struct sk_buff *skb = arg;
@@ -2064,11 +2056,11 @@
 }
 
 static void
-l3dss1_information(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
 {
 	int ret;
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	char tmp[32];
 
 	ret = check_infoelements(pc, skb, ie_INFORMATION);
@@ -2080,7 +2072,7 @@
 		if ((p = findie(p, skb->len, 0x70, 0))) {
 			iecpy(tmp, p, 1);
 			strcat(pc->para.setup.eazmsn, tmp);
-			L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
+			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 		}
 		L3AddTimer(&pc->timer, T302, CC_T302);
 	}
@@ -2089,14 +2081,14 @@
 /******************************/
 /* handle deflection requests */
 /******************************/
-static void l3dss1_redir_req(struct l3_process *pc, u8 pr, void *arg)
+static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[128];
-	u8 *p = tmp;
-        u8 *subp;
-        u8 len_phone = 0;
-        u8 len_sub = 0;
+	u_char tmp[128];
+	u_char *p = tmp;
+        u_char *subp;
+        u_char len_phone = 0;
+        u_char len_sub = 0;
 	int l; 
 
 
@@ -2161,7 +2153,7 @@
 /********************************************/
 /* handle deflection request in early state */
 /********************************************/
-static void l3dss1_redir_req_early(struct l3_process *pc, u8 pr, void *arg)
+static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
 {
   l3dss1_proceed_req(pc,pr,arg);
   l3dss1_redir_req(pc,pr,arg);
@@ -2169,13 +2161,13 @@
 
 /***********************************************/
 /* handle special commands for this protocol.  */
-/* Examples are call independent services like */
+/* Examples are call independant services like */
 /* remote operations with dummy  callref.      */
 /***********************************************/
 static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic)
-{ u8 id;
-  u8 temp[265];
-  u8 *p = temp;
+{ u_char id;
+  u_char temp[265];
+  u_char *p = temp;
   int i, l, proc_len; 
   struct sk_buff *skb;
   struct l3_process *pc = NULL;
@@ -2279,9 +2271,9 @@
 } /* l3dss1_io_timer */
 
 static void
-l3dss1_release_ind(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	int callState = 0;
 	p = skb->data;
@@ -2295,31 +2287,31 @@
 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
 		 * set down layer 3 without sending any message
 		 */
-		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		dss1_release_l3_process(pc);
 	} else {
-		L3L4(pc->st, CC_IGNORE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
 	}
 }
 
 static void
-l3dss1_dummy(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg)
 {
 }
 
 static void
-l3dss1_t302(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 28; /* invalid number */
 	l3dss1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3dss1_t303(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
 {
 	if (pc->N303 > 0) {
 		pc->N303--;
@@ -2328,30 +2320,30 @@
 	} else {
 		L3DelTimer(&pc->timer);
 		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
-		L3L4(pc->st, CC_NOSETUP_RSP, pc);
+		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
 		dss1_release_l3_process(pc);
 	}
 }
 
 static void
-l3dss1_t304(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
 static void
-l3dss1_t305(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
-	u8 cause = 16;
+	u_char cause = 16;
 
 	L3DelTimer(&pc->timer);
 	if (pc->para.cause != NO_CAUSE)
@@ -2374,27 +2366,27 @@
 }
 
 static void
-l3dss1_t310(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3dss1_t313(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_CONNECT_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
-l3dss1_t308_1(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg)
 {
 	newl3state(pc, 19);
 	L3DelTimer(&pc->timer);
@@ -2403,50 +2395,50 @@
 }
 
 static void
-l3dss1_t308_2(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RELEASE_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
 	dss1_release_l3_process(pc);
 }
 
 static void
-l3dss1_t318(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	L3L4(pc->st, CC_RESUME_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 19);
 	l3dss1_message(pc, MT_RELEASE);
 	L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3dss1_t319(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_t319(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	L3L4(pc->st, CC_SUSPEND_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 }
 
 static void
-l3dss1_restart(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	dss1_release_l3_process(pc);
 }
 
 static void
-l3dss1_status(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	int ret; 
-	u8 cause = 0, callState = 0;
+	u_char cause = 0, callState = 0;
 	
 	if ((ret = l3dss1_get_cause(pc, skb))) {
 		if (pc->debug & L3_DEB_WARN)
@@ -2474,7 +2466,7 @@
 			cause = 99;
 	}
 	if (cause) {
-		u8 tmp;
+		u_char tmp;
 		
 		if (pc->debug & L3_DEB_WARN)
 			l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
@@ -2492,14 +2484,14 @@
 		 * if received MT_STATUS with cause == 111 and call
 		 * state == 0, then we must set down layer 3
 		 */
-		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		dss1_release_l3_process(pc);
 	}
 }
 
 static void
-l3dss1_facility(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2507,20 +2499,20 @@
 	ret = check_infoelements(pc, skb, ie_FACILITY);
 	l3dss1_std_ie_err(pc, ret);
  	  {
-		u8 *p;
+		u_char *p;
 		if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
 			l3dss1_parse_facility(pc->st, pc, pc->callref, p);
 	}
 }
 
 static void
-l3dss1_suspend_req(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[32];
-	u8 *p = tmp;
-	u8 i, l;
-	u8 *msg = pc->chan->setup.phone;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->chan->setup.phone;
 
 	MsgHead(p, pc->callref, MT_SUSPEND);
 	l = *msg++;
@@ -2543,7 +2535,7 @@
 }
 
 static void
-l3dss1_suspend_ack(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2551,7 +2543,7 @@
 	L3DelTimer(&pc->timer);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
 	/* We don't handle suspend_ack for IE errors now */
 	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
 		if (pc->debug & L3_DEB_WARN)
@@ -2560,7 +2552,7 @@
 }
 
 static void
-l3dss1_suspend_rej(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2581,20 +2573,20 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_SUSPEND_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
 }
 
 static void
-l3dss1_resume_req(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[32];
-	u8 *p = tmp;
-	u8 i, l;
-	u8 *msg = pc->para.setup.phone;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->para.setup.phone;
 
 	MsgHead(p, pc->callref, MT_RESUME);
 
@@ -2618,7 +2610,7 @@
 }
 
 static void
-l3dss1_resume_ack(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -2645,14 +2637,14 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RESUME | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
 }
 
 static void
-l3dss1_resume_rej(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2673,7 +2665,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RESUME_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 0);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3dss1_std_ie_err(pc, ret);
@@ -2681,11 +2673,11 @@
 }
 
 static void
-l3dss1_global_restart(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[32];
-	u8 *p;
-	u8 ri, ch = 0, chan = 0;
+	u_char tmp[32];
+	u_char *p;
+	u_char ri, ch = 0, chan = 0;
 	int l;
 	struct sk_buff *skb = arg;
 	struct l3_process *up;
@@ -2711,9 +2703,9 @@
 	up = pc->st->l3.proc;
 	while (up) {
 		if ((ri & 7) == 7)
-			L4L3(up->st, CC_RESTART | REQUEST, up);
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
 		else if (up->para.bchannel == chan)
-			L4L3(up->st, CC_RESTART | REQUEST, up);
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
 		up = up->next;
 	}
 	p = tmp;
@@ -2735,26 +2727,26 @@
 }
 
 static void
-l3dss1_dl_reset(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
 {
         pc->para.cause = 0x29;          /* Temporary failure */
         pc->para.loc = 0;
         l3dss1_disconnect_req(pc, pr, NULL);
-        L3L4(pc->st, CC_SETUP_ERR, pc);
+        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3dss1_dl_release(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
 {
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
 static void
-l3dss1_dl_reestablish(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
 {
         L3DelTimer(&pc->timer);
         L3AddTimer(&pc->timer, T309, CC_T309);
@@ -2762,7 +2754,7 @@
 }
  
 static void
-l3dss1_dl_reest_status(struct l3_process *pc, u8 pr, void *arg)
+l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
  
@@ -2920,10 +2912,10 @@
 static void
 global_handler(struct PStack *st, int mt, struct sk_buff *skb)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u_int i;
+	int i;
 	struct l3_process *proc = st->l3.global;
 
 	proc->callref = skb->data[2]; /* cr flag */
@@ -2961,10 +2953,9 @@
 static void
 dss1up(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	int mt, cr, cause, callState;
+	int i, mt, cr, cause, callState;
 	char *ptr;
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	struct l3_process *proc;
 
@@ -2999,7 +2990,7 @@
 		return;
 	}
 	cr = getcallref(skb->data);
-	if (skb->len < (u_int)((skb->data[1] & 0x0f) + 3)) {
+	if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
 		l3_debug(st, "dss1up frame too short(%d)", skb->len);
 		dev_kfree_skb(skb);
 		return;
@@ -3136,8 +3127,7 @@
 static void
 dss1down(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	int cr;
+	int i, cr;
 	struct l3_process *proc;
 	struct Channel *chan;
 
@@ -3188,29 +3178,29 @@
 static void
 dss1man(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	struct l3_process *proc = arg;
-
-	if (!proc) {
-		printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
-		return;
-	}
-	for (i = 0; i < MANSLLEN; i++)
+        int i;
+        struct l3_process *proc = arg;
+ 
+        if (!proc) {
+                printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
+                return;
+        }
+        for (i = 0; i < MANSLLEN; i++)
                 if ((pr == manstatelist[i].primitive) &&
-			((1 << proc->state) & manstatelist[i].state))
-			break;
-	if (i == MANSLLEN) {
-		if (st->l3.debug & L3_DEB_STATE) {
-			l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
-				proc->callref & 0x7f, proc->state, pr);
-		}
-	} else {
-		if (st->l3.debug & L3_DEB_STATE) {
-			l3_debug(st, "cr %d dss1man state %d prim %#x",
-				proc->callref & 0x7f, proc->state, pr);
-		}
-		manstatelist[i].rout(proc, pr, arg);
-	}
+                    ((1 << proc->state) & manstatelist[i].state))
+                        break;
+        if (i == MANSLLEN) {
+                if (st->l3.debug & L3_DEB_STATE) {
+                        l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
+                                proc->callref & 0x7f, proc->state, pr);
+                }
+        } else {
+                if (st->l3.debug & L3_DEB_STATE) {
+                        l3_debug(st, "cr %d dss1man state %d prim %#x",
+                                proc->callref & 0x7f, proc->state, pr);
+                }
+                manstatelist[i].rout(proc, pr, arg);
+        }
 }
  
 void
@@ -3219,9 +3209,9 @@
 	char tmp[64];
 	int i;
 
-	st->l3.l4l3 = dss1down;
-	st->l3.l4l3_proto = l3dss1_cmd_global;
-	st->l3.l2l3 = dss1up;
+	st->lli.l4l3 = dss1down;
+	st->lli.l4l3_proto = l3dss1_cmd_global;
+	st->l2.l2l3 = dss1up;
 	st->l3.l3ml3 = dss1man;
 	st->l3.N303 = 1;
 	st->prot.dss1.last_invoke_id = 0;
--- diff/drivers/isdn/hisax/l3ni1.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/l3ni1.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: l3ni1.c,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $
  *
  * NI1 D-channel protocol
  *
@@ -24,8 +24,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *ni1_revision = "$Revision: 2.5.6.3 $";
-static spinlock_t l3ni1_lock = SPIN_LOCK_UNLOCKED;
+const char *ni1_revision = "$Revision: 2.8.2.3 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -47,13 +46,10 @@
 static unsigned char new_invoke_id(struct PStack *p)
 {
 	unsigned char retval;
-	unsigned long flags;
 	int i;
   
 	i = 32; /* maximum search depth */
 
-	spin_lock_irqsave(&l3ni1_lock, flags);
-
 	retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
 	while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
 		p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
@@ -66,8 +62,6 @@
 		retval = 0;
 	p->prot.ni1.last_invoke_id = retval;
 	p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
-	spin_unlock_irqrestore(&l3ni1_lock, flags);
-
 	return(retval);  
 } /* new_invoke_id */
 
@@ -75,13 +69,11 @@
 /* free a used invoke id */
 /*************************/
 static void free_invoke_id(struct PStack *p, unsigned char id)
-{ unsigned long flags;
+{
 
   if (!id) return; /* 0 = invalid value */
 
-  spin_lock_irqsave(&l3ni1_lock, flags);
   p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
-  spin_unlock_irqrestore(&l3ni1_lock, flags);
 } /* free_invoke_id */  
 
 
@@ -134,7 +126,7 @@
 /* and a return result is delivered. id specifies the invoke id.   */
 /*******************************************************************/ 
 static void 
-l3ni1_dummy_return_result(struct PStack *st, int id, u8 *p, u8 nlen)
+l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
 { isdn_ctrl ic;
   struct IsdnCardState *cs;
   struct l3_process *pc = NULL; 
@@ -201,7 +193,7 @@
 /*******************************************************************/ 
 static void 
 l3ni1_dummy_invoke(struct PStack *st, int cr, int id, 
-                    int ident, u8 *p, u8 nlen)
+                    int ident, u_char *p, u_char nlen)
 { isdn_ctrl ic;
   struct IsdnCardState *cs;
 
@@ -225,7 +217,7 @@
 
 static void
 l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
-                      int cr, u8 * p)
+                      int cr, u_char * p)
 {
 	int qd_len = 0;
 	unsigned char nlen = 0, ilen, cp_tag;
@@ -375,7 +367,7 @@
                             pc->prot.ni1.remote_result = 0; /* success */     
                             pc->prot.ni1.invoke_id = 0;
                             pc->redir_result = pc->prot.ni1.remote_result; 
-                            L3L4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -420,7 +412,7 @@
                             pc->prot.ni1.remote_result = err_ret; /* result */
                             pc->prot.ni1.invoke_id = 0; 
                             pc->redir_result = pc->prot.ni1.remote_result; 
-                            L3L4(st, CC_REDIR | INDICATION, pc);  
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);  
                           } /* Deflection error */
                         else
                           l3_debug(st,"return result unknown identifier");
@@ -432,10 +424,10 @@
 }
 
 static void
-l3ni1_message(struct l3_process *pc, u8 mt)
+l3ni1_message(struct l3_process *pc, u_char mt)
 {
 	struct sk_buff *skb;
-	u8 *p;
+	u_char *p;
 
 	if (!(skb = l3_alloc_skb(4)))
 		return;
@@ -445,15 +437,15 @@
 }
 
 static void
-l3ni1_message_plus_chid(struct l3_process *pc, u8 mt)
+l3ni1_message_plus_chid(struct l3_process *pc, u_char mt)
 /* sends an l3 messages plus channel id -  added GE 05/09/00 */
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
-	u8 chid;
+	u_char tmp[16];
+	u_char *p = tmp;
+	u_char chid;
 
-	chid = (u8)(pc->para.bchannel & 0x03) | 0x88;
+	chid = (u_char)(pc->para.bchannel & 0x03) | 0x88;
 	MsgHead(p, pc->callref, mt);
 	*p++ = IE_CHANNEL_ID;
 	*p++ = 0x01;
@@ -466,11 +458,11 @@
 }
 
 static void
-l3ni1_message_cause(struct l3_process *pc, u8 mt, u8 cause)
+l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 
 	MsgHead(p, pc->callref, mt);
@@ -487,10 +479,10 @@
 }
 
 static void
-l3ni1_status_send(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
 
@@ -513,14 +505,14 @@
 }
 
 static void
-l3ni1_msg_without_setup(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
 {
 	/* This routine is called if here was no SETUP made (checks in ni1up and in
 	 * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
 	 * MT_STATUS_ENQUIRE in the NULL state is handled too
 	 */
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
 
@@ -639,7 +631,7 @@
 };
 
 static int
-getmax_ie_len(u8 ie) {
+getmax_ie_len(u_char ie) {
 	int i = 0;
 	while (max_ie_len[i].ie != -1) {
 		if (max_ie_len[i].ie == ie)
@@ -650,7 +642,7 @@
 }
 
 static int
-ie_in_set(struct l3_process *pc, u8 ie, int *checklist) {
+ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
 	int ret = 1;
 
 	while (*checklist != -1) {
@@ -670,13 +662,13 @@
 check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
 {
 	int *cl = checklist;
-	u8 mt;
-	u8 *p, ie;
+	u_char mt;
+	u_char *p, ie;
 	int l, newpos, oldpos;
 	int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
-	u8 codeset = 0;
-	u8 old_codeset = 0;
-	u8 codelock = 1;
+	u_char codeset = 0;
+	u_char old_codeset = 0;
+	u_char codelock = 1;
 	
 	p = skb->data;
 	/* skip cr */
@@ -685,7 +677,7 @@
 	p += l;
 	mt = *p++;
 	oldpos = 0;
-	while ((u_int)(p - skb->data) < skb->len) {
+	while ((p - skb->data) < skb->len) {
 		if ((*p & 0xf0) == 0x90) { /* shift codeset */
 			old_codeset = codeset;
 			codeset = *p & 7;
@@ -819,7 +811,7 @@
 
 static int
 l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
-	u8 *p;
+	u_char *p;
 
 	p = skb->data;
 	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
@@ -842,8 +834,8 @@
 
 static int
 l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
-	u8 l, i=0;
-	u8 *p;
+	u_char l, i=0;
+	u_char *p;
 
 	p = skb->data;
 	pc->para.cause = 31;
@@ -880,11 +872,11 @@
 }
 
 static void
-l3ni1_msg_with_uus(struct l3_process *pc, u8 cmd)
+l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
 {
 	struct sk_buff *skb;
-	u8 tmp[16+40];
-	u8 *p = tmp;
+	u_char tmp[16+40];
+	u_char *p = tmp;
 	int l;
 
 	MsgHead(p, pc->callref, cmd);
@@ -906,7 +898,7 @@
 } /* l3ni1_msg_with_uus */
 
 static void
-l3ni1_release_req(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	StopAllL3Timer(pc);
 	newl3state(pc, 19);
@@ -918,7 +910,7 @@
 }
 
 static void
-l3ni1_release_cmpl(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -930,14 +922,14 @@
 		pc->para.cause = NO_CAUSE;
 	StopAllL3Timer(pc);
 	newl3state(pc, 0);
-	L3L4(pc->st, CC_RELEASE | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
 	ni1_release_l3_process(pc);
 }
 
 #if EXT_BEARER_CAPS
 
-static u8 *
-EncodeASyncParams(u8 * p, u8 si2)
+static u_char *
+EncodeASyncParams(u_char * p, u_char si2)
 {				// 7c 06 88  90 21 42 00 bb
 
 	p[0] = 0;
@@ -1001,8 +993,8 @@
 	return p + 3;
 }
 
-static u8
-EncodeSyncParams(u8 si2, u8 ai)
+static u_char
+EncodeSyncParams(u_char si2, u_char ai)
 {
 
 	switch (si2) {
@@ -1046,10 +1038,10 @@
 }
 
 
-static u8
-DecodeASyncParams(u8 si2, u8 * p)
+static u_char
+DecodeASyncParams(u_char si2, u_char * p)
 {
-	u8 info;
+	u_char info;
 
 	switch (p[5]) {
 		case 66:	// 1200 bit/s
@@ -1103,8 +1095,8 @@
 }
 
 
-static u8
-DecodeSyncParams(u8 si2, u8 info)
+static u_char
+DecodeSyncParams(u_char si2, u_char info)
 {
 	info &= 0x7f;
 	switch (info) {
@@ -1144,10 +1136,10 @@
 	}
 }
 
-static u8
+static u_char
 DecodeSI2(struct sk_buff *skb)
 {
-	u8 *p;		//, *pend=skb->data + skb->len;
+	u_char *p;		//, *pend=skb->data + skb->len;
 
 	if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
 		switch (p[4] & 0x0f) {
@@ -1174,16 +1166,16 @@
 
 
 static void
-l3ni1_setup_req(struct l3_process *pc, u8 pr,
+l3ni1_setup_req(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[128];
-	u8 *p = tmp;
+	u_char tmp[128];
+	u_char *p = tmp;
 
-	u8 *teln;
-	u8 *sub;
-	u8 *sp;
+	u_char *teln;
+	u_char *sub;
+	u_char *sp;
 	int l;
 
 	MsgHead(p, pc->callref, MT_SETUP);
@@ -1289,7 +1281,7 @@
 }
 
 static void
-l3ni1_call_proc(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -1324,11 +1316,11 @@
 	L3AddTimer(&pc->timer, T310, CC_T310);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_PROCEEDING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
-l3ni1_setup_ack(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -1363,16 +1355,16 @@
 	L3AddTimer(&pc->timer, T304, CC_T304);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
-l3ni1_disconnect(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	int ret;
-	u8 cause = 0;
+	u_char cause = 0;
 
 	StopAllL3Timer(pc);
 	if ((ret = l3ni1_get_cause(pc, skb))) {
@@ -1395,7 +1387,7 @@
 	if (cause)
 		newl3state(pc, 19);
        	if (11 != ret)
-		L3L4(pc->st, CC_DISCONNECT | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
        	else if (!cause)
 		   l3ni1_release_req(pc, pr, NULL);
 	if (cause) {
@@ -1405,7 +1397,7 @@
 }
 
 static void
-l3ni1_connect(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1421,11 +1413,11 @@
 	/* here should inserted COLP handling KKe */
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_SETUP | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
-l3ni1_alerting(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1439,13 +1431,13 @@
 	newl3state(pc, 4);
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_ALERTING | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
-l3ni1_setup(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	int bcfound = 0;
 	char tmp[80];
 	struct sk_buff *skb = arg;
@@ -1456,7 +1448,7 @@
 	 * Bearer Capabilities
 	 */
 	p = skb->data;
-	/* only the first occurrence 'll be detected ! */
+	/* only the first occurence 'll be detected ! */
 	if ((p = findie(p, skb->len, 0x04, 0))) {
 		if ((p[1] < 2) || (p[1] > 11))
 			err = 1;
@@ -1605,23 +1597,23 @@
 	newl3state(pc, 6);
 	if (err) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, err);
-	L3L4(pc->st, CC_SETUP | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
 }
 
 static void
-l3ni1_reset(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
 {
 	ni1_release_l3_process(pc);
 }
 
 static void
-l3ni1_disconnect_req(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16+40];
-	u8 *p = tmp;
+	u_char tmp[16+40];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 16;
+	u_char cause = 16;
 
 	if (pc->para.cause != NO_CAUSE)
 		cause = pc->para.cause;
@@ -1654,7 +1646,7 @@
 }
 
 static void
-l3ni1_setup_rsp(struct l3_process *pc, u8 pr,
+l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
         if (!pc->para.bchannel) 
@@ -1672,7 +1664,7 @@
 }
 
 static void
-l3ni1_connect_ack(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -1686,17 +1678,17 @@
 	L3DelTimer(&pc->timer);
 	if (ret)
 		l3ni1_std_ie_err(pc, ret);
-	L3L4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
-l3ni1_reject_req(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u8 cause = 21;
+	u_char cause = 21;
 
 	if (pc->para.cause != NO_CAUSE)
 		cause = pc->para.cause;
@@ -1713,16 +1705,16 @@
 		return;
 	memcpy(skb_put(skb, l), tmp, l);
 	l3_msg(pc->st, DL_DATA | REQUEST, skb);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	ni1_release_l3_process(pc);
 }
 
 static void
-l3ni1_release(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	int ret, cause=0;
 
 	StopAllL3Timer(pc);
@@ -1747,13 +1739,13 @@
 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
 	else
 		l3ni1_message(pc, MT_RELEASE_COMPLETE);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	newl3state(pc, 0);
 	ni1_release_l3_process(pc);
 }
 
 static void
-l3ni1_alert_req(struct l3_process *pc, u8 pr,
+l3ni1_alert_req(struct l3_process *pc, u_char pr,
 		 void *arg)
 {
 	newl3state(pc, 7);
@@ -1764,16 +1756,16 @@
 }
 
 static void
-l3ni1_proceed_req(struct l3_process *pc, u8 pr,
+l3ni1_proceed_req(struct l3_process *pc, u_char pr,
 		   void *arg)
 {
 	newl3state(pc, 9);
 	l3ni1_message(pc, MT_CALL_PROCEEDING);
-	L3L4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
+	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
 }
 
 static void
-l3ni1_setup_ack_req(struct l3_process *pc, u8 pr,
+l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
 		   void *arg)
 {
 	newl3state(pc, 25);
@@ -1786,8 +1778,8 @@
 /* deliver a incoming display message to HL */
 /********************************************/
 static void
-l3ni1_deliver_display(struct l3_process *pc, int pr, u8 *infp)
-{       u8 len;
+l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
+{       u_char len;
         isdn_ctrl ic; 
 	struct IsdnCardState *cs;
         char *p; 
@@ -1809,11 +1801,11 @@
 
 
 static void
-l3ni1_progress(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int err = 0;
-	u8 *p;
+	u_char *p;
 
 	if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
 		if (p[1] != 2) {
@@ -1862,15 +1854,15 @@
 	if (err)
 		l3ni1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		L3L4(pc->st, CC_PROGRESS | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
 }
 
 static void
-l3ni1_notify(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int err = 0;
-	u8 *p;
+	u_char *p;
 
 	if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
 		if (p[1] != 1) {
@@ -1903,11 +1895,11 @@
 	if (err)
 		l3ni1_std_ie_err(pc, err);
 	if (ERR_IE_COMPREHENSION != err)
-		L3L4(pc->st, CC_NOTIFY | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
 }
 
 static void
-l3ni1_status_enq(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
 {
 	int ret;
 	struct sk_buff *skb = arg;
@@ -1919,11 +1911,11 @@
 }
 
 static void
-l3ni1_information(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
 {
 	int ret;
 	struct sk_buff *skb = arg;
-	u8 *p;
+	u_char *p;
 	char tmp[32];
 
 	ret = check_infoelements(pc, skb, ie_INFORMATION);
@@ -1935,7 +1927,7 @@
 		if ((p = findie(p, skb->len, 0x70, 0))) {
 			iecpy(tmp, p, 1);
 			strcat(pc->para.setup.eazmsn, tmp);
-			L3L4(pc->st, CC_MORE_INFO | INDICATION, pc);
+			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 		}
 		L3AddTimer(&pc->timer, T302, CC_T302);
 	}
@@ -1944,14 +1936,14 @@
 /******************************/
 /* handle deflection requests */
 /******************************/
-static void l3ni1_redir_req(struct l3_process *pc, u8 pr, void *arg)
+static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[128];
-	u8 *p = tmp;
-        u8 *subp;
-        u8 len_phone = 0;
-        u8 len_sub = 0;
+	u_char tmp[128];
+	u_char *p = tmp;
+        u_char *subp;
+        u_char len_phone = 0;
+        u_char len_sub = 0;
 	int l; 
 
 
@@ -2016,7 +2008,7 @@
 /********************************************/
 /* handle deflection request in early state */
 /********************************************/
-static void l3ni1_redir_req_early(struct l3_process *pc, u8 pr, void *arg)
+static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
 {
   l3ni1_proceed_req(pc,pr,arg);
   l3ni1_redir_req(pc,pr,arg);
@@ -2024,13 +2016,13 @@
 
 /***********************************************/
 /* handle special commands for this protocol.  */
-/* Examples are call independent services like */
+/* Examples are call independant services like */
 /* remote operations with dummy  callref.      */
 /***********************************************/
 static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
-{ u8 id;
-  u8 temp[265];
-  u8 *p = temp;
+{ u_char id;
+  u_char temp[265];
+  u_char *p = temp;
   int i, l, proc_len; 
   struct sk_buff *skb;
   struct l3_process *pc = NULL;
@@ -2134,9 +2126,9 @@
 } /* l3ni1_io_timer */
 
 static void
-l3ni1_release_ind(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	int callState = 0;
 	p = skb->data;
@@ -2150,31 +2142,31 @@
 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
 		 * set down layer 3 without sending any message
 		 */
-		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		ni1_release_l3_process(pc);
 	} else {
-		L3L4(pc->st, CC_IGNORE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
 	}
 }
 
 static void
-l3ni1_dummy(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
 {
 }
 
 static void
-l3ni1_t302(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 28; /* invalid number */
 	l3ni1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3ni1_t303(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
 {
 	if (pc->N303 > 0) {
 		pc->N303--;
@@ -2183,30 +2175,30 @@
 	} else {
 		L3DelTimer(&pc->timer);
 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
-		L3L4(pc->st, CC_NOSETUP_RSP, pc);
+		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
 		ni1_release_l3_process(pc);
 	}
 }
 
 static void
-l3ni1_t304(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
 static void
-l3ni1_t305(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
 	struct sk_buff *skb;
-	u8 cause = 16;
+	u_char cause = 16;
 
 	L3DelTimer(&pc->timer);
 	if (pc->para.cause != NO_CAUSE)
@@ -2229,27 +2221,27 @@
 }
 
 static void
-l3ni1_t310(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_SETUP_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3ni1_t313(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3ni1_disconnect_req(pc, pr, NULL);
-	L3L4(pc->st, CC_CONNECT_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
-l3ni1_t308_1(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
 {
 	newl3state(pc, 19);
 	L3DelTimer(&pc->timer);
@@ -2258,50 +2250,50 @@
 }
 
 static void
-l3ni1_t308_2(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RELEASE_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
 	ni1_release_l3_process(pc);
 }
 
 static void
-l3ni1_t318(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	L3L4(pc->st, CC_RESUME_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 19);
 	l3ni1_message(pc, MT_RELEASE);
 	L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3ni1_t319(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
 	pc->para.cause = 102;	/* Timer expiry */
 	pc->para.loc = 0;	/* local */
-	L3L4(pc->st, CC_SUSPEND_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 }
 
 static void
-l3ni1_restart(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 	ni1_release_l3_process(pc);
 }
 
 static void
-l3ni1_status(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	int ret; 
-	u8 cause = 0, callState = 0;
+	u_char cause = 0, callState = 0;
 	
 	if ((ret = l3ni1_get_cause(pc, skb))) {
 		if (pc->debug & L3_DEB_WARN)
@@ -2329,7 +2321,7 @@
 			cause = 99;
 	}
 	if (cause) {
-		u8 tmp;
+		u_char tmp;
 		
 		if (pc->debug & L3_DEB_WARN)
 			l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
@@ -2347,14 +2339,14 @@
 		 * if received MT_STATUS with cause == 111 and call
 		 * state == 0, then we must set down layer 3
 		 */
-		L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
 		newl3state(pc, 0);
 		ni1_release_l3_process(pc);
 	}
 }
 
 static void
-l3ni1_facility(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2362,20 +2354,20 @@
 	ret = check_infoelements(pc, skb, ie_FACILITY);
 	l3ni1_std_ie_err(pc, ret);
  	  {
-		u8 *p;
+		u_char *p;
 		if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
 			l3ni1_parse_facility(pc->st, pc, pc->callref, p);
 	}
 }
 
 static void
-l3ni1_suspend_req(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[32];
-	u8 *p = tmp;
-	u8 i, l;
-	u8 *msg = pc->chan->setup.phone;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->chan->setup.phone;
 
 	MsgHead(p, pc->callref, MT_SUSPEND);
 	l = *msg++;
@@ -2398,7 +2390,7 @@
 }
 
 static void
-l3ni1_suspend_ack(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2406,7 +2398,7 @@
 	L3DelTimer(&pc->timer);
 	newl3state(pc, 0);
 	pc->para.cause = NO_CAUSE;
-	L3L4(pc->st, CC_SUSPEND | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
 	/* We don't handle suspend_ack for IE errors now */
 	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
 		if (pc->debug & L3_DEB_WARN)
@@ -2415,7 +2407,7 @@
 }
 
 static void
-l3ni1_suspend_rej(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2436,20 +2428,20 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_SUSPEND_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
 }
 
 static void
-l3ni1_resume_req(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb;
-	u8 tmp[32];
-	u8 *p = tmp;
-	u8 i, l;
-	u8 *msg = pc->para.setup.phone;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->para.setup.phone;
 
 	MsgHead(p, pc->callref, MT_RESUME);
 
@@ -2473,7 +2465,7 @@
 }
 
 static void
-l3ni1_resume_ack(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int id, ret;
@@ -2500,14 +2492,14 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RESUME | CONFIRM, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
 	newl3state(pc, 10);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
 }
 
 static void
-l3ni1_resume_rej(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
 {
 	struct sk_buff *skb = arg;
 	int ret;
@@ -2528,7 +2520,7 @@
 		return;
 	}
 	L3DelTimer(&pc->timer);
-	L3L4(pc->st, CC_RESUME_ERR, pc);
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
 	newl3state(pc, 0);
 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
 		l3ni1_std_ie_err(pc, ret);
@@ -2536,11 +2528,11 @@
 }
 
 static void
-l3ni1_global_restart(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
 {
-	u8 tmp[32];
-	u8 *p;
-	u8 ri, ch = 0, chan = 0;
+	u_char tmp[32];
+	u_char *p;
+	u_char ri, ch = 0, chan = 0;
 	int l;
 	struct sk_buff *skb = arg;
 	struct l3_process *up;
@@ -2566,9 +2558,9 @@
 	up = pc->st->l3.proc;
 	while (up) {
 		if ((ri & 7) == 7)
-			L4L3(up->st, CC_RESTART | REQUEST, up);
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
 		else if (up->para.bchannel == chan)
-			L4L3(up->st, CC_RESTART | REQUEST, up);
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
 		
 		up = up->next;
 	}
@@ -2591,26 +2583,26 @@
 }
 
 static void
-l3ni1_dl_reset(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
 {
         pc->para.cause = 0x29;          /* Temporary failure */
         pc->para.loc = 0;
         l3ni1_disconnect_req(pc, pr, NULL);
-        L3L4(pc->st, CC_SETUP_ERR, pc);
+        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
-l3ni1_dl_release(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
 {
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
         pc->para.loc = 0;
-        L3L4(pc->st, CC_RELEASE | INDICATION, pc);
+        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
 
 static void
-l3ni1_dl_reestablish(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
 {
         L3DelTimer(&pc->timer);
         L3AddTimer(&pc->timer, T309, CC_T309);
@@ -2618,7 +2610,7 @@
 }
  
 static void
-l3ni1_dl_reest_status(struct l3_process *pc, u8 pr, void *arg)
+l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
  
@@ -2626,9 +2618,9 @@
 	l3ni1_status_send(pc, 0, NULL);
 }
 
-static void l3ni1_SendSpid( struct l3_process *pc, u8 pr, struct sk_buff *skb, int iNewState )
+static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState )
 {
-	u8         * p;
+	u_char         * p;
 	char           * pSPID;
 	struct Channel * pChan = pc->st->lli.userdata;
 	int              l;
@@ -2640,7 +2632,7 @@
 	{
 		printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
 		newl3state( pc, 0 );
-		L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
+		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
 		return;
 	}
 
@@ -2665,15 +2657,15 @@
 	L3DelTimer( &pc->timer );
 	L3AddTimer( &pc->timer, TSPID, CC_TSPID );
 
-	L3L2( pc->st, DL_DATA | REQUEST, skb );
+	pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
 }
 
-static void l3ni1_spid_send( struct l3_process *pc, u8 pr, void *arg )
+static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
 {
 	l3ni1_SendSpid( pc, pr, arg, 20 );
 }
 
-void l3ni1_spid_epid( struct l3_process *pc, u8 pr, void *arg )
+void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
 {
 	struct sk_buff *skb = arg;
 
@@ -2687,7 +2679,7 @@
 	dev_kfree_skb( skb);
 }
 
-static void l3ni1_spid_tout( struct l3_process *pc, u8 pr, void *arg )
+static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg )
 {
 	if ( pc->state < 22 )
 		l3ni1_SendSpid( pc, pr, arg, pc->state+1 );
@@ -2698,7 +2690,7 @@
 
 		printk( KERN_ERR "SPID not accepted\n" );
 		newl3state( pc, 0 );
-		L3L2( pc->st, DL_RELEASE | REQUEST, NULL );
+		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
 	}
 }
 
@@ -2856,10 +2848,10 @@
 static void
 global_handler(struct PStack *st, int mt, struct sk_buff *skb)
 {
-	u8 tmp[16];
-	u8 *p = tmp;
+	u_char tmp[16];
+	u_char *p = tmp;
 	int l;
-	u_int i;
+	int i;
 	struct l3_process *proc = st->l3.global;
 
 	if ( skb )	
@@ -2900,10 +2892,9 @@
 static void
 ni1up(struct PStack *st, int pr, void *arg)
 {
-	u_int i; 
-	int mt, cr, cause, callState;
+	int i, mt, cr, cause, callState;
 	char *ptr;
-	u8 *p;
+	u_char *p;
 	struct sk_buff *skb = arg;
 	struct l3_process *proc;
 
@@ -2942,7 +2933,7 @@
 		return;
 	}
 	cr = getcallref(skb->data);
-	if (skb->len < (u_int)((skb->data[1] & 0x0f) + 3)) {
+	if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
 		l3_debug(st, "ni1up frame too short(%d)", skb->len);
 		dev_kfree_skb(skb);
 		return;
@@ -3087,8 +3078,7 @@
 static void
 ni1down(struct PStack *st, int pr, void *arg)
 {
-	u_int i;
-	int cr;
+	int i, cr;
 	struct l3_process *proc;
 	struct Channel *chan;
 
@@ -3139,7 +3129,7 @@
 static void
 ni1man(struct PStack *st, int pr, void *arg)
 {
-        u_int i;
+        int i;
         struct l3_process *proc = arg;
 
         if (!proc) {
@@ -3170,9 +3160,9 @@
 	char tmp[64];
 	int i;
 
-	st->l3.l4l3 = ni1down;
-	st->l3.l4l3_proto = l3ni1_cmd_global;
-	st->l3.l2l3 = ni1up;
+	st->lli.l4l3 = ni1down;
+	st->lli.l4l3_proto = l3ni1_cmd_global;
+	st->l2.l2l3 = ni1up;
 	st->l3.l3ml3 = ni1man;
 	st->l3.N303 = 1;
 	st->prot.ni1.last_invoke_id = 0;
--- diff/drivers/isdn/hisax/mic.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/mic.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: mic.c,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
+/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for mic cards
  *
@@ -18,8 +18,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.10.6.2 $";
-static spinlock_t mic_lock = SPIN_LOCK_UNLOCKED;
+const char *mic_revision = "$Revision: 1.12.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -31,146 +30,210 @@
 /* CARD_ADR (Write) */
 #define MIC_RESET      0x3	/* same as DOS driver */
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&mic_lock, flags);
-	byteout(cs->hw.mic.adr, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&mic_lock, flags);
-
 	return (ret);
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&mic_lock, flags);
-	byteout(cs->hw.mic.adr, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&mic_lock, flags);
+	byteout(ale, off);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.mic.adr, off);
-	insb(adr, data, size);
+	byteout(ale, off);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.mic.adr, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
-{
-	return readreg(cs, cs->hw.mic.isac, offset);
-}
+/* Interface functions */
 
-static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	writereg(cs, cs->hw.mic.isac, offset, value);
+	return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	readfifo(cs, cs->hw.mic.isac, 0, data, size);
+	writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
-{
-	writefifo(cs, cs->hw.mic.isac, 0, data, size);
-}
-
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	return readreg(cs, cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0));
+	readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writereg(cs, cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
+	writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	readfifo(cs, cs->hw.mic.hscx, hscx ? 0x40 : 0, data, size);
+	return (readreg(cs->hw.mic.adr,
+			cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writefifo(cs, cs->hw.mic.hscx, hscx ? 0x40 : 0, data, size);
+	writereg(cs->hw.mic.adr,
+		 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static struct card_ops mic_ops = {
-	.init     = inithscxisac,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static int __init
-mic_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->irq = card->para[0];
-	cs->hw.mic.cfg_reg = card->para[1];
-	cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
-	cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
-	cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
-
-	if (!request_io(&cs->rs, cs->hw.mic.cfg_reg, 8, "mic isdn"))
-		goto err;
-  
-	printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n",
-	       cs->hw.mic.cfg_reg, cs->irq);
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-	cs->card_ops = &mic_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
+		cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
+		cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
+		cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
+		cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
+	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+void
+release_io_mic(struct IsdnCardState *cs)
+{
+	int bytecnt = 8;
+
+	if (cs->hw.mic.cfg_reg)
+		release_region(cs->hw.mic.cfg_reg, bytecnt);
+}
+
+static int
+mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			return(0);
+		case CARD_RELEASE:
+			release_io_mic(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscx(cs); /* /RTSA := ISAC RST */
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 int __init
 setup_mic(struct IsdnCard *card)
 {
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, mic_revision);
 	printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_MIC)
+		return (0);
+
+	bytecnt = 8;
+	cs->hw.mic.cfg_reg = card->para[1];
+	cs->irq = card->para[0];
+	cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
+	cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
+	cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
 
-	if (mic_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.mic.cfg_reg,
+		       cs->hw.mic.cfg_reg + bytecnt);
+		return (0);
+	}
+	printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n",
+		cs->hw.mic.cfg_reg, cs->irq);
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &mic_card_msg;
+	cs->irq_func = &mic_interrupt;
+	ISACVersion(cs, "mic:");
+	if (HscxVersion(cs, "mic:")) {
+		printk(KERN_WARNING
+		    "mic: wrong HSCX versions check IO address\n");
+		release_io_mic(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/netjet.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/netjet.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.24.6.6 2001/09/23 22:24:50 kai Exp $
+/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $
  *
  * low level stuff for Traverse Technologie NETJet ISDN cards
  *
@@ -25,63 +25,40 @@
 #include <asm/io.h>
 #include "netjet.h"
 
-const char *NETjet_revision = "$Revision: 1.24.6.6 $";
-static spinlock_t netjet_lock = SPIN_LOCK_UNLOCKED;
+const char *NETjet_revision = "$Revision: 1.29.2.4 $";
 
 /* Interface functions */
 
-u8
-NETjet_ReadIC(struct IsdnCardState *cs, u8 offset)
+u_char
+NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
 {
-	unsigned long flags;
-	u8 ret;
+	u_char ret;
 	
-	spin_lock_irqsave(&netjet_lock, flags);
 	cs->hw.njet.auxd &= 0xfc;
 	cs->hw.njet.auxd |= (offset>>4) & 3;
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
 	ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2));
-	spin_unlock_irqrestore(&netjet_lock, flags);
 	return(ret);
 }
 
 void
-NETjet_WriteIC(struct IsdnCardState *cs, u8 offset, u8 value)
+NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	unsigned long flags;
-	
-	spin_lock_irqsave(&netjet_lock, flags);
 	cs->hw.njet.auxd &= 0xfc;
 	cs->hw.njet.auxd |= (offset>>4) & 3;
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
 	byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value);
-	spin_unlock_irqrestore(&netjet_lock, flags);
 }
 
 void
-NETjet_ReadICfifo(struct IsdnCardState *cs, u8 *data, int size)
+NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
 {
 	cs->hw.njet.auxd &= 0xfc;
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
 	insb(cs->hw.njet.isac, data, size);
 }
 
-void 
-NETjet_WriteICfifo(struct IsdnCardState *cs, u8 *data, int size)
-{
-	cs->hw.njet.auxd &= 0xfc;
-	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-	outsb(cs->hw.njet.isac, data, size);
-}
-
-struct dc_hw_ops netjet_dc_ops = {
-	.read_reg   = NETjet_ReadIC,
-	.write_reg  = NETjet_WriteIC,
-	.read_fifo  = NETjet_ReadICfifo,
-	.write_fifo = NETjet_WriteICfifo,
-};
-
-static u16 fcstab[256] =
+__u16 fcstab[256] =
 {
 	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
 	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
@@ -117,7 +94,15 @@
 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
 
-void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u8 fill)
+void 
+NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+	cs->hw.njet.auxd &= 0xfc;
+	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+	outsb(cs->hw.njet.isac, data, size);
+}
+
+void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
 {
 	u_int mask=0x000000ff, val = 0, *p=pos;
 	u_int i;
@@ -140,7 +125,7 @@
 mode_tiger(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
-        u8 led;
+        u_char led;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "Tiger mode %d bchan %d/%d",
@@ -216,11 +201,11 @@
 			bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
 }
 
-static void printframe(struct IsdnCardState *cs, u8 *buf, int count, char *s) {
+static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
 	char tmp[128];
 	char *t = tmp;
 	int i=count,j;
-	u8 *p = buf;
+	u_char *p = buf;
 
 	t += sprintf(t, "tiger %s(%4d)", s, count);
 	while (i>0) {
@@ -269,11 +254,11 @@
 static int make_raw_data(struct BCState *bcs) {
 // this make_raw is for 64k
 	register u_int i,s_cnt=0;
-	register u8 j;
-	register u8 val;
-	register u8 s_one = 0;
-	register u8 s_val = 0;
-	register u8 bitcnt = 0;
+	register u_char j;
+	register u_char val;
+	register u_char s_one = 0;
+	register u_char s_val = 0;
+	register u_char bitcnt = 0;
 	u_int fcs;
 	
 	if (!bcs->tx_skb) {
@@ -359,11 +344,11 @@
 static int make_raw_data_56k(struct BCState *bcs) {
 // this make_raw is for 56k
 	register u_int i,s_cnt=0;
-	register u8 j;
-	register u8 val;
-	register u8 s_one = 0;
-	register u8 s_val = 0;
-	register u8 bitcnt = 0;
+	register u_char j;
+	register u_char val;
+	register u_char s_one = 0;
+	register u_char s_val = 0;
+	register u_char bitcnt = 0;
 	u_int fcs;
 	
 	if (!bcs->tx_skb) {
@@ -439,7 +424,8 @@
 		memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count);
 		skb_queue_tail(&bcs->rqueue, skb);
 	}
-	sched_b_event(bcs, B_RCVBUFREADY);
+	test_and_set_bit(B_RCVBUFREADY, &bcs->event);
+	schedule_work(&bcs->tqueue);
 	
 	if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
 		printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
@@ -449,16 +435,16 @@
 
 static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
 	int i;
-	register u8 j;
-	register u8 val;
+	register u_char j;
+	register u_char val;
 	u_int  *pend = bcs->hw.tiger.rec +NETJET_DMA_RXSIZE -1;
-	register u8 state = bcs->hw.tiger.r_state;
-	register u8 r_one = bcs->hw.tiger.r_one;
-	register u8 r_val = bcs->hw.tiger.r_val;
+	register u_char state = bcs->hw.tiger.r_state;
+	register u_char r_one = bcs->hw.tiger.r_one;
+	register u_char r_val = bcs->hw.tiger.r_val;
 	register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
 	u_int *p = buf;
 	int bits;
-	u8 mask;
+	u_char mask;
 
         if (bcs->mode == L1_MODE_HDLC) { // it's 64k
 		mask = 0xff;
@@ -682,9 +668,7 @@
 	if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
 		write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
 	} else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
-		p = inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)
-			- bcs->hw.tiger.send_dma
-			+ bcs->hw.tiger.send;
+		p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
 		sp = bcs->hw.tiger.sendp;
 		if (p == bcs->hw.tiger.s_end)
 			p = bcs->hw.tiger.send -1;
@@ -705,9 +689,7 @@
 			write_raw(bcs, p, bcs->hw.tiger.free - cnt);
 		}
 	} else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
-		p = inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR) 
-			- bcs->hw.tiger.send_dma
-			+ bcs->hw.tiger.send;
+		p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
 		cnt = bcs->hw.tiger.s_end - p;
 		if (cnt < 2) {
 			p = bcs->hw.tiger.send + 1;
@@ -729,7 +711,7 @@
 
 static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
 	u_int mask, val, *p=buf;
-	int i, s_cnt;
+	u_int i, s_cnt;
         
         if (cnt <= 0)
         	return;
@@ -766,7 +748,16 @@
 			if (!bcs->tx_skb) {
 				debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
 			} else {
-				xmit_complete_b(bcs);
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->tx_skb->len;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_any(bcs->tx_skb);
+				bcs->tx_skb = NULL;
 			}
 			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 			bcs->hw.tiger.free = cnt - s_cnt;
@@ -790,7 +781,8 @@
 						debugl1(bcs->cs, "tiger write_raw: fill rest %d",
 							cnt - s_cnt);
 				}
-				sched_b_event(bcs, B_XMTBUFREADY);
+				test_and_set_bit(B_XMTBUFREADY, &bcs->event);
+				schedule_work(&bcs->tqueue);
 			}
 		}
 	} else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
@@ -838,36 +830,59 @@
 static void
 tiger_l2l1(struct PStack *st, int pr, void *arg)
 {
+	struct BCState *bcs = st->l1.bcs;
 	struct sk_buff *skb = arg;
-	struct IsdnCardState *cs = st->l1.bcs->cs;
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
+			} else {
+				bcs->tx_skb = skb;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
-			if (cs->hw.njet.bc_activate)
-				(cs->hw.njet.bc_activate)(cs, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			mode_tiger(bcs, st->l1.mode, st->l1.bc);
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
-			if (cs->hw.njet.bc_deactivate)
-				(cs->hw.njet.bc_deactivate)(cs, st->l1.bc);
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			mode_tiger(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			mode_tiger(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -928,7 +943,7 @@
 	if (open_tigerstate(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = tiger_l2l1;
+	st->l2.l2l1 = tiger_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
@@ -936,47 +951,32 @@
 }
 
  
-static struct bc_l1_ops netjet_l1_ops = {
-	.fill_fifo = netjet_fill_dma,
-	.open      = setstack_tiger,
-	.close     = close_tigerstate,
-};
-
 void __init
 inittiger(struct IsdnCardState *cs)
 {
-	cs->bc_l1_ops = &netjet_l1_ops;
-
-	cs->bcs[0].hw.tiger.send = 
-		pci_alloc_consistent(cs->hw.njet.pdev,
-				     NETJET_DMA_TXSIZE * sizeof(unsigned int),
-				     &cs->bcs[0].hw.tiger.send_dma);
-	if (!cs->bcs[0].hw.tiger.send) {
+	if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
+		GFP_KERNEL | GFP_DMA))) {
 		printk(KERN_WARNING
 		       "HiSax: No memory for tiger.send\n");
 		return;
 	}
-	cs->bcs[0].hw.tiger.s_end     = cs->bcs[0].hw.tiger.send     + NETJET_DMA_TXSIZE - 1;
-
-	cs->bcs[1].hw.tiger.send      = cs->bcs[0].hw.tiger.send;
-	cs->bcs[1].hw.tiger.send_dma  = cs->bcs[0].hw.tiger.send_dma;
-	cs->bcs[1].hw.tiger.s_end     = cs->bcs[0].hw.tiger.s_end;
+	cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE/2 - 1;
+	cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
+	cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
+	cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
+	cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
 	
 	memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int));
 	debugl1(cs, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send,
 		(u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1));
-	outl(cs->bcs[0].hw.tiger.send_dma,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
 		cs->hw.njet.base + NETJET_DMA_READ_START);
-	outl(cs->bcs[0].hw.tiger.send_dma + NETJET_DMA_TXSIZE/2 - 1,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
 		cs->hw.njet.base + NETJET_DMA_READ_IRQ);
-	outl(cs->bcs[0].hw.tiger.send_dma + NETJET_DMA_TXSIZE - 1,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
 		cs->hw.njet.base + NETJET_DMA_READ_END);
-
-	cs->bcs[0].hw.tiger.rec = 
-		pci_alloc_consistent(cs->hw.njet.pdev,
-				     NETJET_DMA_RXSIZE * sizeof(unsigned int),
-				     &cs->bcs[0].hw.tiger.rec_dma);
-	if (!cs->bcs[0].hw.tiger.rec) {
+	if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int),
+		GFP_KERNEL | GFP_DMA))) {
 		printk(KERN_WARNING
 		       "HiSax: No memory for tiger.rec\n");
 		return;
@@ -984,39 +984,36 @@
 	debugl1(cs, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec,
 		(u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1));
 	cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
-	cs->bcs[1].hw.tiger.rec_dma = cs->bcs[0].hw.tiger.rec_dma;
 	memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int));
-	outl(cs->bcs[0].hw.tiger.rec_dma,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
 		cs->hw.njet.base + NETJET_DMA_WRITE_START);
-	outl(cs->bcs[0].hw.tiger.rec_dma + NETJET_DMA_RXSIZE/2 - 1,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE/2 - 1),
 		cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
-	outl(cs->bcs[0].hw.tiger.rec_dma + NETJET_DMA_RXSIZE - 1,
+	outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1),
 		cs->hw.njet.base + NETJET_DMA_WRITE_END);
 	debugl1(cs, "tiger: dmacfg  %x/%x  pulse=%d",
 		inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
 		inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
 		bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
 	cs->hw.njet.last_is0 = 0;
+	cs->bcs[0].BC_SetStack = setstack_tiger;
+	cs->bcs[1].BC_SetStack = setstack_tiger;
+	cs->bcs[0].BC_Close = close_tigerstate;
+	cs->bcs[1].BC_Close = close_tigerstate;
 }
 
-static void
+void
 releasetiger(struct IsdnCardState *cs)
 {
 	if (cs->bcs[0].hw.tiger.send) {
-		pci_free_consistent(cs->hw.njet.pdev,
-				    NETJET_DMA_TXSIZE * sizeof(unsigned int),
-				    cs->bcs[0].hw.tiger.send,
-				    cs->bcs[0].hw.tiger.send_dma);
+		kfree(cs->bcs[0].hw.tiger.send);
 		cs->bcs[0].hw.tiger.send = NULL;
 	}
 	if (cs->bcs[1].hw.tiger.send) {
 		cs->bcs[1].hw.tiger.send = NULL;
 	}
 	if (cs->bcs[0].hw.tiger.rec) {
-		pci_free_consistent(cs->hw.njet.pdev,
-				    NETJET_DMA_RXSIZE * sizeof(unsigned int),
-				    cs->bcs[0].hw.tiger.rec,
-				    cs->bcs[0].hw.tiger.rec_dma);
+		kfree(cs->bcs[0].hw.tiger.rec);
 		cs->bcs[0].hw.tiger.rec = NULL;
 	}
 	if (cs->bcs[1].hw.tiger.rec) {
@@ -1025,11 +1022,11 @@
 }
 
 void
-netjet_release(struct IsdnCardState *cs)
+release_io_netjet(struct IsdnCardState *cs)
 {
 	byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
 	byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
 	releasetiger(cs);
-	hisax_release_resources(cs);
+	release_region(cs->hw.njet.base, 256);
 }
 
--- diff/drivers/isdn/hisax/netjet.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/netjet.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: netjet.h,v 2.5.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $
  *
  * NETjet common header file
  *
@@ -57,12 +57,10 @@
 
 #define HDLC_FLAG_VALUE	0x7e
 
-extern struct dc_hw_ops netjet_dc_ops;
-
-u8 NETjet_ReadIC(struct IsdnCardState *cs, u8 offset);
-void NETjet_WriteIC(struct IsdnCardState *cs, u8 offset, u8 value);
-void NETjet_ReadICfifo(struct IsdnCardState *cs, u8 *data, int size);
-void NETjet_WriteICfifo(struct IsdnCardState *cs, u8 *data, int size);
+u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
+void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
+void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
+void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
 
 void read_tiger(struct IsdnCardState *cs);
 void write_tiger(struct IsdnCardState *cs);
@@ -70,5 +68,5 @@
 void netjet_fill_dma(struct BCState *bcs);
 void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
 void inittiger(struct IsdnCardState *cs);
-void netjet_release(struct IsdnCardState *cs);
+void release_io_netjet(struct IsdnCardState *cs);
 
--- diff/drivers/isdn/hisax/niccy.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/hisax/niccy.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.15.6.6 2001/10/20 22:08:24 kai Exp $
+/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  * compatible (SAGEM cybermodem)
@@ -24,8 +24,7 @@
 #include <linux/isapnp.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.15.6.6 $";
-static spinlock_t niccy_lock = SPIN_LOCK_UNLOCKED;
+const char *niccy_revision = "$Revision: 1.21.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -47,127 +46,140 @@
 #define PCI_IRQ_DISABLE		0xff0000
 #define PCI_IRQ_ASSERT		0x800000
 
-static inline u8
-readreg(unsigned int ale, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&niccy_lock, flags);
 	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&niccy_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writereg(unsigned int ale, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&niccy_lock, flags);
 	byteout(ale, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&niccy_lock, flags);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
 	byteout(ale, off);
-	insb(adr, data, size);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
 	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
+	return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs->hw.niccy.hscx_ale,
-		       cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.niccy.hscx_ale,
+			cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
 	writereg(cs->hw.niccy.hscx_ale,
 		 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	readfifo(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
-		 hscx ? 0x40 : 0, data, size);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
+		cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
+		cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	writefifo(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
-		  hscx ? 0x40 : 0, data, size);
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
+		cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg  = hscx_read,
-	.write_reg = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
+		cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
 
 static irqreturn_t
 niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	
+	u_char val;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
 	if (cs->subtyp == NICCY_PCI) {
 		int ival;
 		ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
-		if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */
+		if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
+			spin_unlock_irqrestore(&cs->lock, flags);
 			return IRQ_NONE;
+		}
 		outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
 	}
-	return hscxisac_irq(intno, dev_id, regs);
+	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
 void
-niccy_release(struct IsdnCardState *cs)
+release_io_niccy(struct IsdnCardState *cs)
 {
 	if (cs->subtyp == NICCY_PCI) {
 		int val;
@@ -175,11 +187,15 @@
 		val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
 		val &= PCI_IRQ_DISABLE;
 		outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+		release_region(cs->hw.niccy.cfg_reg, 0x40);
+		release_region(cs->hw.niccy.isac, 4);
+	} else {
+		release_region(cs->hw.niccy.isac, 2);
+		release_region(cs->hw.niccy.isac_ale, 2);
 	}
-	hisax_release_resources(cs);
 }
 
-static int
+static void
 niccy_reset(struct IsdnCardState *cs)
 {
 	if (cs->subtyp == NICCY_PCI) {
@@ -189,78 +205,32 @@
 		val |= PCI_IRQ_ENABLE;
 		outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
 	}
-	return 0;
+	inithscxisac(cs, 3);
 }
 
-static struct card_ops niccy_ops = {
-	.init     = inithscxisac,
-	.reset    = niccy_reset,
-	.release  = niccy_release,
-	.irq_func = niccy_interrupt,
-};
-
-static int __init
-niccy_probe(struct IsdnCardState *cs)
+static int
+niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
-	       CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
-	       cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
-	cs->card_ops = &niccy_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		return -EBUSY;
-	return 0;
-}
-
-static int __init
-niccy_pnp_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = NICCY_PNP;
-	cs->irq = card->para[0];
-	cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
-	cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
-	cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
-	cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
-	cs->hw.niccy.cfg_reg = 0;
-
-	if (!request_io(&cs->rs, cs->hw.niccy.isac, 2, "niccy data"))
-		goto err;
-	if (!request_io(&cs->rs, cs->hw.niccy.isac_ale, 2, "niccy addr"))
-		goto err;
-	if (niccy_probe(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-niccy_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	u32 pci_ioaddr;
-
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = NICCY_PCI;
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.niccy.cfg_reg = pci_resource_start(pdev, 0);
-	pci_ioaddr = pci_resource_start(pdev, 1);
-	cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
-	cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
-	cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
-	cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
-	if (!request_io(&cs->rs, cs->hw.niccy.isac, 4, "niccy"))
-		goto err;
-	if (!request_io(&cs->rs, cs->hw.niccy.cfg_reg, 0x40, "niccy pci"))
-		goto err;
-	if (niccy_probe(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			niccy_reset(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_niccy(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			niccy_reset(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 static struct pci_dev *niccy_dev __initdata = NULL;
@@ -271,62 +241,149 @@
 int __init
 setup_niccy(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, niccy_revision);
 	printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_NICCY)
+		return (0);
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev  *pd;
+		struct pnp_dev *pnp_d = NULL;
+		int err;
 
-		if ((pb = pnp_find_card(
+		if ((pnp_c = pnp_find_card(
 			ISAPNP_VENDOR('S', 'D', 'A'),
 			ISAPNP_FUNCTION(0x0150), pnp_c))) {
-			pnp_c = pb;
-			pd = NULL;
-			if (!(pd = pnp_find_dev(pnp_c,
+			if (!(pnp_d = pnp_find_dev(pnp_c,
 				ISAPNP_VENDOR('S', 'D', 'A'),
-				ISAPNP_FUNCTION(0x0150), pd))) {
+				ISAPNP_FUNCTION(0x0150), pnp_d))) {
 				printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
 				return (0);
 			}
-			if (pnp_device_attach(pd) < 0) {
-				printk(KERN_ERR "NiccyPnP: attach failed\n");
-				return 0;
-			}
-			if (pnp_activate_dev(pd) < 0) {
-				printk(KERN_ERR "NiccyPnP: activate failed\n");
-				pnp_device_detach(pd);
-				return 0;
+			pnp_disable_dev(pnp_d);
+			err = pnp_activate_dev(pnp_d);
+			if (err<0) {
+				printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+					__FUNCTION__, err);
+				return(0);
 			}
-			if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0) || !pnp_port_valid(pd, 1)) {
+			card->para[1] = pnp_port_start(pnp_d, 0);
+			card->para[2] = pnp_port_start(pnp_d, 1);
+			card->para[0] = pnp_irq(pnp_d, 0);;
+			if (!card->para[0] || !card->para[1] || !card->para[2]) {
 				printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
-					pnp_irq(pd, 0), pnp_port_start(pd, 0), pnp_port_start(pd, 1));
-				pnp_device_detach(pd);
+					card->para[0], card->para[1], card->para[2]);
+				pnp_disable_dev(pnp_d);
 				return(0);
 			}
-			card->para[1] = pnp_port_start(pd, 0);
-			card->para[2] = pnp_port_start(pd, 1);
-			card->para[0] = pnp_irq(pd, 0);
 		} else {
 			printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
 		}
 	}
 #endif
 	if (card->para[1]) {
-		if (niccy_pnp_probe(card->cs, card) < 0)
-			return 0;
-		return 1;
+		cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
+		cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
+		cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
+		cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
+		cs->hw.niccy.cfg_reg = 0;
+		cs->subtyp = NICCY_PNP;
+		cs->irq = card->para[0];
+		if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
+			printk(KERN_WARNING
+				"HiSax: %s data port %x-%x already in use\n",
+				CardType[card->typ],
+				cs->hw.niccy.isac,
+				cs->hw.niccy.isac + 1);
+			return (0);
+		}
+		if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
+			printk(KERN_WARNING
+				"HiSax: %s address port %x-%x already in use\n",
+				CardType[card->typ],
+				cs->hw.niccy.isac_ale,
+				cs->hw.niccy.isac_ale + 1);
+			release_region(cs->hw.niccy.isac, 2);
+			return (0);
+		}
 	} else {
-#ifdef CONFIG_PCI
+#if CONFIG_PCI
+		u_int pci_ioaddr;
+		cs->subtyp = 0;
 		if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
 			PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
-			if (niccy_pci_probe(card->cs, niccy_dev) < 0)
-				return 0;
-			return 1;
+			if (pci_enable_device(niccy_dev))
+				return(0);
+			/* get IRQ */
+			if (!niccy_dev->irq) {
+				printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->irq = niccy_dev->irq;
+			cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
+			if (!cs->hw.niccy.cfg_reg) {
+				printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+				return(0);
+			}
+			pci_ioaddr = pci_resource_start(niccy_dev, 1);
+			if (!pci_ioaddr) {
+				printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+			cs->subtyp = NICCY_PCI;
+		} else {
+			printk(KERN_WARNING "Niccy: No PCI card found\n");
+			return(0);
+		}
+		cs->irq_flags |= SA_SHIRQ;
+		cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
+		cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
+		cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
+		cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
+		if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
+			printk(KERN_WARNING
+				"HiSax: %s data port %x-%x already in use\n",
+				CardType[card->typ],
+				cs->hw.niccy.isac,
+				cs->hw.niccy.isac + 4);
+			return (0);
+		}
+		if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
+			printk(KERN_WARNING
+			       "HiSax: %s pci port %x-%x already in use\n",
+				CardType[card->typ],
+				cs->hw.niccy.cfg_reg,
+				cs->hw.niccy.cfg_reg + 0x40);
+			release_region(cs->hw.niccy.isac, 4);
+			return (0);
 		}
+#else
+		printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
+		printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
+		return (0);
 #endif /* CONFIG_PCI */
 	}
-	return 0;
+	printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
+		CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+		cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &niccy_card_msg;
+	cs->irq_func = &niccy_interrupt;
+	ISACVersion(cs, "Niccy:");
+	if (HscxVersion(cs, "Niccy:")) {
+		printk(KERN_WARNING
+		    "Niccy: wrong HSCX versions check IO address\n");
+		release_io_niccy(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/nj_s.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/nj_s.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: nj_s.c,v 2.7.6.6 2001/09/23 22:24:50 kai Exp $
+/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -15,43 +15,74 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_S_revision = "$Revision: 2.7.6.6 $";
+const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+	return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
 
 static irqreturn_t
-nj_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val, sval;
+	u_char val, s1val, s0val;
+	u_long flags;
 
-	spin_lock(&cs->lock);
-	if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
-		NETJET_ISACIRQ)) {
+	spin_lock_irqsave(&cs->lock, flags);
+	s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1);
+	if (!(s1val & NETJET_ISACIRQ)) {
 		val = NETjet_ReadIC(cs, ISAC_ISTA);
 		if (cs->debug & L1_DEB_ISAC)
-			debugl1(cs, "tiger: i1 %x %x", sval, val);
+			debugl1(cs, "tiger: i1 %x %x", s1val, val);
 		if (val) {
 			isac_interrupt(cs, val);
 			NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
 			NETjet_WriteIC(cs, ISAC_MASK, 0x0);
 		}
-	}
+		s1val = 1;
+	} else
+		s1val = 0;
+	/* 
+	 * read/write stat0 is better, because lower IRQ rate
+	 * Note the IRQ is on for 125 us if a condition match
+	 * thats long on modern CPU and so the IRQ is reentered
+	 * all the time.
+	 */
+	s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0);
+	if ((s0val | s1val)==0) { // shared IRQ
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
+	} 
+	if (s0val)
+		byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
 	/* start new code 13/07/00 GE */
 	/* set bits in sval to indicate which page is free */
 	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
 		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
 		/* the 2nd write page is free */
-		sval = 0x08;
+		s0val = 0x08;
 	else	/* the 1st write page is free */
-		sval = 0x04;	
+		s0val = 0x04;	
 	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
 		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
 		/* the 2nd read page is free */
-		sval = sval | 0x02;
+		s0val |= 0x02;
 	else	/* the 1st read page is free */
-		sval = sval | 0x01;	
-	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+		s0val |= 0x01;	
+	if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
 	{
-		cs->hw.njet.irqstat0 = sval;
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n",
+				cs->hw.njet.last_is0, s0val);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return IRQ_HANDLED;;
+		}
+		cs->hw.njet.irqstat0 = s0val;
 		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 
 			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
 			/* we have a read dma int */
@@ -61,112 +92,58 @@
 			/* we have a write dma int */
 			write_tiger(cs);
 		/* end new code 13/07/00 GE */
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	}
-/*	if (!testcnt--) {
-		cs->hw.njet.dmactrl = 0;
-		byteout(cs->hw.njet.base + NETJET_DMACTRL,
-			cs->hw.njet.dmactrl);
-		byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
-	}
-*/
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static int
-nj_s_reset(struct IsdnCardState *cs)
+static void
+reset_netjet_s(struct IsdnCardState *cs)
 {
 	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	cs->hw.njet.ctrl_reg = 0x40;  /* Reset Off and status read clear */
+	mdelay(10);
+	cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
 	/* now edge triggered for TJ320 GE 13/07/00 */
+	/* see comment in IRQ function */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	mdelay(10);
 	cs->hw.njet.auxd = 0;
 	cs->hw.njet.dmactrl = 0;
 	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
 	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-	return 0;
 }
 
-static void
-nj_s_init(struct IsdnCardState *cs)
-{
-	inittiger(cs);
-	initisac(cs);
-}
-
-static struct card_ops nj_s_ops = {
-	.init     = nj_s_init,
-	.reset    = nj_s_reset,
-	.release  = netjet_release,
-	.irq_func = nj_s_interrupt,
-};
-
-static int __init
-nj_s_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
+static int
+NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	pci_set_master(pdev);
+	u_long flags;
 
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.njet.pdev = pdev;
-	cs->hw.njet.base = pci_resource_start(pdev, 0);
-	if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "netjet-s isdn"))
-		return 0;
-	
-	cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-	cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
-	
-	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	
-	cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	
-	cs->hw.njet.auxd = 0xC0;
-	cs->hw.njet.dmactrl = 0;
-	
-	byteout(cs->hw.njet.auxa, 0);
-	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
-	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
-	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-
-	switch ((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3) {
-	case 0 :
-		break;
-	case 3 :
-		printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
-		goto err;
-	default :
-		printk(KERN_WARNING "NETjet-S: No PCI card found\n" );
-		goto err;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_netjet_s(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			return(0);
+		case CARD_INIT:
+			reset_netjet_s(cs);
+			inittiger(cs);
+			spin_lock_irqsave(&cs->lock, flags);
+			clear_pending_isac_ints(cs);
+			initisac(cs);
+			/* Reenable all IRQ */
+			cs->writeisac(cs, ISAC_MASK, 0);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	printk(KERN_INFO
-		"NETjet-S: PCI card configured at %#lx IRQ %d\n",
-		cs->hw.njet.base, cs->irq);
-	
-	nj_s_reset(cs);
-	cs->irq_flags |= SA_SHIRQ;
-	cs->card_ops = &nj_s_ops;
-	isac_setup(cs, &netjet_dc_ops);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return(0);
 }
 
 static struct pci_dev *dev_netjet __initdata = NULL;
@@ -174,32 +151,116 @@
 int __init
 setup_netjet_s(struct IsdnCard *card)
 {
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
 	strcpy(tmp, NETjet_S_revision);
-	printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n",
-	       HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_NETJET_S)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+#if CONFIG_PCI
 
-	dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				     PCI_DEVICE_ID_TIGERJET_300, dev_netjet);
-	if (dev_netjet) {
-		/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
-		if (dev_netjet->subsystem_vendor == 0x55 &&
-		    dev_netjet->subsystem_device == 0x02) {
-			printk(KERN_WARNING "Netjet: You tried to load this "
-			       "driver with an incompatible TigerJet-card\n");
-			printk(KERN_WARNING "Use type=41 for Formula-n "
-			       "enter:now ISDN PCI and compatible\n");
-			return 0;
+	for ( ;; )
+	{
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			pci_set_master(dev_netjet);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+			if ((dev_netjet->subsystem_vendor == 0x55) &&
+				(dev_netjet->subsystem_device == 0x02)) {
+				printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+				printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+				return(0);
+			}
+			/* end new code */
+		} else {
+			printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+			return(0);
 		}
-		if (nj_s_probe(card->cs, dev_netjet))
-			return 1;
-		return 0;
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+
+		cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		mdelay(10);
+
+		cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		mdelay(10);
+
+		cs->hw.njet.auxd = 0xC0;
+		cs->hw.njet.dmactrl = 0;
+
+		byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+		byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+		switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
+		{
+			case 0 :
+				break;
+
+			case 3 :
+				printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
+				continue;
+
+			default :
+				printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
+				return 0;
+                }
+                break;
 	}
-	printk(KERN_WARNING "NETjet-S: No PCI card found\n");
-	return 0;
-}
+#else
+
+	printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
 
+	printk(KERN_INFO
+		"NETjet-S: PCI card configured at %#lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %#lx-%#lx already in use\n",
+		       CardType[card->typ],
+		       cs->hw.njet.base,
+		       cs->hw.njet.base + bytecnt);
+		return (0);
+	}
+	cs->readisac  = &NETjet_ReadIC;
+	cs->writeisac = &NETjet_WriteIC;
+	cs->readisacfifo  = &NETjet_ReadICfifo;
+	cs->writeisacfifo = &NETjet_WriteICfifo;
+	cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	setup_isac(cs);
+	cs->cardmsg = &NETjet_S_card_msg;
+	cs->irq_func = &netjet_s_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ISACVersion(cs, "NETjet-S:");
+	return (1);
+}
--- diff/drivers/isdn/hisax/nj_u.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/nj_u.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: nj_u.c,v 2.8.6.6 2001/09/23 22:24:50 kai Exp $ 
+/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $ 
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -15,15 +15,25 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_U_revision = "$Revision: 2.8.6.6 $";
+const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+	return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
 
 static irqreturn_t
-nj_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val, sval;
+	u_char val, sval;
+	u_long flags;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
 		NETJET_ISACIRQ)) {
 		val = NETjet_ReadIC(cs, ICC_ISTA);
@@ -51,6 +61,10 @@
 		sval = sval | 0x01;	
 	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
 	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return IRQ_HANDLED;
+		}
 		cs->hw.njet.irqstat0 = sval;
 		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 
 			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
@@ -61,113 +75,58 @@
 			/* we have a write dma int */
 			write_tiger(cs);
 		/* end new code 13/07/00 GE */
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	}
-/*	if (!testcnt--) {
-		cs->hw.njet.dmactrl = 0;
-		byteout(cs->hw.njet.base + NETJET_DMACTRL,
-			cs->hw.njet.dmactrl);
-		byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
-	}
-*/
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static int
-nj_u_reset(struct IsdnCardState *cs)
+static void
+reset_netjet_u(struct IsdnCardState *cs)
 {
 	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	mdelay(10);
 	cs->hw.njet.ctrl_reg = 0x40;  /* Reset Off and status read clear */
 	/* now edge triggered for TJ320 GE 13/07/00 */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-
+	mdelay(10);
 	cs->hw.njet.auxd = 0xC0;
 	cs->hw.njet.dmactrl = 0;
 	byteout(cs->hw.njet.auxa, 0);
 	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
 	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-	return 0;
 }
 
-static void
-nj_u_init(struct IsdnCardState *cs)
+static int
+NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	inittiger(cs);
-	initicc(cs);
-	/* Reenable all IRQ */
-	NETjet_WriteIC(cs, ICC_MASK, 0);
-}
-
-static struct card_ops nj_u_ops = {
-	.init     = nj_u_init,
-	.reset    = nj_u_reset,
-	.release  = netjet_release,
-	.irq_func = nj_u_interrupt,
-};
-
-static int __init
-nj_u_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	pci_set_master(pdev);
-
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.njet.pdev = pdev;
-	cs->hw.njet.base = pci_resource_start(pdev, 0);
-	if (!request_io(&cs->rs, cs->hw.njet.base, 0x100, "netspider-u isdn"))
-		goto err;
-	
-	cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-	cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
-
-	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	
-	cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	
-	cs->hw.njet.auxd = 0xC0;
-	cs->hw.njet.dmactrl = 0;
-	
-	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
-	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
-	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+	u_long flags;
 
-	switch ((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3)	{
-	case 3:
-		break;
-	case 0:
-		printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
-		goto err;
-	default:
-		printk(KERN_WARNING "NETspider-U: No PCI card found\n" );
-		goto err;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_netjet_u(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inittiger(cs);
+			reset_netjet_u(cs);
+			clear_pending_icc_ints(cs);
+			initicc(cs);
+			/* Reenable all IRQ */
+			cs->writeisac(cs, ICC_MASK, 0);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	printk(KERN_INFO "NETspider-U: PCI card configured at %#lx IRQ %d\n",
-	       cs->hw.njet.base, cs->irq);
-
-	nj_u_reset(cs);
-	cs->card_ops = &nj_u_ops;
-	icc_setup(cs, &netjet_dc_ops);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return(0);
 }
 
 static struct pci_dev *dev_netjet __initdata = NULL;
@@ -175,21 +134,111 @@
 int __init
 setup_netjet_u(struct IsdnCard *card)
 {
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
+#if CONFIG_PCI
+#endif
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
 	strcpy(tmp, NETjet_U_revision);
-	printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-	
-	dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				     PCI_DEVICE_ID_TIGERJET_300, dev_netjet);
-	if (dev_netjet) {
-		if (nj_u_probe(card->cs, dev_netjet))
-			return 1;
-		return 0;
+	printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_NETJET_U)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+#if CONFIG_PCI
+
+	for ( ;; )
+	{
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			pci_set_master(dev_netjet);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_WARNING "NETspider-U: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+		mdelay(10);
+
+		cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		mdelay(10);
+
+		cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+		mdelay(10);
+
+		cs->hw.njet.auxd = 0xC0;
+		cs->hw.njet.dmactrl = 0;
+
+		byteout(cs->hw.njet.auxa, 0);
+		byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+		byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+		switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
+		{
+			case 3 :
+				break;
+
+			case 0 :
+				printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
+				continue;
+
+			default :
+				printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
+				return 0;
+                }
+                break;
+	}
+#else
+
+	printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"NETspider-U: PCI card configured at %#lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %#lx-%#lx already in use\n",
+		       CardType[card->typ],
+		       cs->hw.njet.base,
+		       cs->hw.njet.base + bytecnt);
+		return (0);
 	}
-	printk(KERN_WARNING "NETspider-U: No PCI card found\n");
-	return 0;
+	setup_icc(cs);
+	cs->readisac  = &NETjet_ReadIC;
+	cs->writeisac = &NETjet_WriteIC;
+	cs->readisacfifo  = &NETjet_ReadICfifo;
+	cs->writeisacfifo = &NETjet_WriteICfifo;
+	cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &NETjet_U_card_msg;
+	cs->irq_func = &netjet_u_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ICCVersion(cs, "NETspider-U:");
+	return (1);
 }
--- diff/drivers/isdn/hisax/q931.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/q931.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.10.6.3 2001/09/23 22:24:50 kai Exp $
+/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
  *
  * code to decode ITU Q.931 call control messages
  *
@@ -21,9 +21,9 @@
 #include "l3_1tr6.h"
 
 void
-iecpy(u8 * dest, u8 * iestart, int ieoffset)
+iecpy(u_char * dest, u_char * iestart, int ieoffset)
 {
-	u8 *p;
+	u_char *p;
 	int l;
 
 	p = iestart + ieoffset + 2;
@@ -38,7 +38,7 @@
  */
 static
 struct MessageType {
-	u8 nr;
+	u_char nr;
 	char *descr;
 } mtlist[] = {
 
@@ -198,7 +198,7 @@
 
 
 static int
-prbits(char *dest, u8 b, int start, int len)
+prbits(char *dest, u_char b, int start, int len)
 {
 	char *dp = dest;
 
@@ -214,8 +214,8 @@
 }
 
 static
-u8 *
-skipext(u8 * p)
+u_char *
+skipext(u_char * p)
 {
 	while (!(*p++ & 0x80));
 	return (p);
@@ -230,7 +230,7 @@
 
 static
 struct CauseValue {
-	u8 nr;
+	u_char nr;
 	char *edescr;
 	char *ddescr;
 } cvlist[] = {
@@ -442,11 +442,11 @@
 
 static
 int
-prcause(char *dest, u8 * p)
+prcause(char *dest, u_char * p)
 {
-	u8 *end;
+	u_char *end;
 	char *dp = dest;
-	u_int i, cause;
+	int i, cause;
 
 	end = p + p[1] + 1;
 	p += 2;
@@ -519,7 +519,7 @@
 int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
 
 static int
-prcause_1tr6(char *dest, u8 * p)
+prcause_1tr6(char *dest, u_char * p)
 {
 	char *dp = dest;
 	int i, cause;
@@ -554,7 +554,7 @@
 }
 
 static int
-prchident(char *dest, u8 * p)
+prchident(char *dest, u_char * p)
 {
 	char *dp = dest;
 
@@ -566,7 +566,7 @@
 }
 
 static int
-prcalled(char *dest, u8 * p)
+prcalled(char *dest, u_char * p)
 {
 	int l;
 	char *dp = dest;
@@ -583,7 +583,7 @@
 	return (dp - dest);
 }
 static int
-prcalling(char *dest, u8 * p)
+prcalling(char *dest, u_char * p)
 {
 	int l;
 	char *dp = dest;
@@ -610,7 +610,7 @@
 
 static
 int
-prbearer(char *dest, u8 * p)
+prbearer(char *dest, u_char * p)
 {
 	char *dp = dest, ch;
 
@@ -658,10 +658,10 @@
 
 static
 int
-prbearer_ni1(char *dest, u8 * p)
+prbearer_ni1(char *dest, u_char * p)
 {
 	char *dp = dest;
-	u8 len;
+	u_char len;
 
 	p++;
 	len = *p++;
@@ -715,7 +715,7 @@
 }
 
 static int
-general(char *dest, u8 * p)
+general(char *dest, u_char * p)
 {
 	char *dp = dest;
 	char ch = ' ';
@@ -742,7 +742,7 @@
 }
 
 static int
-general_ni1(char *dest, u8 * p)
+general_ni1(char *dest, u_char * p)
 {
 	char *dp = dest;
 	char ch = ' ';
@@ -769,7 +769,7 @@
 }
 
 static int
-prcharge(char *dest, u8 * p)
+prcharge(char *dest, u_char * p)
 {
 	char *dp = dest;
 	int l;
@@ -786,7 +786,7 @@
 	return (dp - dest);
 }
 static int
-prtext(char *dest, u8 * p)
+prtext(char *dest, u_char * p)
 {
 	char *dp = dest;
 	int l;
@@ -802,7 +802,7 @@
 }
 
 static int
-prfeatureind(char *dest, u8 * p)
+prfeatureind(char *dest, u_char * p)
 {
 	char *dp = dest;
 
@@ -839,7 +839,7 @@
 
 static
 struct DTag { /* Display tags */
-	u8 nr;
+	u_char nr;
 	char *descr;
 } dtaglist[] = {
 	{ 0x82, "Continuation" },
@@ -868,11 +868,10 @@
 #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
 
 static int
-disptext_ni1(char *dest, u8 * p)
+disptext_ni1(char *dest, u_char * p)
 {
 	char *dp = dest;
-	int l, tag, len;
-	u_int i;
+	int l, tag, len, i;
 
 	p++;
 	l = *p++ - 1;
@@ -908,7 +907,7 @@
 	return (dp - dest);
 }
 static int
-display(char *dest, u8 * p)
+display(char *dest, u_char * p)
 {
 	char *dp = dest;
 	char ch = ' ';
@@ -937,7 +936,7 @@
 }
 
 int
-prfacility(char *dest, u8 * p)
+prfacility(char *dest, u_char * p)
 {
 	char *dp = dest;
 	int l, l2;
@@ -968,9 +967,9 @@
 
 static
 struct InformationElement {
-	u8 nr;
+	u_char nr;
 	char *descr;
-	int (*f) (char *, u8 *);
+	int (*f) (char *, u_char *);
 } ielist[] = {
 
 	{
@@ -1149,11 +1148,11 @@
 #define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
 
 int
-QuickHex(char *txt, u8 * p, int cnt)
+QuickHex(char *txt, u_char * p, int cnt)
 {
 	register int i;
 	register char *t = txt;
-	register u8 w;
+	register u_char w;
 
 	for (i = 0; i < cnt; i++) {
 		*t++ = ' ';
@@ -1173,7 +1172,7 @@
 }
 
 void
-LogFrame(struct IsdnCardState *cs, u8 * buf, int size)
+LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
 {
 	char *dp;
 
@@ -1197,11 +1196,11 @@
 void
 dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
 {
-	u8 *bend, *buf;
+	u_char *bend, *buf;
 	char *dp;
 	unsigned char pd, cr_l, cr, mt;
 	unsigned char sapi, tei, ftyp;
-	u_int i, cset = 0, cs_old = 0, cs_fest = 0;
+	int i, cset = 0, cs_old = 0, cs_fest = 0;
 	int size, finish = 0;
 
 	if (skb->len < 3)
--- diff/drivers/isdn/hisax/s0box.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/s0box.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: s0box.c,v 2.4.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for Creatix S0BOX
  *
@@ -17,16 +17,10 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.4.6.2 $";
-static spinlock_t s0box_lock = SPIN_LOCK_UNLOCKED;
+const char *s0box_revision = "$Revision: 2.6.2.4 $";
 
 static inline void
-writereg(struct IsdnCardState *cs, int addr, u8 off, u8 val)
-{
-	unsigned long flags;
-	unsigned long padr = cs->hw.teles3.cfg_reg;
-
-	spin_lock_irqsave(&s0box_lock, flags);
+writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
 	outb_p(0x1c,padr+2);
 	outb_p(0x14,padr+2);
 	outb_p((addr+off)&0x7f,padr);
@@ -35,21 +29,16 @@
 	outb_p(0x17,padr+2);
 	outb_p(0x14,padr+2);
 	outb_p(0x1c,padr+2);
-	spin_unlock_irqrestore(&s0box_lock, flags);
 }
 
-static u8 nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
+static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
 			 0, 0, 0, 0, 0, 0, 0, 0,
 			 0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ;
 
-static inline u8
-readreg(struct IsdnCardState *cs, int addr, u8 off)
-{
-	u8 n1, n2;
-	unsigned long flags;
-	unsigned long padr = cs->hw.teles3.cfg_reg;
+static inline u_char
+readreg(unsigned int padr, signed int addr, u_char off) {
+	register u_char n1, n2;
 
-	spin_lock_irqsave(&s0box_lock, flags);
 	outb_p(0x1c,padr+2);
 	outb_p(0x14,padr+2);
 	outb_p((addr+off)|0x80,padr);
@@ -60,16 +49,14 @@
 	n2 = (inb_p(padr+1) >> 3) & 0x17;
 	outb_p(0x14,padr+2);
 	outb_p(0x1c,padr+2);
-	spin_unlock_irqrestore(&s0box_lock, flags);
 	return nibtab[n1] | (nibtab[n2] << 4);
 }
 
 static inline void
-read_fifo(struct IsdnCardState *cs, signed int adr, u8 * data, int size)
+read_fifo(unsigned int padr, signed int adr, u_char * data, int size)
 {
 	int i;
-	u8 n1, n2;
-	unsigned long padr = cs->hw.teles3.cfg_reg;
+	register u_char n1, n2;
 	
 	outb_p(0x1c, padr+2);
 	outb_p(0x14, padr+2);
@@ -84,14 +71,13 @@
 	}
 	outb_p(0x14,padr+2);
 	outb_p(0x1c,padr+2);
+	return;
 }
 
 static inline void
-write_fifo(struct IsdnCardState *cs, signed int adr, u8 * data, int size)
+write_fifo(unsigned int padr, signed int adr, u_char * data, int size)
 {
 	int i;
-	unsigned long padr = cs->hw.teles3.cfg_reg;
-
 	outb_p(0x1c, padr+2);
 	outb_p(0x14, padr+2);
 	outb_p(adr&0x7f, padr);
@@ -102,79 +88,140 @@
 	}
 	outb_p(0x14,padr+2);
 	outb_p(0x1c,padr+2);
+	return;
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.teles3.isac, offset);
+	return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.teles3.isac, offset, value);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	read_fifo(cs, cs->hw.teles3.isacfifo, data, size);
+	read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	write_fifo(cs, cs->hw.teles3.isacfifo, data, size);
+	write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs, cs->hw.teles3.hscx[hscx], offset);
+	return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.teles3.hscx[hscx], offset, value);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	read_fifo(cs, cs->hw.teles3.hscxfifo[hscx], data, size);
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 5
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+	int count = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	count++;
+	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	if (count >= MAXCOUNT)
+		printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+void
+release_io_s0box(struct IsdnCardState *cs)
+{
+	release_region(cs->hw.teles3.cfg_reg, 8);
+}
+
+static int
+S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			break;
+		case CARD_RELEASE:
+			release_io_s0box(cs);
+			break;
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			break;
+		case CARD_TEST:
+			break;
+	}
+	return(0);
 }
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+int __init
+setup_s0box(struct IsdnCard *card)
 {
-	write_fifo(cs, cs->hw.teles3.hscxfifo[hscx], data, size);
-}
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
- 
-static struct card_ops s0box_ops = {
-	.init     = inithscxisac,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
+	strcpy(tmp, s0box_revision);
+	printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_S0BOX)
+		return (0);
 
-static int __init
-s0box_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
 	cs->hw.teles3.cfg_reg = card->para[1];
 	cs->hw.teles3.hscx[0] = -0x20;
 	cs->hw.teles3.hscx[1] = 0x0;
@@ -183,32 +230,37 @@
 	cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
 	cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
 	cs->irq = card->para[0];
-	if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O"))
-		goto err;
+	if (!request_region(cs->hw.teles3.cfg_reg,8, "S0Box parallel I/O")) {
+		printk(KERN_WARNING
+		       "HiSax: %s ports %x-%x already in use\n",
+		       CardType[cs->typ],
+                       cs->hw.teles3.cfg_reg,
+                       cs->hw.teles3.cfg_reg + 7);
+		return 0;
+	}
 	printk(KERN_INFO
-	       "HiSax: %s config irq:%d isac:0x%x  cfg:0x%x\n",
-	       CardType[cs->typ], cs->irq,
-	       cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
+		"HiSax: %s config irq:%d isac:0x%x  cfg:0x%x\n",
+		CardType[cs->typ], cs->irq,
+		cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
 	printk(KERN_INFO
-	       "HiSax: hscx A:0x%x  hscx B:0x%x\n",
-	       cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
-	cs->card_ops = &s0box_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-int __init
-setup_s0box(struct IsdnCard *card)
-{
-	char tmp[64];
-
-	strcpy(tmp, s0box_revision);
-	printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
-	if (s0box_probe(card->cs, card))
-		return 0;
-	return 1;
+		"HiSax: hscx A:0x%x  hscx B:0x%x\n",
+		cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &S0Box_card_msg;
+	cs->irq_func = &s0box_interrupt;
+	ISACVersion(cs, "S0Box:");
+	if (HscxVersion(cs, "S0Box:")) {
+		printk(KERN_WARNING
+		       "S0Box: wrong HSCX versions check IO address\n");
+		release_io_s0box(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/saphir.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/saphir.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: saphir.c,v 1.8.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for HST Saphir 1
  *
@@ -19,8 +19,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.8.6.2 $";
-static spinlock_t saphir_lock = SPIN_LOCK_UNLOCKED;
+static char *saphir_rev = "$Revision: 1.10.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -32,138 +31,160 @@
 #define SPARE_REG	4
 #define RESET_REG	5
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&saphir_lock, flags);
-	byteout(cs->hw.saphir.ale, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&saphir_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&saphir_lock, flags);
-	byteout(cs->hw.saphir.ale, off);
-	byteout(adr, data);
-	spin_unlock_irqrestore(&saphir_lock, flags);
+	byteout(ale, off);
+	insb(adr, data, size);
 }
 
+
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 *data, int size)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.saphir.ale, off);
-	insb(adr, data, size);
+	byteout(ale, off);
+	byteout(adr, data);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 *data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.saphir.ale, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.saphir.isac, offset);
+	return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.saphir.isac, offset, value);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.saphir.isac, 0, data, size);
+	readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.saphir.isac, 0, data, size);
+	writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs, cs->hw.saphir.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
+		offset + (hscx ? 0x40 : 0)));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.saphir.hscx, offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
+		offset + (hscx ? 0x40 : 0), value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	readfifo(cs, cs->hw.saphir.hscx, hscx ? 0x40 : 0, data, size);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
+		cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
+		cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	writefifo(cs, cs->hw.saphir.hscx, hscx ? 0x40 : 0, data, size);
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
+		cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
+		cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+#include "hscx_irq.c"
 
 static irqreturn_t
 saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	irqreturn_t ret;
+	u_char val;
+	u_long flags;
 
-	ret = hscxisac_irq(intno, dev_id, regs);
-	mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
-	return ret;
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	/* Watchdog */
+	if (cs->hw.saphir.timer.function) 
+		mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
+	else
+		printk(KERN_WARNING "saphir: Spurious timer!\n");
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
+	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
 static void
 SaphirWatchDog(struct IsdnCardState *cs)
 {
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
         /* 5 sec WatchDog, so read at least every 4 sec */
-	isac_read(cs, ISAC_RBCH);
+	cs->readisac(cs, ISAC_RBCH);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
 }
 
-static void
-saphir_release(struct IsdnCardState *cs)
+void
+release_io_saphir(struct IsdnCardState *cs)
 {
 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
-	del_timer_sync(&cs->hw.saphir.timer);
+	del_timer(&cs->hw.saphir.timer);
 	cs->hw.saphir.timer.function = NULL;
-	hisax_release_resources(cs);
+	if (cs->hw.saphir.cfg_reg)
+		release_region(cs->hw.saphir.cfg_reg, 6);
 }
 
 static int
 saphir_reset(struct IsdnCardState *cs)
 {
-	u8 irq_val;
+	u_char irq_val;
 
 	switch(cs->irq) {
 		case 5: irq_val = 0;
@@ -186,66 +207,94 @@
 	}
 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
+	mdelay(10);
 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
+	mdelay(10);
 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
 	byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
 	return (0);
 }
 
-static struct card_ops saphir_ops = {
-	.init     = inithscxisac,
-	.reset    = saphir_reset,
-	.release  = saphir_release,
-	.irq_func = saphir_interrupt,
-};
+static int
+saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			saphir_reset(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_saphir(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
+}
 
-static int __init
-saphir_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+
+int __init
+setup_saphir(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, saphir_rev);
+	printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
+		return (0);
+
+	/* IO-Ports */
 	cs->hw.saphir.cfg_reg = card->para[1];
 	cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
 	cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
 	cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
 	cs->irq = card->para[0];
-
-	if (!request_io(&cs->rs, cs->hw.saphir.cfg_reg, 6, "saphir"))
-		goto err;
+	if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) {
+		printk(KERN_WARNING
+			"HiSax: %s config port %x-%x already in use\n",
+			CardType[card->typ],
+			cs->hw.saphir.cfg_reg,
+			cs->hw.saphir.cfg_reg + 5);
+		return (0);
+	}
 
 	printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
-	       CardType[cs->typ], cs->irq, cs->hw.saphir.cfg_reg);
+		CardType[cs->typ], cs->irq, cs->hw.saphir.cfg_reg);
 
-	if (saphir_reset(cs))
-		goto err;
-
-	cs->card_ops = &saphir_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-
-	init_timer(&cs->hw.saphir.timer);
+	setup_isac(cs);
 	cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
 	cs->hw.saphir.timer.data = (long) cs;
+	init_timer(&cs->hw.saphir.timer);
 	cs->hw.saphir.timer.expires = jiffies + 4*HZ;
 	add_timer(&cs->hw.saphir.timer);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-int __init
-setup_saphir(struct IsdnCard *card)
-{
-	char tmp[64];
-
-	strcpy(tmp, saphir_rev);
-	printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-
-	if (saphir_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	if (saphir_reset(cs)) {
+		release_io_saphir(cs);
+		return (0);
+	}
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &saphir_card_msg;
+	cs->irq_func = &saphir_interrupt;
+	ISACVersion(cs, "saphir:");
+	if (HscxVersion(cs, "saphir:")) {
+		printk(KERN_WARNING
+		    "saphir: wrong HSCX versions check IO address\n");
+		release_io_saphir(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/sedlbauer.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/sedlbauer.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.25.6.6 2001/09/23 22:24:51 kai Exp $
+/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $
  *
  * low level stuff for Sedlbauer cards
  * includes support for the Sedlbauer speed star (speed star II),
@@ -50,16 +50,16 @@
 #include <linux/isapnp.h>
 
 extern const char *CardType[];
-static spinlock_t sedlbauer_lock = SPIN_LOCK_UNLOCKED; 
 
-const char *Sedlbauer_revision = "$Revision: 1.25.6.6 $";
+const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+",
 	"speed win II / ISDN PC/104", "speed star II", "speed pci",
-	"speed fax+ pyramid", "speed fax+ pci"};
+	"speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
 
 #define PCI_SUBVENDOR_SPEEDFAX_PYRAMID	0x51
+#define PCI_SUBVENDOR_HST_SAPHIR3	0x52
 #define PCI_SUBVENDOR_SEDLBAUER_PCI	0x53
 #define PCI_SUBVENDOR_SPEEDFAX_PCI	0x54
 #define PCI_SUB_ID_SEDLBAUER		0x01
@@ -72,7 +72,9 @@
 #define SEDL_SPEED_PCI   	6
 #define SEDL_SPEEDFAX_PYRAMID	7
 #define SEDL_SPEEDFAX_PCI	8
+#define HST_SAPHIR3		9
 
+#define SEDL_CHIP_TEST		0
 #define SEDL_CHIP_ISAC_HSCX	1
 #define SEDL_CHIP_ISAC_ISAR	2
 #define SEDL_CHIP_IPAC		3
@@ -117,209 +119,264 @@
 
 #define SEDL_RESET      0x3	/* same as DOS driver */
 
-static inline u8
-readreg(struct IsdnCardState *cs, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	u8 ret;
-	unsigned long flags;
+	register u_char ret;
 
-	spin_lock_irqsave(&sedlbauer_lock, flags);
-	byteout(cs->hw.sedl.adr, off);
+	byteout(ale, off);
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&sedlbauer_lock, flags);
-	return ret;
+	return (ret);
 }
 
 static inline void
-readfifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&sedlbauer_lock, flags);
-	byteout(cs->hw.sedl.adr, off);
+	byteout(ale, off);
 	insb(adr, data, size);
-	spin_unlock_irqrestore(&sedlbauer_lock, flags);
 }
 
 
 static inline void
-writereg(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 data)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	byteout(cs->hw.sedl.adr, off);
+	byteout(ale, off);
 	byteout(adr, data);
 }
 
 static inline void
-writefifo(struct IsdnCardState *cs, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	byteout(cs->hw.sedl.adr, off);
+	byteout(ale, off);
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.sedl.isac, offset);
+	return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.sedl.isac, offset, value);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.sedl.isac, 0, data, size);
+	readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.sedl.isac, 0, data, size);
+	writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs, cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0));
+	return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writereg(cs, cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	readfifo(cs, cs->hw.sedl.hscx, hscx ? 0x40 : 0, data, size);
+	readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-	writefifo(cs, cs->hw.sedl.hscx, hscx ? 0x40 : 0, data, size);
+	writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs, cs->hw.sedl.isac, offset);
+	return (readreg(cs->hw.sedl.adr,
+			cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-static inline void
-ipac_write(struct IsdnCardState *cs, u8 offset, u8 value)
-{
-	writereg(cs, cs->hw.sedl.isac, offset, value);
-}
-
-static inline void
-ipac_readfifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
-{
-	readfifo(cs, cs->hw.sedl.isac, offset, data, size);
-}
-
-static inline void
-ipac_writefifo(struct IsdnCardState *cs, u8 offset, u8 *data, int size)
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-	writefifo(cs, cs->hw.sedl.isac, offset, data, size);
+	writereg(cs->hw.sedl.adr,
+		 cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-/* This will generate ipac_dc_ops and ipac_bc_ops using the functions
- * above */
-
-BUILD_IPAC_OPS(ipac);
-
-
 /* ISAR access routines
  * mode = 0 access with IRQ on
  * mode = 1 access with IRQ off
  * mode = 2 access with IRQ off and using last offset
  */
 
-static u8
-isar_read(struct IsdnCardState *cs, int mode, u8 offset)
+static u_char
+ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
 {	
 	if (mode == 0)
-		return readreg(cs, cs->hw.sedl.hscx, offset);
-
-	if (mode == 1)
+		return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset));
+	else if (mode == 1)
 		byteout(cs->hw.sedl.adr, offset);
-
-	return bytein(cs->hw.sedl.hscx);
+	return(bytein(cs->hw.sedl.hscx));
 }
 
 static void
-isar_write(struct IsdnCardState *cs, int mode, u8 offset, u8 value)
+WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
 {
 	if (mode == 0)
-		return writereg(cs, cs->hw.sedl.hscx, offset, value);
+		writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value);
+	else {
+		if (mode == 1)
+			byteout(cs->hw.sedl.adr, offset);
+		byteout(cs->hw.sedl.hscx, value);
+	}
+}
 
-	if (mode == 1)
-		byteout(cs->hw.sedl.adr, offset);
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-	byteout(cs->hw.sedl.hscx, value);
-}
+#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
+		cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
+		cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
 
-static struct bc_hw_ops isar_ops = {
-	.read_reg   = isar_read,
-	.write_reg  = isar_write,
-};
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
+		cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
+		cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
 
 static irqreturn_t
 sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
 
+	spin_lock_irqsave(&cs->lock, flags);
 	if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
 		/* The card tends to generate interrupts while being removed
 		   causing us to just crash the kernel. bad. */
+		spin_unlock_irqrestore(&cs->lock, flags);
 		printk(KERN_WARNING "Sedlbauer: card not available!\n");
 		return IRQ_NONE;
 	}
-	return hscxisac_irq(intno, dev_id, regs);
+
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char ista, val, icnt = 5;
+	u_long flags;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
+Start_IPAC:
+	if (cs->debug & L1_DEB_IPAC)
+		debugl1(cs, "IPAC ISTA %02X", ista);
+	if (ista & 0x0f) {
+		val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+		if (ista & 0x01)
+			val |= 0x01;
+		if (ista & 0x04)
+			val |= 0x02;
+		if (ista & 0x08)
+			val |= 0x04;
+		if (val)
+			hscx_int_main(cs, val);
+	}
+	if (ista & 0x20) {
+		val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80);
+		if (val) {
+			isac_interrupt(cs, val);
+		}
+	}
+	if (ista & 0x10) {
+		val = 0x01;
+		isac_interrupt(cs, val);
+	}
+	ista  = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
+	if ((ista & 0x3f) && icnt) {
+		icnt--;
+		goto Start_IPAC;
+	}
+	if (!icnt)
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Sedlbauer IRQ LOOP");
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
 }
 
 static irqreturn_t
-sedlbauer_isar_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_char val;
 	int cnt = 5;
+	u_long flags;
 
-	spin_lock(&cs->lock);
-	val = isar_read(cs, 0, ISAR_IRQBIT);
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
       Start_ISAR:
 	if (val & ISAR_IRQSTA)
 		isar_int_main(cs);
-	val = isac_read(cs, ISAC_ISTA);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
       Start_ISAC:
 	if (val)
 		isac_interrupt(cs, val);
-	val = isar_read(cs, 0, ISAR_IRQBIT);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
 	if ((val & ISAR_IRQSTA) && --cnt) {
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "ISAR IntStat after IntRoutine");
 		goto Start_ISAR;
 	}
-	val = isac_read(cs, ISAC_ISTA);
+	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
 	if (val && --cnt) {
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ISAC IntStat after IntRoutine");
@@ -329,362 +386,131 @@
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "Sedlbauer IRQ LOOP");
 
-	isar_write(cs, 0, ISAR_IRQBIT, 0);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0x0);
-	isar_write(cs, 0, ISAR_IRQBIT, ISAR_IRQMSK);
-	spin_unlock(&cs->lock);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static int
-sedlbauer_ipac_reset(struct IsdnCardState *cs)
+void
+release_io_sedlbauer(struct IsdnCardState *cs)
 {
-	writereg(cs, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	writereg(cs, cs->hw.sedl.isac, IPAC_CONF, 0x0);
-	writereg(cs, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
-	writereg(cs, cs->hw.sedl.isac, IPAC_AOE, 0x0);
-	writereg(cs, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
-	writereg(cs, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
-	return 0;
-}
+	int bytecnt = 8;
 
-static int
-sedlbauer_isar_pci_reset(struct IsdnCardState *cs)
-{
-	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout((20*HZ)/1000);
-	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout((20*HZ)/1000);
-	return 0;
-}
-
-static int
-sedlbauer_reset(struct IsdnCardState *cs)
-{
-	printk(KERN_INFO "Sedlbauer: resetting card\n");
-	if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA &&
-	   cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX)
-		return 0;
-
-	if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
-		return sedlbauer_ipac_reset(cs);
-	} else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
-		   (cs->hw.sedl.bus == SEDL_BUS_PCI)) {
-		return sedlbauer_isar_pci_reset(cs);
-	} else {		
-		byteout(cs->hw.sedl.reset_on, SEDL_RESET);	/* Reset On */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((10*HZ)/1000);
-		byteout(cs->hw.sedl.reset_off, 0);	/* Reset Off */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((10*HZ)/1000);
+	if (cs->subtyp == SEDL_SPEED_FAX) {
+		bytecnt = 16;
+	} else if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+		bytecnt = 256;
 	}
-	return 0;
+	if (cs->hw.sedl.cfg_reg)
+		release_region(cs->hw.sedl.cfg_reg, bytecnt);
 }
 
 static void
-sedlbauer_isar_release(struct IsdnCardState *cs)
+reset_sedlbauer(struct IsdnCardState *cs)
 {
-	isar_write(cs, 0, ISAR_IRQBIT, 0);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	sedlbauer_reset(cs);
-	isar_write(cs, 0, ISAR_IRQBIT, 0);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	hisax_release_resources(cs);
-}
-
-static void
-sedlbauer_led_handler(struct IsdnCardState *cs)
-{
-	if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
-		return;
-
-	if (cs->status & 0x2000)
-		cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
-	else
-		cs->hw.sedl.reset_off |=  SEDL_ISAR_PCI_LED2;
-
-	if (cs->status & 0x1000)
-		cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
-	else
-		cs->hw.sedl.reset_off |=  SEDL_ISAR_PCI_LED1;
-
-	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-}
-
-static void
-sedlbauer_isar_init(struct IsdnCardState *cs)
-{
-	isar_write(cs, 0, ISAR_IRQBIT, 0);
-	initisac(cs);
-	initisar(cs);
-}
-
-static struct card_ops sedlbauer_ops = {
-	.init        = inithscxisac,
-	.reset       = sedlbauer_reset,
-	.release     = hisax_release_resources,
-	.led_handler = sedlbauer_led_handler,
-	.irq_func    = sedlbauer_interrupt,
-};
-
-static struct card_ops sedlbauer_ipac_ops = {
-	.init        = ipac_init,
-	.reset       = sedlbauer_reset,
-	.release     = hisax_release_resources,
-	.led_handler = sedlbauer_led_handler,
-	.irq_func    = ipac_irq,
-};
-
-static struct card_ops sedlbauer_isar_ops = {
-	.init        = sedlbauer_isar_init,
-	.reset       = sedlbauer_reset,
-	.release     = sedlbauer_isar_release,
-	.led_handler = sedlbauer_led_handler,
-	.irq_func    = sedlbauer_isar_interrupt,
-};
-
-static int __init
-sedl_ipac_probe(struct IsdnCardState *cs)
-{
-	u8 val;
-
-	cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
-	val = readreg(cs, cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
-	printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val);
-	return (val == 1 || val == 2);
-}
-
-static int __init
-sedl_ipac_init(struct IsdnCardState *cs)
-{
-	cs->card_ops = &sedlbauer_ipac_ops;
-	if (ipac_setup(cs, &ipac_dc_ops, &ipac_bc_ops))
-		return -ENODEV;
-	sedlbauer_reset(cs);
-	return 0;
-}
-
-static int __init
-sedl_isac_isar_init(struct IsdnCardState *cs)
-{
-	cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
-	cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
-	__set_bit(HW_ISAR, &cs->HW_Flags);
-	cs->card_ops = &sedlbauer_isar_ops;
-	cs->auxcmd = &isar_auxcmd;
-	isac_setup(cs, &isac_ops);
-	return isar_setup(cs, &isar_ops);
-}
+	printk(KERN_INFO "Sedlbauer: resetting card\n");
 
-static int __init
-sedl_isac_hscx_init(struct IsdnCardState *cs)
-{
-	cs->card_ops = &sedlbauer_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		return -ENODEV;
-	sedlbauer_reset(cs);
-	return 0;
+	if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
+	   (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
+		if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
+			mdelay(2);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
+			mdelay(10);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
+			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
+		} else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
+			(cs->hw.sedl.bus == SEDL_BUS_PCI)) {
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+			mdelay(2);
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			mdelay(10);
+		} else {		
+			byteout(cs->hw.sedl.reset_on, SEDL_RESET);	/* Reset On */
+			mdelay(2);
+			byteout(cs->hw.sedl.reset_off, 0);	/* Reset Off */
+			mdelay(10);
+		}
+	}
 }
 
-static int __init
-sedl_card_win_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static int
+Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	cs->irq = card->para[0];
-	cs->hw.sedl.cfg_reg = card->para[1];
-	cs->hw.sedl.bus = SEDL_BUS_ISA;
-	if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 8, "sedlbauer isdn"))
-		goto err;
+	u_long flags;
 
-	if (sedl_ipac_probe(cs)) {
-		cs->subtyp = SEDL_SPEED_WIN2_PC104;
-		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-		cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
-		cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
-		if (sedl_ipac_init(cs))
-			goto err;
-	} else {
-		cs->subtyp = SEDL_SPEED_CARD_WIN;
-		cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
-		cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
-		cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
-		cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
-		cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
-		cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
-		if (sedl_isac_hscx_init(cs))
-			goto err;
-	}
-	printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n",
-	       Sedlbauer_Types[cs->subtyp],
-	       cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 8, cs->irq);
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-sedl_star_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
-	if (sedl_ipac_probe(cs)) {
-		cs->subtyp = SEDL_SPEED_STAR2;
-		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-		cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
-		cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
-		if (sedl_ipac_init(cs))
-			goto err;
-	} else {
-		cs->subtyp = SEDL_SPEED_STAR;
-		cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
-		cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
-		cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
-		cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
-		cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
-		cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
-		if (sedl_isac_hscx_init(cs))
-			goto err;
-	}
-	printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n",
-	       Sedlbauer_Types[cs->subtyp],
-	       cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 8, cs->irq);
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-sedl_fax_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->subtyp = SEDL_SPEED_FAX;
-	cs->hw.sedl.bus = SEDL_BUS_ISA;
-	cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-	if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 16, "sedlbauer isdn"))
-		goto err;
-
-	printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n",
-	       Sedlbauer_Types[cs->subtyp],
-	       cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 16, cs->irq);
-
-	cs->hw.sedl.adr = cs->hw.sedl.cfg_reg  + SEDL_ISAR_ISA_ADR;
-	cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC;
-	cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR;
-	cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON;
-	cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF;
-	if (sedl_isac_isar_init(cs))
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-sedl_pci_init(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.sedl.cfg_reg = pci_resource_start(pdev, 0);
-	cs->hw.sedl.bus = SEDL_BUS_PCI;
-
-	if (!request_io(&cs->rs, cs->hw.sedl.cfg_reg, 256, "sedlbauer isdn"))
-		return -EBUSY;
-
-	printk(KERN_INFO "Sedlbauer %s: defined at 0x%x-0x%x IRQ %d\n",
-	       Sedlbauer_Types[cs->subtyp],
-	       cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + 256, cs->irq);
-
-	cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
-	cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
-	byteout(cs->hw.sedl.cfg_reg, 0xff);
-	byteout(cs->hw.sedl.cfg_reg, 0x00);
-	byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
-	byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
-	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout((10*HZ)/1000);
-	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-	return 0;
-}
-
-static int __init
-sedl_fax_pyramid_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
-	cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-	if (sedl_pci_init(cs, pdev))
-		goto err;
-
-	cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ADR;
-	cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAC;
-	cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAR;
-	if (sedl_isac_isar_init(cs))
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-sedl_fax_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = SEDL_SPEEDFAX_PCI;
-	cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-
-	if (sedl_pci_init(cs, pdev))
-		goto err;
-
-	cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ADR;
-	cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAC;
-	cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_PCI_ISAR;
-	if (sedl_isac_isar_init(cs))
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-sedl_pci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
-{
-	if (pci_enable_device(pdev))
-		goto err;
-
-	cs->subtyp = SEDL_SPEED_PCI;
-	cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-	if (sedl_pci_init(cs, pdev))
-		goto err;
-
-	cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
-	cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
-	if (sedl_ipac_init(cs))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_sedlbauer(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+				spin_lock_irqsave(&cs->lock, flags);
+				writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+					ISAR_IRQBIT, 0);
+				writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
+					ISAC_MASK, 0xFF);
+				reset_sedlbauer(cs);
+				writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+					ISAR_IRQBIT, 0);
+				writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
+					ISAC_MASK, 0xFF);
+				spin_unlock_irqrestore(&cs->lock, flags);
+			}
+			release_io_sedlbauer(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_sedlbauer(cs);
+			if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+				clear_pending_isac_ints(cs);
+				writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+					ISAR_IRQBIT, 0);
+				initisac(cs);
+				initisar(cs);
+				/* Reenable all IRQ */
+				cs->writeisac(cs, ISAC_MASK, 0);
+				/* RESET Receiver and Transmitter */
+				cs->writeisac(cs, ISAC_CMDR, 0x41);
+			} else {
+				inithscxisac(cs, 3);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+		case MDL_INFO_CONN:
+			if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
+				return(0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if ((long) arg)
+				cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
+			else
+				cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			break;
+		case MDL_INFO_REL:
+			if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
+				return(0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if ((long) arg)
+				cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
+			else
+				cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			break;
+	}
+	return(0);
 }
 
 static struct pci_dev *dev_sedl __devinitdata = NULL;
@@ -700,124 +526,308 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *pdev = &sedl_ids[0];
+static struct isapnp_device_id *ipid __initdata = &sedl_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
+	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 	u16 sub_vendor_id, sub_id;
 
 	strcpy(tmp, Sedlbauer_revision);
-	printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n",
-	       HiSax_getrev(tmp));
+	printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
 	
+ 	if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
+ 		cs->subtyp = SEDL_SPEED_CARD_WIN;
+		cs->hw.sedl.bus = SEDL_BUS_ISA;
+		cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ 	} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {	
+ 		cs->subtyp = SEDL_SPEED_STAR;
+		cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
+		cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ 	} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {	
+ 		cs->subtyp = SEDL_SPEED_FAX;
+		cs->hw.sedl.bus = SEDL_BUS_ISA;
+		cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ 	} else
+		return (0);
+
+	bytecnt = 8;
 	if (card->para[1]) {
-		if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
-			if (sedl_card_win_probe(card->cs, card) < 0)
-				return 0;
-			return 1;
-		} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {	
-			if (sedl_star_probe(card->cs, card) < 0)
-				return 0;
-			return 1;
-		} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {	
-			if (sedl_fax_probe(card->cs, card) < 0)
-				return 0;
-			return 1;
+		cs->hw.sedl.cfg_reg = card->para[1];
+		cs->irq = card->para[0];
+		if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+			bytecnt = 16;
 		}
-	}
+	} else {
 #ifdef __ISAPNP__
-	if (isapnp_present()) {
-		struct pnp_card *pb;
-		struct pnp_dev *pd;
-		
-		while(pdev->card_vendor) {
-			if ((pb = pnp_find_card(pdev->card_vendor,
-						pdev->card_device,
-						pnp_c))) {
-				pnp_c = pb;
-				pd = NULL;
-				if ((pd = pnp_find_dev(pnp_c,
-						       pdev->vendor,
-						       pdev->function,
-						       pd))) {
-					printk(KERN_INFO "HiSax: %s detected\n",
-					       (char *)pdev->driver_data);
-					if (pnp_device_attach(pd) < 0) {
-						printk(KERN_ERR "Sedlbauer PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pd) < 0) {
-						printk(KERN_ERR "Sedlbauer PnP: activate failed\n");
-						pnp_device_detach(pd);
-						return 0;
-					}
-					if (!pnp_irq_valid(pd, 0) || !pnp_port_valid(pd, 0)) {
-						printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
-						       pnp_irq(pd, 0), pnp_port_start(pd, 0));
-						pnp_device_detach(pd);
-						return 0;
-					}
-					card->para[1] = pnp_port_start(pd, 0);
-					card->para[0] = pnp_irq(pd, 0);
-					cs->hw.sedl.cfg_reg = card->para[1];
-					cs->irq = card->para[0];
-					if (pdev->function == ISAPNP_FUNCTION(0x2)) {
-						if (sedl_fax_probe(card->cs, card))
-							return 0;
-						return 1;
+		if (isapnp_present()) {
+			struct pnp_dev *pnp_d;
+			while(ipid->card_vendor) {
+				if ((pnp_c = pnp_find_card(ipid->card_vendor,
+					ipid->card_device, pnp_c))) {
+					pnp_d = NULL;
+					if ((pnp_d = pnp_find_dev(pnp_c,
+						ipid->vendor, ipid->function, pnp_d))) {
+						int err;
+
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)ipid->driver_data);
+						pnp_disable_dev(pnp_d);
+						err = pnp_activate_dev(pnp_d);
+						if (err<0) {
+							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+								__FUNCTION__, err);
+							return(0);
+						}
+						card->para[1] = pnp_port_start(pnp_d, 0);
+						card->para[0] = pnp_irq(pnp_d, 0);
+
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pnp_disable_dev(pnp_d);
+							return(0);
+						}
+						cs->hw.sedl.cfg_reg = card->para[1];
+						cs->irq = card->para[0];
+						if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+							cs->subtyp = SEDL_SPEED_FAX;
+							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+							bytecnt = 16;
+						} else {
+							cs->subtyp = SEDL_SPEED_CARD_WIN;
+							cs->hw.sedl.chip = SEDL_CHIP_TEST;
+						}
+						goto ready;
 					} else {
-						if (sedl_card_win_probe(card->cs, card))
-							return 0;
-						return 1;
+						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+						return(0);
 					}
-				} else {
-					printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
-					return 0;
 				}
+				ipid++;
+				pnp_c = NULL;
+			} 
+			if (!ipid->card_vendor) {
+				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
 			}
-			pdev++;
-			pnp_c=NULL;
-		} 
-		if (!pdev->card_vendor) {
-			printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
 		}
-	}
 #endif
 /* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
-	dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				   PCI_DEVICE_ID_TIGERJET_100, dev_sedl);
-	if (dev_sedl) {
+#if CONFIG_PCI
+		if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+				PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+			if (pci_enable_device(dev_sedl))
+				return(0);
+			cs->irq = dev_sedl->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+		} else {
+			printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+			return(0);
+		}
+		cs->irq_flags |= SA_SHIRQ;
+		cs->hw.sedl.bus = SEDL_BUS_PCI;
 		sub_vendor_id = dev_sedl->subsystem_vendor;
 		sub_id = dev_sedl->subsystem_device;
 		printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
-		       sub_vendor_id, sub_id);
+			sub_vendor_id, sub_id);
+		printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+			cs->hw.sedl.cfg_reg);
 		if (sub_id != PCI_SUB_ID_SEDLBAUER) {
 			printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
-			return 0;
+			return(0);
 		}
 		if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
-			if (sedl_fax_pyramid_probe(cs, dev_sedl))
-				return 0;
-			return 1;
+			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+			cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
 		} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
-			if (sedl_fax_pci_probe(cs, dev_sedl))
-				return 0;
-			return 1;
+			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+			cs->subtyp = SEDL_SPEEDFAX_PCI;
+		} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+			cs->subtyp = HST_SAPHIR3;
 		} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
-			if (sedl_pci_probe(cs, dev_sedl))
-				return 0;
-			return 1;
+			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+			cs->subtyp = SEDL_SPEED_PCI;
+		} else {
+			printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+				sub_vendor_id);
+			return(0);
 		}
-		printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
-		       sub_vendor_id);
-		return 0;
-	}
+		bytecnt = 256;
+		cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+		cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+		byteout(cs->hw.sedl.cfg_reg, 0xff);
+		byteout(cs->hw.sedl.cfg_reg, 0x00);
+		byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+		byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
+		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+		mdelay(2);
+		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+		mdelay(10);
+#else
+		printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
+		return (0);
 #endif /* CONFIG_PCI */
-	return 0;
+	}	
+ready:	
+	/* In case of the sedlbauer pcmcia card, this region is in use,
+	 * reserved for us by the card manager. So we do not check it
+	 * here, it would fail.
+	 */
+	if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA &&
+		!request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) {
+		printk(KERN_WARNING
+			"HiSax: %s config port %x-%x already in use\n",
+			CardType[card->typ],
+			cs->hw.sedl.cfg_reg,
+			cs->hw.sedl.cfg_reg + bytecnt);
+			return (0);
+	}
+
+	printk(KERN_INFO
+	       "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n",
+	       cs->hw.sedl.cfg_reg,
+	       cs->hw.sedl.cfg_reg + bytecnt,
+	       cs->irq);
+
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Sedl_card_msg;
+
+/*
+ * testing ISA and PCMCIA Cards for IPAC, default is ISAC
+ * do not test for PCI card, because ports are different
+ * and PCI card uses only IPAC (for the moment)
+ */	
+	if (cs->hw.sedl.bus != SEDL_BUS_PCI) {
+		val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR,
+			cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
+		printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val);
+	        if ((val == 1) || (val == 2)) {
+			/* IPAC */
+			cs->subtyp = SEDL_SPEED_WIN2_PC104;
+			if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
+				cs->subtyp = SEDL_SPEED_STAR2;
+			}
+			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+		} else {
+			/* ISAC_HSCX oder ISAC_ISAR */
+			if (cs->hw.sedl.chip == SEDL_CHIP_TEST) {
+				cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
+			}
+		}
+	}
+
+/*
+ * hw.sedl.chip is now properly set
+ */
+	printk(KERN_INFO "Sedlbauer: %s detected\n",
+		Sedlbauer_Types[cs->subtyp]);
+
+	setup_isac(cs);
+	if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
+		if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+	                cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
+			cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
+			cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
+		} else {
+	                cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
+			cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
+			cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
+		}
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+		cs->readisac = &ReadISAC_IPAC;
+		cs->writeisac = &WriteISAC_IPAC;
+		cs->readisacfifo = &ReadISACfifo_IPAC;
+		cs->writeisacfifo = &WriteISACfifo_IPAC;
+		cs->irq_func = &sedlbauer_interrupt_ipac;
+		val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
+		printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
+	} else {
+		/* ISAC_HSCX oder ISAC_ISAR */
+		cs->readisac = &ReadISAC;
+		cs->writeisac = &WriteISAC;
+		cs->readisacfifo = &ReadISACfifo;
+		cs->writeisacfifo = &WriteISACfifo;
+		if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+			if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ISAR;
+			} else {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR;
+				cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR_RESET_ON;
+				cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR_RESET_OFF;
+			}
+			cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
+			cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
+			test_and_set_bit(HW_ISAR, &cs->HW_Flags);
+			cs->irq_func = &sedlbauer_interrupt_isar;
+			cs->auxcmd = &isar_auxcmd;
+			ISACVersion(cs, "Sedlbauer:");
+			cs->BC_Read_Reg = &ReadISAR;
+			cs->BC_Write_Reg = &WriteISAR;
+			cs->BC_Send_Data = &isar_fill_fifo;
+			bytecnt = 3;
+			while (bytecnt) {
+				ver = ISARVersion(cs, "Sedlbauer:");
+				if (ver < 0)
+					printk(KERN_WARNING
+						"Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
+				else
+					break;
+				reset_sedlbauer(cs);
+				bytecnt--;
+			}
+			if (!bytecnt) {
+				release_io_sedlbauer(cs);
+				return (0);
+			}
+		} else {
+			if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
+				cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
+				cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
+				cs->irq_flags |= SA_SHIRQ;
+			} else {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
+				cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
+				cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
+			}
+			cs->irq_func = &sedlbauer_interrupt;
+			ISACVersion(cs, "Sedlbauer:");
+		
+			if (HscxVersion(cs, "Sedlbauer:")) {
+				printk(KERN_WARNING
+					"Sedlbauer: wrong HSCX versions check IO address\n");
+				release_io_sedlbauer(cs);
+				return (0);
+			}
+		}
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/sedlbauer_cs.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/isdn/hisax/sedlbauer_cs.c	2004-02-18 09:03:59.000000000 +0000
@@ -53,6 +53,7 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
+#include "hisax_cfg.h"
 
 MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
 MODULE_AUTHOR("Marcus Niemann");
@@ -93,8 +94,6 @@
 static int protocol = 2;        /* EURO-ISDN Default */
 MODULE_PARM(protocol, "i");
 
-extern int sedl_init_pcmcia(int, int, int*, int);
-
 /*====================================================================*/
 
 /*
@@ -176,6 +175,7 @@
     dev_link_t		link;
     dev_node_t		node;
     int			stop;
+    int			cardnr;
 } local_info_t;
 
 /*======================================================================
@@ -203,6 +203,7 @@
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
     if (!local) return NULL;
     memset(local, 0, sizeof(local_info_t));
+    local->cardnr = -1;
     link = &local->link; link->priv = local;
     
     /* Interrupt setup */
@@ -324,7 +325,7 @@
     config_info_t conf;
     win_req_t req;
     memreq_t map;
-    
+    IsdnCard_t  icard;
 
     DEBUG(0, "sedlbauer_config(0x%p)\n", link);
 
@@ -509,10 +510,19 @@
     printk("\n");
     
     link->state &= ~DEV_CONFIG_PENDING;
- 
-    sedl_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ,
-                     &(((local_info_t*)link->priv)->stop),
-                     protocol);
+
+    icard.para[0] = link->irq.AssignedIRQ;
+    icard.para[1] = link->io.BasePort1;
+    icard.protocol = protocol;
+    icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+    
+    last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
+    if (last_ret < 0) {
+    	printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
+    		last_ret, link->io.BasePort1);
+    	sedlbauer_release(link);
+    } else
+    	((local_info_t*)link->priv)->cardnr = last_ret;
 
     return;
 
@@ -532,8 +542,15 @@
 
 static void sedlbauer_release(dev_link_t *link)
 {
+    local_info_t *local = link->priv;
     DEBUG(0, "sedlbauer_release(0x%p)\n", link);
 
+    if (local) {
+    	if (local->cardnr >= 0) {
+    	    /* no unregister function with hisax */
+	    HiSax_closecard(local->cardnr);
+	}
+    }
     /* Unlink the device chain */
     link->dev = NULL;
 
--- diff/drivers/isdn/hisax/sportster.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/sportster.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: sportster.c,v 1.14.6.2 2001/09/23 22:24:51 kai Exp $
+/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for USR Sportster internal TA
  *
@@ -19,7 +19,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.14.6.2 $";
+const char *sportster_revision = "$Revision: 1.16.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -38,91 +38,102 @@
 }
 
 static inline void
-read_fifo(unsigned int adr, u8 * data, int size)
+read_fifo(unsigned int adr, u_char * data, int size)
 {
 	insb(adr, data, size);
 }
 
 static void
-write_fifo(unsigned int adr, u8 * data, int size)
+write_fifo(unsigned int adr, u_char * data, int size)
 {
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return bytein(calc_off(cs->hw.spt.isac, offset));
+	return (bytein(calc_off(cs->hw.spt.isac, offset)));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	byteout(calc_off(cs->hw.spt.isac, offset), value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	read_fifo(cs->hw.spt.isac, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	write_fifo(cs->hw.spt.isac, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return bytein(calc_off(cs->hw.spt.hscx[hscx], offset));
+	return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
 	byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	read_fifo(cs->hw.spt.hscx[hscx], data, size);
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	write_fifo(cs->hw.spt.hscx[hscx], data, size);
-}
+#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
+#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+#include "hscx_irq.c"
 
 static irqreturn_t
 sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
 
-	hscxisac_irq(intno, dev_id, regs);
+	spin_lock_irqsave(&cs->lock, flags);
+	val = READHSCX(cs, 1, HSCX_ISTA);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = ReadISAC(cs, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	val = READHSCX(cs, 1, HSCX_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = ReadISAC(cs, ISAC_ISTA);
+	if (val) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	/* get a new irq impulse if there any pending */
 	bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static void
-sportster_release(struct IsdnCardState *cs)
+void
+release_io_sportster(struct IsdnCardState *cs)
 {
 	int i, adr;
 
@@ -133,45 +144,50 @@
 	}
 }
 
-static int
-sportster_reset(struct IsdnCardState *cs)
+void
+reset_sportster(struct IsdnCardState *cs)
 {
 	cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
 	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
+	mdelay(10);
 	cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
 	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	return 0;
+	mdelay(10);
 }
 
 static int
 Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	return(0);
-}
+	u_long flags;
 
-static void
-sportster_init(struct IsdnCardState *cs)
-{
-	inithscxisac(cs);
-	cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
-	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_sportster(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_sportster(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_sportster(cs);
+			inithscxisac(cs, 1);
+			cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
+			byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+			inithscxisac(cs, 2);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
-static struct card_ops sportster_ops = {
-	.init     = sportster_init,
-	.reset    = sportster_reset,
-	.release  = sportster_release,
-	.irq_func = sportster_interrupt,
-};
-
 static int __init
 get_io_range(struct IsdnCardState *cs)
 {
-	int i, adr;
+	int i, j, adr;
 	
 	for (i=0;i<64;i++) {
 		adr = cs->hw.spt.cfg_reg + i *1024;
@@ -179,65 +195,76 @@
 			printk(KERN_WARNING
 				"HiSax: %s config port %x-%x already in use\n",
 				CardType[cs->typ], adr, adr + 8);
-			goto err;
-		}
+			break;
+		} 
 	}
-	return 1;
- err:
-	for (i=i-1; i >= 0; i--) {
-		adr = cs->hw.spt.cfg_reg + i *1024;
-		release_region(adr, 8);
+	if (i==64)
+		return(1);
+	else {
+		for (j=0; j<i; j++) {
+			adr = cs->hw.spt.cfg_reg + j *1024;
+			release_region(adr, 8);
+		}
+		return(0);
 	}
-	return 0;
 }
 
-static int __init
-sportster_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+int __init
+setup_sportster(struct IsdnCard *card)
 {
-	cs->irq = card->para[0];
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, sportster_revision);
+	printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_SPORTSTER)
+		return (0);
+
 	cs->hw.spt.cfg_reg = card->para[1];
+	cs->irq = card->para[0];
 	if (!get_io_range(cs))
-		return -EBUSY;
+		return (0);
 	cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
 	cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
 	cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
 	
 	switch(cs->irq) {
-	case 5:	cs->hw.spt.res_irq = 1;	break;
-	case 7:	cs->hw.spt.res_irq = 2;	break;
-	case 10:cs->hw.spt.res_irq = 3;	break;
-	case 11:cs->hw.spt.res_irq = 4;	break;
-	case 12:cs->hw.spt.res_irq = 5;	break;
-	case 14:cs->hw.spt.res_irq = 6;	break;
-	case 15:cs->hw.spt.res_irq = 7;	break;
-	default:
-		printk(KERN_WARNING "Sportster: wrong IRQ\n");
-		goto err;
+		case 5:	cs->hw.spt.res_irq = 1;
+			break;
+		case 7:	cs->hw.spt.res_irq = 2;
+			break;
+		case 10:cs->hw.spt.res_irq = 3;
+			break;
+		case 11:cs->hw.spt.res_irq = 4;
+			break;
+		case 12:cs->hw.spt.res_irq = 5;
+			break;
+		case 14:cs->hw.spt.res_irq = 6;
+			break;
+		case 15:cs->hw.spt.res_irq = 7;
+			break;
+		default:release_io_sportster(cs);
+			printk(KERN_WARNING "Sportster: wrong IRQ\n");
+			return(0);
 	}
-	sportster_reset(cs);
 	printk(KERN_INFO "HiSax: %s config irq:%d cfg:0x%X\n",
-	       CardType[cs->typ], cs->irq, cs->hw.spt.cfg_reg);
-
+		CardType[cs->typ], cs->irq, cs->hw.spt.cfg_reg);
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
 	cs->cardmsg = &Sportster_card_msg;
-	cs->card_ops = &sportster_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	sportster_release(cs);
-	return -EBUSY;
-}
-
-int __init
-setup_sportster(struct IsdnCard *card)
-{
-	char tmp[64];
-
-	strcpy(tmp, sportster_revision);
-	printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-
-	if (sportster_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	cs->irq_func = &sportster_interrupt;
+	ISACVersion(cs, "Sportster:");
+	if (HscxVersion(cs, "Sportster:")) {
+		printk(KERN_WARNING
+		       "Sportster: wrong HSCX versions check IO address\n");
+		release_io_sportster(cs);
+		return (0);
+	}
+	return (1);
 }
--- diff/drivers/isdn/hisax/st5481.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/st5481.h	2004-02-18 09:03:59.000000000 +0000
@@ -219,15 +219,15 @@
 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
 
 #define ERR(format, arg...) \
-printk(KERN_ERR __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+printk(KERN_ERR "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
 #define WARN(format, arg...) \
-printk(KERN_WARNING __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
 #define INFO(format, arg...) \
-printk(KERN_INFO __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+printk(KERN_INFO "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
-#include "st5481_hdlc.h"
+#include "isdnhdlc.h"
 #include "fsm.h"
 #include "hisax_if.h"
 #include <linux/skbuff.h>
@@ -236,9 +236,9 @@
  * FIFO handling
  */
 
-/* Generic FIFO structure */ 
+/* Generic FIFO structure */
 struct fifo {
-	u8 r,w,count,size;
+	u_char r,w,count,size;
 	spinlock_t lock;
 };
 
@@ -270,7 +270,7 @@
 		index = -1;
 	} else {
 		// Return index where to get the next data to add to the FIFO
-		index = fifo->w++ & (fifo->size-1); 
+		index = fifo->w++ & (fifo->size-1);
 		fifo->count++;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -289,13 +289,13 @@
 		return -1;
 	}
 
-	spin_lock_irqsave(&fifo->lock, flags);		
+	spin_lock_irqsave(&fifo->lock, flags);
 	if (!fifo->count) {
 		// FIFO empty
 		index = -1;
 	} else {
 		// Return index where to get the next data from the FIFO
-		index = fifo->r++ & (fifo->size-1); 
+		index = fifo->r++ & (fifo->size-1);
 		fifo->count--;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -336,7 +336,7 @@
 };
 
 struct st5481_d_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	unsigned long busy;
 	struct sk_buff *tx_skb;
@@ -344,15 +344,15 @@
 };
 
 struct st5481_b_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
-	u8 flow_event;
+	u_char flow_event;
 	u_long busy;
 	struct sk_buff *tx_skb;
 };
 
 struct st5481_in {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	int mode;
 	int bufsize;
@@ -452,7 +452,7 @@
 
 int  st5481_isoc_flatten(struct urb *urb);
 void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
-		    u8 pipe, ctrl_complete_t complete, void *context);
+		    u_char pipe, ctrl_complete_t complete, void *context);
 void st5481_usb_ctrl_msg(struct st5481_adapter *adapter,
 		  u8 request, u8 requesttype, u16 value, u16 index,
 		  ctrl_complete_t complete, void *context);
@@ -482,7 +482,7 @@
 {
 	int i,j;
 	int len,ofs;
-	u8 *data;
+	u_char *data;
 
 	printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
 	       name,urb->number_of_packets,urb->error_count);
--- diff/drivers/isdn/hisax/st5481_b.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/st5481_b.c	2004-02-18 09:03:59.000000000 +0000
@@ -31,9 +31,9 @@
 	struct st5481_b_out *b_out = &bcs->b_out;
 	struct st5481_adapter *adapter = bcs->adapter;
 	struct urb *urb;
-	u_int packet_size, bytes_sent;
-	int len, offset, buf_size;
-	u_int i;
+	unsigned int packet_size,offset;
+	int len,buf_size,bytes_sent;
+	int i;
 	struct sk_buff *skb;
 	
 	if (test_and_set_bit(buf_nr, &b_out->busy)) {
@@ -67,22 +67,31 @@
 				bytes_sent = buf_size - len;
 				if (skb->len < bytes_sent)
 					bytes_sent = skb->len;
-
-				memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
-				
+				{	/* swap tx bytes to get hearable audio data */
+					register unsigned char *src  = skb->data;
+					register unsigned char *dest = urb->transfer_buffer+len;
+					register unsigned int count;
+					for (count = 0; count < bytes_sent; count++)
+						*dest++ = isdnhdlc_bit_rev_tab[*src++];
+				}
 				len += bytes_sent;
 			} else {
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   skb->data, skb->len, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       skb->data, skb->len, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 
 			skb_pull(skb, bytes_sent);
-			
+
 			if (!skb->len) {
 				// Frame sent
 				b_out->tx_skb = NULL;
-				B_L1L2(bcs, PH_DATA | CONFIRM, skb);
+				B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+				dev_kfree_skb_any(skb);
+
+/* 				if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
+/* 					st5481B_sched_event(bcs, B_XMTBUFREADY); */
+/* 				} */
 			}
 		} else {
 			if (bcs->mode == L1_MODE_TRANS) {
@@ -90,9 +99,9 @@
 				len = buf_size;
 			} else {
 				// Send flags
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   NULL, 0, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       NULL, 0, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 		}	
 	}
@@ -136,7 +145,7 @@
  */
 static void led_blink(struct st5481_adapter *adapter)
 {
-	u8 leds = adapter->leds;
+	u_char leds = adapter->leds;
 
 	// 50 frames/sec for each channel
 	if (++adapter->led_counter % 50) {
@@ -204,7 +213,7 @@
 	if (bcs->mode != L1_MODE_NULL) {
 		// Open the B channel
 		if (bcs->mode != L1_MODE_TRANS) {
-			hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
 		}
 		st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
 	
@@ -260,7 +269,7 @@
 	endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
 
 	DBG(4,"endpoint address=%02x,packet size=%d",
-	    endpoint->desc.bEndpointAddress,endpoint->desc.wMaxPacketSize);
+	    endpoint->desc.bEndpointAddress, endpoint->desc.wMaxPacketSize);
 
 	// Allocate memory for 8000bytes/sec + extra bytes if underrun
 	return st5481_setup_isocpipes(b_out->urb, dev, 
--- diff/drivers/isdn/hisax/st5481_d.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/hisax/st5481_d.c	2004-02-18 09:03:59.000000000 +0000
@@ -294,8 +294,8 @@
 {
 	struct st5481_d_out *d_out = &adapter->d_out;
 	struct urb *urb;
-	unsigned int num_packets;
-	int len, buf_size, bytes_sent, packet_offset;
+	unsigned int num_packets, packet_offset;
+	int len, buf_size, bytes_sent;
 	struct sk_buff *skb;
 	struct usb_iso_packet_descriptor *desc;
 
@@ -313,15 +313,15 @@
 	buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
 	
 	if (skb) {
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  skb->data, skb->len, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      skb->data, skb->len, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 		skb_pull(skb,bytes_sent);
 	} else {
 		// Send flags or idle
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  NULL, 0, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      NULL, 0, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 	}
 	
 	if (len < buf_size) {
@@ -341,7 +341,7 @@
 		desc = &urb->iso_frame_desc[num_packets];
 		desc->offset = packet_offset;
 		desc->length = SIZE_ISO_PACKETS_D_OUT;
-		if (len - packet_offset < (int)desc->length)
+		if (len - packet_offset < desc->length)
 			desc->length = len - packet_offset;
 		num_packets++;
 		packet_offset += desc->length;
@@ -413,7 +413,7 @@
 
 	DBG(2,"len=%d",skb->len);
 
-	hdlc_out_init(&d_out->hdlc_state, 1, 0);
+	isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
 
 	if (test_and_set_bit(buf_nr, &d_out->busy)) {
 		WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
@@ -422,9 +422,9 @@
 	urb = d_out->urb[buf_nr];
 
 	DBG_SKB(0x10, skb);
-	len = hdlc_encode(&d_out->hdlc_state, 
-			  skb->data, skb->len, &bytes_sent,
-			  urb->transfer_buffer, 16);
+	len = isdnhdlc_encode(&d_out->hdlc_state,
+			      skb->data, skb->len, &bytes_sent,
+			      urb->transfer_buffer, 16);
 	skb_pull(skb, bytes_sent);
 
 	if(len < 16)
@@ -664,7 +664,7 @@
 	endpoint = &altsetting->endpoint[EP_D_OUT-1];
 
 	DBG(2,"endpoint address=%02x,packet size=%d",
-	    endpoint->desc.bEndpointAddress,endpoint->desc.wMaxPacketSize);
+	    endpoint->desc.bEndpointAddress, endpoint->desc.wMaxPacketSize);
 
 	return st5481_setup_isocpipes(d_out->urb, dev, 
 				      usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
--- diff/drivers/isdn/hisax/st5481_init.c	2003-08-20 14:16:09.000000000 +0100
+++ source/drivers/isdn/hisax/st5481_init.c	2004-02-18 09:03:59.000000000 +0000
@@ -14,7 +14,6 @@
  * TODO:
  *
  * b layer1 delay?
- * hdlc as module
  * hotplug / unregister issues
  * mod_inc/dec_use_count
  * unify parts of d/b channel usb handling
@@ -59,8 +58,8 @@
  * This function will be called when the adapter is plugged
  * into the USB bus.
  */
-static int probe_st5481(struct usb_interface *intf,
-			const struct usb_device_id *id)
+static int __devinit probe_st5481(struct usb_interface *intf,
+				     const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct st5481_adapter *adapter;
@@ -140,7 +139,7 @@
 	usb_set_intfdata(intf, NULL);
 	if (!adapter)
 		return;
-
+	
 	list_del(&adapter->list);
 
 	st5481_stop(adapter);
@@ -196,7 +195,7 @@
 	st5481_debug = debug;
 #endif
 
-	printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver v0.1.0\n");
+	printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n");
 
 	retval = st5481_d_init();
 	if (retval < 0)
--- diff/drivers/isdn/hisax/st5481_usb.c	2003-08-26 10:00:52.000000000 +0100
+++ source/drivers/isdn/hisax/st5481_usb.c	2004-02-18 09:03:59.000000000 +0000
@@ -96,7 +96,7 @@
  * Asynchronous pipe reset (async version of usb_clear_halt).
  */
 void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
-		    u8 pipe,
+		    u_char pipe,
 		    ctrl_complete_t complete, void *context)
 {
 	DBG(1,"pipe=%02x",pipe);
@@ -500,8 +500,8 @@
 			status = len;
 			len = 0;
 		} else {
-			status = hdlc_decode(&in->hdlc_state, ptr, len, &count,
-					     in->rcvbuf, in->bufsize);
+			status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
+				in->rcvbuf, in->bufsize);
 			ptr += count;
 			len -= count;
 		}
@@ -633,8 +633,8 @@
 
 	if (in->mode != L1_MODE_NULL) {
 		if (in->mode != L1_MODE_TRANS)
-			hdlc_rcv_init(&in->hdlc_state,
-				      in->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_rcv_init(&in->hdlc_state,
+				in->mode == L1_MODE_HDLC_56K);
 		
 		st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
 		st5481_usb_device_ctrl_msg(in->adapter, in->counter,
--- diff/drivers/isdn/hisax/tei.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/hisax/tei.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 2.17.6.3 2001/09/23 22:24:51 kai Exp $
+/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
  *
  * Author       Karsten Keil
  *              based on the teles driver from Jan den Ouden
@@ -20,7 +20,7 @@
 #include <linux/init.h>
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.17.6.3 $";
+const char *tei_revision = "$Revision: 2.20.2.3 $";
 
 #define ID_REQUEST	1
 #define ID_ASSIGNED	2
@@ -34,7 +34,7 @@
 
 static struct Fsm teifsm;
 
-void tei_handler(struct PStack *st, u8 pr, struct sk_buff *skb);
+void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
 
 enum {
 	ST_TEI_NOP,
@@ -74,22 +74,6 @@
 	"EV_T202",
 };
 
-static inline void
-mdl_assign(struct IsdnCardState *cs)
-{
-	cs->status |= 0x0001;
-	if (cs->card_ops->led_handler)
-		cs->card_ops->led_handler(cs);
-}
-
-static inline void
-mdl_remove(struct IsdnCardState *cs)
-{
-	cs->status = 0;
-	if (cs->card_ops->led_handler)
-		cs->card_ops->led_handler(cs);
-}
-
 unsigned int
 random_ri(void)
 {
@@ -116,10 +100,10 @@
 }
 
 static void
-put_tei_msg(struct PStack *st, u8 m_id, unsigned int ri, u8 tei)
+put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
 {
 	struct sk_buff *skb;
-	u8 *bp;
+	u_char *bp;
 
 	if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
 		printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
@@ -135,7 +119,7 @@
 	bp[2] = ri & 0xff;
 	bp[3] = m_id;
 	bp[4] = (tei << 1) | 1;
-	L2L1(st, PH_DATA | REQUEST, skb);
+	st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
 static void
@@ -145,7 +129,7 @@
 
 	if (st->l2.tei != -1) {
 		st->ma.tei_m.printdebug(&st->ma.tei_m,
-			"assign request for already assigned tei %d",
+			"assign request for allready asigned tei %d",
 			st->l2.tei);
 		return;
 	}
@@ -181,9 +165,9 @@
 	} else if (ri == st->ma.ri) {
 		FsmDelTimer(&st->ma.t202, 1);
 		FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
-		L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
+		st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
 		cs = (struct IsdnCardState *) st->l1.hardware;
-		mdl_assign(cs);
+		cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
 	}
 }
 
@@ -255,9 +239,9 @@
 	if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
 		FsmDelTimer(&st->ma.t202, 5);
 		FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
-		L3L2(st, MDL_REMOVE | REQUEST, 0);
+		st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
-		mdl_remove(cs);
+		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 	}
 }
 
@@ -291,9 +275,9 @@
 		FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
 	} else {
 		st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
-		L3L2(st, MDL_ERROR | RESPONSE, 0);
+		st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
-		mdl_remove(cs);
+		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 		FsmChangeState(fi, ST_TEI_NOP);
 	}
 }
@@ -314,9 +298,9 @@
 	} else {
 		st->ma.tei_m.printdebug(&st->ma.tei_m,
 			"verify req for tei %d failed", st->l2.tei);
-		L3L2(st, MDL_REMOVE | REQUEST, 0);
+		st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
 		cs = (struct IsdnCardState *) st->l1.hardware;
-		mdl_remove(cs);
+		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
 		FsmChangeState(fi, ST_TEI_NOP);
 	}
 }
@@ -387,9 +371,9 @@
 			if (st->ma.debug)
 				st->ma.tei_m.printdebug(&st->ma.tei_m,
 					"fixed assign tei %d", st->l2.tei);
-			L3L2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
+			st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
 			cs = (struct IsdnCardState *) st->l1.hardware;
-			mdl_assign(cs);
+			cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
 		}
 		return;
 	}
--- diff/drivers/isdn/hisax/teleint.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/hisax/teleint.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: teleint.c,v 1.14.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $
  *
  * low level stuff for TeleInt isdn cards
  *
@@ -18,38 +18,33 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.14.6.2 $";
-static spinlock_t teleint_lock = SPIN_LOCK_UNLOCKED;
+const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static inline u8
-readreg(unsigned int ale, unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
 {
-	register u8 ret;
+	register u_char ret;
 	int max_delay = 2000;
-	unsigned long flags;
 
-	spin_lock_irqsave(&teleint_lock, flags);
 	byteout(ale, off);
 	ret = HFC_BUSY & bytein(ale);
 	while (ret && --max_delay)
 		ret = HFC_BUSY & bytein(ale);
 	if (!max_delay) {
 		printk(KERN_WARNING "TeleInt Busy not inactive\n");
-		spin_unlock_irqrestore(&teleint_lock, flags);
 		return (0);
 	}
 	ret = bytein(adr);
-	spin_unlock_irqrestore(&teleint_lock, flags);
 	return (ret);
 }
 
 static inline void
-readfifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	register u8 ret;
+	register u_char ret;
 	register int max_delay = 20000;
 	register int i;
 	
@@ -68,34 +63,29 @@
 
 
 static inline void
-writereg(unsigned int ale, unsigned int adr, u8 off, u8 data)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
-	register u8 ret;
+	register u_char ret;
 	int max_delay = 2000;
-	unsigned long flags;
 
-	spin_lock_irqsave(&teleint_lock, flags);
 	byteout(ale, off);
 	ret = HFC_BUSY & bytein(ale);
 	while (ret && --max_delay)
 		ret = HFC_BUSY & bytein(ale);
 	if (!max_delay) {
 		printk(KERN_WARNING "TeleInt Busy not inactive\n");
-		spin_unlock_irqrestore(&teleint_lock, flags);
 		return;
 	}
 	byteout(adr, data);
-	spin_unlock_irqrestore(&teleint_lock, flags);
 }
 
 static inline void
-writefifo(unsigned int ale, unsigned int adr, u8 off, u8 * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-	register u8 ret;
+	register u_char ret;
 	register int max_delay = 20000;
 	register int i;
 	
-	/* fifo write without cli because it's already done  */
 	byteout(ale, off);
 	for (i = 0; i<size; i++) {
 		ret = HFC_BUSY & bytein(ale);
@@ -111,45 +101,38 @@
 
 /* Interface functions */
 
-static u8
-ReadISAC(struct IsdnCardState *cs, u8 offset)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
 	cs->hw.hfc.cip = offset;
 	return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
 }
 
 static void
-WriteISAC(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	cs->hw.hfc.cip = offset;
 	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
 }
 
 static void
-ReadISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	cs->hw.hfc.cip = 0;
 	readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
 }
 
 static void
-WriteISACfifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	cs->hw.hfc.cip = 0;
 	writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = ReadISAC,
-	.write_reg  = WriteISAC,
-	.read_fifo  = ReadISACfifo,
-	.write_fifo = WriteISACfifo,
-};
-
-static u8
-ReadHFC(struct IsdnCardState *cs, int data, u8 reg)
+static u_char
+ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
 {
-	register u8 ret;
+	register u_char ret;
 
 	if (data) {
 		cs->hw.hfc.cip = reg;
@@ -163,7 +146,7 @@
 }
 
 static void
-WriteHFC(struct IsdnCardState *cs, int data, u8 reg, u8 value)
+WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
 {
 	byteout(cs->hw.hfc.addr | 1, reg);
 	cs->hw.hfc.cip = reg;
@@ -173,18 +156,14 @@
 		debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
 }
 
-static struct bc_hw_ops hfc_ops = {
-	.read_reg  = ReadHFC,
-	.write_reg = WriteHFC,
-};
-
 static irqreturn_t
-teleint_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_char val;
+	u_long flags;
 
-	spin_lock(&cs->lock);
+	spin_lock_irqsave(&cs->lock, flags);
 	val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
       Start_ISAC:
 	if (val)
@@ -197,7 +176,7 @@
 	}
 	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
 	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -205,7 +184,9 @@
 TeleInt_Timer(struct IsdnCardState *cs)
 {
 	int stat = 0;
-
+	u_long flags;
+	
+	spin_lock_irqsave(&cs->lock, flags);
 	if (cs->bcs[0].mode) {
 		stat |= 1;
 		main_irq_hfc(&cs->bcs[0]);
@@ -214,52 +195,83 @@
 		stat |= 2;
 		main_irq_hfc(&cs->bcs[1]);
 	}
-	cs->hw.hfc.timer.expires = jiffies + 1;
+	spin_unlock_irqrestore(&cs->lock, flags);
+	stat = HZ/100;
+	if (!stat)
+		stat = 1;
+	cs->hw.hfc.timer.expires = jiffies + stat;
 	add_timer(&cs->hw.hfc.timer);
 }
 
-static void
-teleint_release(struct IsdnCardState *cs)
+void
+release_io_TeleInt(struct IsdnCardState *cs)
 {
 	del_timer(&cs->hw.hfc.timer);
 	releasehfc(cs);
-	hisax_release_resources(cs);
+	if (cs->hw.hfc.addr)
+		release_region(cs->hw.hfc.addr, 2);
 }
 
-static int
-teleint_reset(struct IsdnCardState *cs)
+static void
+reset_TeleInt(struct IsdnCardState *cs)
 {
 	printk(KERN_INFO "TeleInt: resetting card\n");
 	cs->hw.hfc.cirm |= HFC_RESET;
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset On */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30*HZ)/1000);
+	mdelay(10);
 	cs->hw.hfc.cirm &= ~HFC_RESET;
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset Off */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((10*HZ)/1000);
-	return 0;
+	mdelay(10);
 }
 
-static void
-teleint_init(struct IsdnCardState *cs)
+static int
+TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	inithfc(cs);
-	initisac(cs);
-	cs->hw.hfc.timer.expires = jiffies + 1;
-	add_timer(&cs->hw.hfc.timer);
-}
+	u_long flags;
+	int delay;
 
-static struct card_ops teleint_ops = {
-	.init     = teleint_init,
-	.reset    = teleint_reset,
-	.release  = teleint_release,
-	.irq_func = teleint_interrupt,
-};
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_TeleInt(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_TeleInt(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_TeleInt(cs);
+			inithfc(cs);
+			clear_pending_isac_ints(cs);
+			initisac(cs);
+			/* Reenable all IRQ */
+			cs->writeisac(cs, ISAC_MASK, 0);
+			cs->writeisac(cs, ISAC_CMDR, 0x41);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			delay = HZ/100;
+			if (!delay)
+				delay = 1;
+			cs->hw.hfc.timer.expires = jiffies + delay;
+			add_timer(&cs->hw.hfc.timer);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
+}
 
-static int __init
-teleint_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, TeleInt_revision);
+	printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_TELEINT)
+		return (0);
+
 	cs->hw.hfc.addr = card->para[1] & 0x3fe;
 	cs->irq = card->para[0];
 	cs->hw.hfc.cirm = HFC_CIRM;
@@ -272,61 +284,56 @@
 	cs->hw.hfc.timer.function = (void *) TeleInt_Timer;
 	cs->hw.hfc.timer.data = (long) cs;
 	init_timer(&cs->hw.hfc.timer);
-	if (!request_io(&cs->rs, cs->hw.hfc.addr, 2, "TeleInt isdn"))
-		goto err;
-	
+	if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.hfc.addr,
+		       cs->hw.hfc.addr + 2);
+		return (0);
+	}
 	/* HW IO = IO */
 	byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
 	byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
 	switch (cs->irq) {
-	case 3:
-		cs->hw.hfc.cirm |= HFC_INTA;
-		break;
-	case 4:
-		cs->hw.hfc.cirm |= HFC_INTB;
-		break;
-	case 5:
-		cs->hw.hfc.cirm |= HFC_INTC;
-		break;
-	case 7:
-		cs->hw.hfc.cirm |= HFC_INTD;
-		break;
-	case 10:
-		cs->hw.hfc.cirm |= HFC_INTE;
-		break;
-	case 11:
-		cs->hw.hfc.cirm |= HFC_INTF;
-		break;
-	default:
-		printk(KERN_WARNING "TeleInt: wrong IRQ\n");
-		goto err;
+		case 3:
+			cs->hw.hfc.cirm |= HFC_INTA;
+			break;
+		case 4:
+			cs->hw.hfc.cirm |= HFC_INTB;
+			break;
+		case 5:
+			cs->hw.hfc.cirm |= HFC_INTC;
+			break;
+		case 7:
+			cs->hw.hfc.cirm |= HFC_INTD;
+			break;
+		case 10:
+			cs->hw.hfc.cirm |= HFC_INTE;
+			break;
+		case 11:
+			cs->hw.hfc.cirm |= HFC_INTF;
+			break;
+		default:
+			printk(KERN_WARNING "TeleInt: wrong IRQ\n");
+			release_io_TeleInt(cs);
+			return (0);
 	}
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
 
 	printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n",
-	       cs->hw.hfc.addr, cs->irq);
-
-	cs->card_ops = &teleint_ops;
-	teleint_reset(cs);
-	isac_setup(cs, &isac_ops);
-	hfc_setup(cs, &hfc_ops);
-	return 0;
-
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-int __init
-setup_TeleInt(struct IsdnCard *card)
-{
-	char tmp[64];
-
-	strcpy(tmp, TeleInt_revision);
-	printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
+		cs->hw.hfc.addr, cs->irq);
 
-	if (teleint_probe(card->cs, card) < 0)
-		return 0;
-	return 1;
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHFC;
+	cs->BC_Write_Reg = &WriteHFC;
+	cs->cardmsg = &TeleInt_card_msg;
+	cs->irq_func = &TeleInt_interrupt;
+	ISACVersion(cs, "TeleInt:");
+	return (1);
 }
--- diff/drivers/isdn/hisax/teles0.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/teles0.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.13.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for Teles Memory IO isdn cards
  *
@@ -23,97 +23,179 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.13.6.2 $";
+const char *teles0_revision = "$Revision: 2.15.2.4 $";
 
 #define TELES_IOMEM_SIZE	0x400
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 off)
+static inline u_char
+readisac(unsigned long adr, u_char off)
 {
-	return readb(cs->hw.teles0.membase + 
-		     ((off & 1) ? 0x2ff : 0x100) + off);
+	return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
-static void
-isac_write(struct IsdnCardState *cs, u8 off, u8 data)
+static inline void
+writeisac(unsigned long adr, u_char off, u_char data)
 {
-	writeb(data, cs->hw.teles0.membase + 
-	       ((off & 1) ? 0x2ff : 0x100) + off); mb();
+	writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
 }
 
 
-static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+static inline u_char
+readhscx(unsigned long adr, int hscx, u_char off)
 {
-	int i;
-	void *ad = cs->hw.teles0.membase + 0x100;
+	return readb(adr + (hscx ? 0x1c0 : 0x180) +
+		     ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
+{
+	writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
+	       ((off & 1) ? 0x1ff : 0) + off); mb();
+}
+
+static inline void
+read_fifo_isac(unsigned long adr, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *)adr + 0x100;
 	for (i = 0; i < size; i++)
 		data[i] = readb(ad);
 }
 
-static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+static inline void
+write_fifo_isac(unsigned long adr, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *)adr + 0x100;
+	for (i = 0; i < size; i++) {
+		writeb(data[i], ad); mb();
+	}
+}
+
+static inline void
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+	for (i = 0; i < size; i++)
+		data[i] = readb(ad);
+}
+
+static inline void
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
 	int i;
-	void *ad = cs->hw.teles0.membase + 0x100;
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
 	for (i = 0; i < size; i++) {
 		writeb(data[i], ad); mb();
 	}
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
+/* Interface functions */
 
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readb(cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180) +
-		     ((off & 1) ? 0x1ff : 0) + off);
+	return (readisac(cs->hw.teles0.membase, offset));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 data)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-	writeb(data, cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180) +
-	       ((off & 1) ? 0x1ff : 0) + off); mb();
+	writeisac(cs->hw.teles0.membase, offset, value);
 }
 
 static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	int i;
-	void *ad = cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180);
-	for (i = 0; i < size; i++)
-		data[i] = readb(ad);
+	read_fifo_isac(cs->hw.teles0.membase, data, size);
 }
 
 static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-	int i;
-	void *ad = cs->hw.teles0.membase + (hscx ? 0x1c0 : 0x180);
-	for (i = 0; i < size; i++) {
-		writeb(data[i], ad);
-	}
+	write_fifo_isac(cs->hw.teles0.membase, data, size);
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return (readhscx(cs->hw.teles0.membase, hscx, offset));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	writehscx(cs->hw.teles0.membase, hscx, offset, value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+	int count = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	count++;
+	val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+	if (val && count < 5) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+	if (val && count < 5) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+	writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+	writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+	writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
+	writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+	writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+void
+release_io_teles0(struct IsdnCardState *cs)
+{
+	if (cs->hw.teles0.cfg_reg)
+		release_region(cs->hw.teles0.cfg_reg, 8);
+	iounmap((unsigned char *)cs->hw.teles0.membase);
+	release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
+}
 
 static int
-teles0_reset(struct IsdnCardState *cs)
+reset_teles0(struct IsdnCardState *cs)
 {
-	u8 cfval;
+	u_char cfval;
 
 	if (cs->hw.teles0.cfg_reg) {
 		switch (cs->irq) {
@@ -158,102 +240,129 @@
 	return(0);
 }
 
-static struct card_ops teles0_ops = {
-	.init     = inithscxisac,
-	.reset    = teles0_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
-static int __init
-teles0_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->irq = card->para[0];
-	/* 16.0 and 8.0 designed for IOM1 */
-	test_and_set_bit(HW_IOM1, &cs->HW_Flags);
-	cs->hw.teles0.phymem = card->para[1];
-	cs->hw.teles0.membase = request_mmio(&cs->rs, cs->hw.teles0.phymem,
-					     TELES_IOMEM_SIZE, "teles iomem");
-	if (!cs->hw.teles0.membase)
-		return -EBUSY;
-
-	if (teles0_reset(cs)) {
-		printk(KERN_WARNING "Teles0: wrong IRQ\n");
-		return -EBUSY;
-	}
-	cs->card_ops = &teles0_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int __init
-teles16_0_probe(struct IsdnCardState *cs, struct IsdnCard *card)
+static int
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	u8 val;
+	u_long flags;
 
-	cs->hw.teles0.cfg_reg = card->para[2];
-	if (!request_io(&cs->rs, cs->hw.teles0.cfg_reg, 8, "teles cfg"))
-		goto err;
-		
-	if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
-		printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
-		       cs->hw.teles0.cfg_reg + 0, val);
-		goto err;
-	}
-	if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
-		printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
-		       cs->hw.teles0.cfg_reg + 1, val);
-		goto err;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_teles0(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_teles0(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	val = bytein(cs->hw.teles0.cfg_reg + 2);/* 0x1e=without AB
-						 * 0x1f=with AB
-						 * 0x1c 16.3 ???
-						 */
-	if (val != 0x1e && val != 0x1f) {
-		printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
-		       cs->hw.teles0.cfg_reg + 2, val);
-		goto err;
-	}
-	if (teles0_probe(cs, card) < 0)
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-teles8_0_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->hw.teles0.cfg_reg = 0;
-
-	if (teles0_probe(cs, card) < 0)
-		goto err;
-
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return(0);
 }
 
 int __init
 setup_teles0(struct IsdnCard *card)
 {
+	u_char val;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, teles0_revision);
-	printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-
-	if (card->cs->typ == ISDN_CTYPE_16_0) {
-		if (teles16_0_probe(card->cs, card) < 0)
-			return 0;
-	} else {
-		if (teles8_0_probe(card->cs, card) < 0)
-			return 0;
+	printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
+	if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
+		return (0);
+
+	if (cs->typ == ISDN_CTYPE_16_0)
+		cs->hw.teles0.cfg_reg = card->para[2];
+	else			/* 8.0 */
+		cs->hw.teles0.cfg_reg = 0;
+
+	if (card->para[1] < 0x10000) {
+		card->para[1] <<= 4;
+		printk(KERN_INFO
+		   "Teles0: membase configured DOSish, assuming 0x%lx\n",
+		       (unsigned long) card->para[1]);
+	}
+	cs->irq = card->para[0];
+	if (cs->hw.teles0.cfg_reg) {
+		if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
+			printk(KERN_WARNING
+			  "HiSax: %s config port %x-%x already in use\n",
+			       CardType[card->typ],
+			       cs->hw.teles0.cfg_reg,
+			       cs->hw.teles0.cfg_reg + 8);
+			return (0);
+		}
+	}
+	if (cs->hw.teles0.cfg_reg) {
+		if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       cs->hw.teles0.cfg_reg + 0, val);
+			release_region(cs->hw.teles0.cfg_reg, 8);
+			return (0);
+		}
+		if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       cs->hw.teles0.cfg_reg + 1, val);
+			release_region(cs->hw.teles0.cfg_reg, 8);
+			return (0);
+		}
+		val = bytein(cs->hw.teles0.cfg_reg + 2);	/* 0x1e=without AB
+								   * 0x1f=with AB
+								   * 0x1c 16.3 ???
+								 */
+		if (val != 0x1e && val != 0x1f) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       cs->hw.teles0.cfg_reg + 2, val);
+			release_region(cs->hw.teles0.cfg_reg, 8);
+			return (0);
+		}
+	}
+	/* 16.0 and 8.0 designed for IOM1 */
+	test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+	cs->hw.teles0.phymem = card->para[1];
+	if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
+		printk(KERN_WARNING
+			"HiSax: %s memory region %lx-%lx already in use\n",
+			CardType[card->typ],
+			cs->hw.teles0.phymem,
+			cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
+		if (cs->hw.teles0.cfg_reg)
+			release_region(cs->hw.teles0.cfg_reg, 8);
+		return (0);
+	}
+	cs->hw.teles0.membase =
+		(unsigned long) ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
+	printk(KERN_INFO
+	       "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n",
+	       CardType[cs->typ], cs->irq,
+	       cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
+	if (reset_teles0(cs)) {
+		printk(KERN_WARNING "Teles0: wrong IRQ\n");
+		release_io_teles0(cs);
+		return (0);
+	}
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Teles_card_msg;
+	cs->irq_func = &teles0_interrupt;
+	ISACVersion(cs, "Teles0:");
+	if (HscxVersion(cs, "Teles0:")) {
+		printk(KERN_WARNING
+		 "Teles0: wrong HSCX versions check IO/MEM addresses\n");
+		release_io_teles0(cs);
+		return (0);
 	}
-	return 1;
+	return (1);
 }
--- diff/drivers/isdn/hisax/teles3.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/hisax/teles3.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 2.17.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $
  *
  * low level stuff for Teles 16.3 & PNP isdn cards
  *
@@ -21,102 +21,160 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.17.6.2 $";
+const char *teles3_revision = "$Revision: 2.19.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static inline u8
-readreg(unsigned int adr, u8 off)
+static inline u_char
+readreg(unsigned int adr, u_char off)
 {
 	return (bytein(adr + off));
 }
 
 static inline void
-writereg(unsigned int adr, u8 off, u8 data)
+writereg(unsigned int adr, u_char off, u_char data)
 {
 	byteout(adr + off, data);
 }
 
 
 static inline void
-read_fifo(unsigned int adr, u8 * data, int size)
+read_fifo(unsigned int adr, u_char * data, int size)
 {
 	insb(adr, data, size);
 }
 
 static void
-write_fifo(unsigned int adr, u8 * data, int size)
+write_fifo(unsigned int adr, u_char * data, int size)
 {
 	outsb(adr, data, size);
 }
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 offset)
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return readreg(cs->hw.teles3.isac, offset);
+	return (readreg(cs->hw.teles3.isac, offset));
 }
 
 static void
-isac_write(struct IsdnCardState *cs, u8 offset, u8 value)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.teles3.isac, offset, value);
 }
 
 static void
-isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	read_fifo(cs->hw.teles3.isacfifo, data, size);
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	write_fifo(cs->hw.teles3.isacfifo, data, size);
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 offset)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return readreg(cs->hw.teles3.hscx[hscx], offset);
+	return (readreg(cs->hw.teles3.hscx[hscx], offset));
 }
 
 static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
 	writereg(cs->hw.teles3.hscx[hscx], offset, value);
 }
 
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	read_fifo(cs->hw.teles3.hscxfifo[hscx], data, size);
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 *data, int size)
-{
-	write_fifo(cs->hw.teles3.hscxfifo[hscx], data, size);
+#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+
+#include "hscx_irq.c"
+
+static irqreturn_t
+teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 5
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_long flags;
+	int count = 0;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
+      Start_HSCX:
+	if (val)
+		hscx_int_main(cs, val);
+	val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		isac_interrupt(cs, val);
+	count++;
+	val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	if (count >= MAXCOUNT)
+		printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
+	writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+	writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+	writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+	writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
+	writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+	writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
+	return IRQ_HANDLED;
+}
+
+inline static void
+release_ioregs(struct IsdnCardState *cs, int mask)
+{
+	if (mask & 1)
+		release_region(cs->hw.teles3.isac + 32, 32);
+	if (mask & 2)
+		release_region(cs->hw.teles3.hscx[0] + 32, 32);
+	if (mask & 4)
+		release_region(cs->hw.teles3.hscx[1] + 32, 32);
+}
+
+void
+release_io_teles3(struct IsdnCardState *cs)
+{
+	if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+		release_region(cs->hw.teles3.hscx[1], 96);
+	} else {
+		if (cs->hw.teles3.cfg_reg) {
+			if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+				release_region(cs->hw.teles3.cfg_reg, 1);
+			} else {
+				release_region(cs->hw.teles3.cfg_reg, 8);
+			}
+		}
+		release_ioregs(cs, 0x7);
+	}
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
-
 static int
-teles3_reset(struct IsdnCardState *cs)
+reset_teles3(struct IsdnCardState *cs)
 {
-	u8 irqcfg;
+	u_char irqcfg;
 
 	if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
 		if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
@@ -169,160 +227,33 @@
 	return(0);
 }
 
-static struct card_ops teles3_ops = {
-	.init     = inithscxisac,
-	.reset    = teles3_reset,
-	.release  = hisax_release_resources,
-	.irq_func = hscxisac_irq,
-};
-
 static int
-teles_hw_init(struct IsdnCardState *cs)
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-	
-	printk(KERN_INFO "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
-	       CardType[cs->typ], cs->irq,
-	       cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
-	printk(KERN_INFO "HiSax: hscx A:0x%X  hscx B:0x%X\n",
-	       cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
+	u_long flags;
 
-	if (teles3_reset(cs)) {
-		printk(KERN_WARNING "Teles3: wrong IRQ\n");
-		return -EBUSY;
+	switch (mt) {
+		case CARD_RESET:
+			spin_lock_irqsave(&cs->lock, flags);
+			reset_teles3(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_RELEASE:
+			release_io_teles3(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
 	}
-	cs->card_ops = &teles3_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		return -EBUSY;
-	return 0;
-}
-
-static void __init
-teles_setup_io(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->irq = card->para[0];
-	cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
-	cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
-	cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
-}
-
-static int __init
-telespcmcia_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->hw.teles3.cfg_reg = 0;
-	cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
-	cs->hw.teles3.hscx[1] = card->para[1];
-	cs->hw.teles3.isac = card->para[1] + 0x20;
-	teles_setup_io(cs, card);
-	if (!request_io(&cs->rs, cs->hw.teles3.hscx[1], 96, 
-			"HiSax Teles PCMCIA"))
-		goto err;
-	if (teles_hw_init(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-teles_request_io(struct IsdnCardState *cs)
-{
-	if (!request_io(&cs->rs, cs->hw.teles3.isac + 32, 32, "HiSax isac"))
-		return -EBUSY;
-	if (!request_io(&cs->rs, cs->hw.teles3.hscx[0]+32, 32, "HiSax hscx A"))
-		return -EBUSY;
-	if (!request_io(&cs->rs, cs->hw.teles3.hscx[1]+32, 32, "HiSax hscx B"))
-		return -EBUSY;
-	return 0;
-}
-
-static int __init
-teles16_3_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	u8 val;
-
-	cs->hw.teles3.cfg_reg = card->para[1];
-	switch (cs->hw.teles3.cfg_reg) {
-	case 0x180:
-	case 0x280:
-	case 0x380:
-		cs->hw.teles3.cfg_reg |= 0xc00;
-		break;
-	}
-	cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
-	cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
-	cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
-	teles_setup_io(cs, card);
-	if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 8, "teles3 cfg"))
-		goto err;
-	if (teles_request_io(cs) < 0)
-		goto err;
-	if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
-		printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
-		       cs->hw.teles3.cfg_reg + 0, val);
-		goto err;
-	}
-	if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
-		printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
-		       cs->hw.teles3.cfg_reg + 1, val);
-		goto err;
-	}
-	/* 0x1e without AB, 0x1f with AB,  0x1c 16.3 ???, 
-	 * 0x39 16.3 1.1,   0x38 16.3 1.3, 0x46 16.3 with AB + Video */
-	val = bytein(cs->hw.teles3.cfg_reg + 2);
-	if (val != 0x46 && val != 0x39 && val != 0x38 && 
-	    val != 0x1c && val != 0x1e && val != 0x1f) {
-		printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
-		       cs->hw.teles3.cfg_reg + 2, val);
-		goto err;
-	}
-	if (teles_hw_init(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-compaq_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->hw.teles3.cfg_reg = card->para[3];
-	cs->hw.teles3.isac = card->para[2] - 32;
-	cs->hw.teles3.hscx[0] = card->para[1] - 32;
-	cs->hw.teles3.hscx[1] = card->para[1];
-	teles_setup_io(cs, card);
-	if (!request_io(&cs->rs, cs->hw.teles3.cfg_reg, 1, "teles3 cfg"))
-		goto err;
-	if (teles_request_io(cs) < 0)
-		goto err;
-	if (teles_hw_init(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
-}
-
-static int __init
-telespnp_probe(struct IsdnCardState *cs, struct IsdnCard *card)
-{
-	cs->hw.teles3.cfg_reg = 0;
-	cs->hw.teles3.isac = card->para[1] - 32;
-	cs->hw.teles3.hscx[0] = card->para[2] - 32;
-	cs->hw.teles3.hscx[1] = card->para[2];
-	teles_setup_io(cs, card);
-	if (teles_request_io(cs) < 0)
-		goto err;
-	if (teles_hw_init(cs) < 0)
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return -EBUSY;
+	return(0);
 }
 
 #ifdef __ISAPNP__
+
 static struct isapnp_device_id teles_ids[] __initdata = {
 	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
 	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
@@ -336,80 +267,233 @@
 	{ 0, }
 };
 
-static struct isapnp_device_id *tdev = &teles_ids[0];
+static struct isapnp_device_id *ipid __initdata = &teles_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
 int __devinit
 setup_teles3(struct IsdnCard *card)
 {
+	u_char val;
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 	strcpy(tmp, teles3_revision);
 	printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
+	if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
+	    && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
+		return (0);
+
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
-		struct pnp_card *pnp_card;
-		struct pnp_dev *pnp_dev;
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-		while(tdev->card_vendor) {
-			if ((pnp_card = pnp_find_card(tdev->card_vendor,
-						      tdev->card_device, pnp_c))) {
-				pnp_c = pnp_card;
-				pnp_dev = NULL;
-				if ((pnp_dev = pnp_find_dev(pnp_card,
-							    tdev->vendor,
-							    tdev->function,
-							    pnp_dev))) {
 					printk(KERN_INFO "HiSax: %s detected\n",
-						(char *)tdev->driver_data);
-					if (pnp_device_attach(pnp_dev) < 0) {
-						printk(KERN_ERR "Teles PnP: attach failed\n");
-						return 0;
-					}
-					if (pnp_activate_dev(pnp_dev) < 0) {
-						printk(KERN_ERR "Teles PnP: activate failed\n");
-						pnp_device_detach(pnp_dev);
-						return 0;
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
+						return(0);
 					}
-					if (!pnp_irq_valid(pnp_dev, 0) ||
-					    !pnp_port_valid(pnp_dev, 0) ||
-					    !pnp_port_valid(pnp_dev, 1)) {
-						printk(KERN_ERR "Teles PnP: some resources are missing %ld/%lx/%lx\n",
-							pnp_irq(pnp_dev, 0), pnp_port_start(pnp_dev, 0), pnp_port_start(pnp_dev, 1));
-						pnp_device_detach(pnp_dev);
-						return 0;
+					card->para[3] = pnp_port_start(pnp_d, 2);
+					card->para[2] = pnp_port_start(pnp_d, 1);
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+					if (!card->para[0] || !card->para[1] || !card->para[2]) {
+						printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
+							card->para[0], card->para[1], card->para[2]);
+						pnp_disable_dev(pnp_d);
+						return(0);
 					}
-					card->para[3] = pnp_port_start(pnp_dev, 2);
-					card->para[2] = pnp_port_start(pnp_dev, 1);
-					card->para[1] = pnp_port_start(pnp_dev, 0);
-					card->para[0] = pnp_irq(pnp_dev, 0);
 					break;
 				} else {
 					printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
 				}
 			}
-			tdev++;
-			pnp_c=NULL;
+			ipid++;
+			pnp_c = NULL;
 		} 
-		if (!tdev->card_vendor) {
+		if (!ipid->card_vendor) {
 			printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
 			return(0);
 		}
 	}
 #endif
-	if (card->cs->typ == ISDN_CTYPE_16_3) {
-		if (teles16_3_probe(card->cs, card) < 0)
-			return 0;
-	} else if (card->cs->typ == ISDN_CTYPE_TELESPCMCIA) {
-		if (telespcmcia_probe(card->cs, card) < 0)
-			return 0;
-	} else if (card->cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
-		if (compaq_probe(card->cs, card) < 0)
-			return 0;
+	if (cs->typ == ISDN_CTYPE_16_3) {
+		cs->hw.teles3.cfg_reg = card->para[1];
+		switch (cs->hw.teles3.cfg_reg) {
+			case 0x180:
+			case 0x280:
+			case 0x380:
+				cs->hw.teles3.cfg_reg |= 0xc00;
+				break;
+		}
+		cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
+		cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
+		cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
+	} else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+		cs->hw.teles3.cfg_reg = 0;
+		cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
+		cs->hw.teles3.hscx[1] = card->para[1];
+		cs->hw.teles3.isac = card->para[1] + 0x20;
+	} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+		cs->hw.teles3.cfg_reg = card->para[3];
+		cs->hw.teles3.isac = card->para[2] - 32;
+		cs->hw.teles3.hscx[0] = card->para[1] - 32;
+		cs->hw.teles3.hscx[1] = card->para[1];
 	} else {	/* PNP */
-		if (telespnp_probe(card->cs, card) < 0)
-			return 0;
+		cs->hw.teles3.cfg_reg = 0;
+		cs->hw.teles3.isac = card->para[1] - 32;
+		cs->hw.teles3.hscx[0] = card->para[2] - 32;
+		cs->hw.teles3.hscx[1] = card->para[2];
+	}
+	cs->irq = card->para[0];
+	cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
+	cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
+	cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
+	if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+		if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
+			printk(KERN_WARNING
+			       "HiSax: %s ports %x-%x already in use\n",
+			       CardType[cs->typ],
+			       cs->hw.teles3.hscx[1],
+			       cs->hw.teles3.hscx[1] + 96);
+			return (0);
+		}
+	} else {
+		if (cs->hw.teles3.cfg_reg) {
+			if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+				if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
+					printk(KERN_WARNING
+						"HiSax: %s config port %x already in use\n",
+						CardType[card->typ],
+						cs->hw.teles3.cfg_reg);
+					return (0);
+				}
+			} else {
+				if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
+					printk(KERN_WARNING
+					       "HiSax: %s config port %x-%x already in use\n",
+					       CardType[card->typ],
+					       cs->hw.teles3.cfg_reg,
+						cs->hw.teles3.cfg_reg + 8);
+					return (0);
+				}
+			}
+		}
+		if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
+			printk(KERN_WARNING
+			   "HiSax: %s isac ports %x-%x already in use\n",
+			       CardType[cs->typ],
+			       cs->hw.teles3.isac + 32,
+			       cs->hw.teles3.isac + 64);
+			if (cs->hw.teles3.cfg_reg) {
+				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+					release_region(cs->hw.teles3.cfg_reg, 1);
+				} else {
+					release_region(cs->hw.teles3.cfg_reg, 8);
+				}
+			}
+			return (0);
+		}
+		if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
+			printk(KERN_WARNING
+			 "HiSax: %s hscx A ports %x-%x already in use\n",
+			       CardType[cs->typ],
+			       cs->hw.teles3.hscx[0] + 32,
+			       cs->hw.teles3.hscx[0] + 64);
+			if (cs->hw.teles3.cfg_reg) {
+				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+					release_region(cs->hw.teles3.cfg_reg, 1);
+				} else {
+					release_region(cs->hw.teles3.cfg_reg, 8);
+				}
+			}
+			release_ioregs(cs, 1);
+			return (0);
+		}
+		if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
+			printk(KERN_WARNING
+			 "HiSax: %s hscx B ports %x-%x already in use\n",
+			       CardType[cs->typ],
+			       cs->hw.teles3.hscx[1] + 32,
+			       cs->hw.teles3.hscx[1] + 64);
+			if (cs->hw.teles3.cfg_reg) {
+				if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+					release_region(cs->hw.teles3.cfg_reg, 1);
+				} else {
+					release_region(cs->hw.teles3.cfg_reg, 8);
+				}
+			}
+			release_ioregs(cs, 3);
+			return (0);
+		}
+	}
+	if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
+		if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       cs->hw.teles3.cfg_reg + 0, val);
+			release_io_teles3(cs);
+			return (0);
+		}
+		if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       cs->hw.teles3.cfg_reg + 1, val);
+			release_io_teles3(cs);
+			return (0);
+		}
+		val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
+							 * 0x1f=with AB
+							 * 0x1c 16.3 ???
+							 * 0x39 16.3 1.1
+							 * 0x38 16.3 1.3
+							 * 0x46 16.3 with AB + Video (Teles-Vision)
+							 */
+		if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       cs->hw.teles3.cfg_reg + 2, val);
+			release_io_teles3(cs);
+			return (0);
+		}
+	}
+	printk(KERN_INFO
+	       "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
+	       CardType[cs->typ], cs->irq,
+	       cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
+	printk(KERN_INFO
+	       "HiSax: hscx A:0x%X  hscx B:0x%X\n",
+	       cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
+
+	setup_isac(cs);
+	if (reset_teles3(cs)) {
+		printk(KERN_WARNING "Teles3: wrong IRQ\n");
+		release_io_teles3(cs);
+		return (0);
+	}
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &Teles_card_msg;
+	cs->irq_func = &teles3_interrupt;
+	ISACVersion(cs, "Teles3:");
+	if (HscxVersion(cs, "Teles3:")) {
+		printk(KERN_WARNING
+		       "Teles3: wrong HSCX versions check IO address\n");
+		release_io_teles3(cs);
+		return (0);
 	}
-	return 1;
+	return (1);
 }
--- diff/drivers/isdn/hisax/telespci.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/telespci.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: telespci.c,v 2.16.6.5 2001/09/23 22:24:52 kai Exp $
+/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $
  *
  * low level stuff for Teles PCI isdn cards
  *
@@ -21,7 +21,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.16.6.5 $";
+const char *telespci_revision = "$Revision: 2.23.2.3 $";
 
 #define ZORAN_PO_RQ_PEN	0x02000000
 #define ZORAN_PO_WR	0x00800000
@@ -39,233 +39,250 @@
 #define WRITE_DATA_HSCX	(ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
 
 #define ZORAN_WAIT_NOBUSY	do { \
-					portdata = readl(adr); \
+					portdata = readl(adr + 0x200); \
 				} while (portdata & ZORAN_PO_RQ_PEN)
 
-static u8
-isac_read(struct IsdnCardState *cs, u8 off)
+static inline u_char
+readisac(unsigned long adr, u_char off)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
+	register unsigned int portdata;
 
 	ZORAN_WAIT_NOBUSY;
 	
 	/* set address for ISAC */
-	writel(WRITE_ADDR_ISAC | off, adr);
+	writel(WRITE_ADDR_ISAC | off, adr + 0x200);
 	ZORAN_WAIT_NOBUSY;
 	
 	/* read data from ISAC */
-	writel(READ_DATA_ISAC, adr);
+	writel(READ_DATA_ISAC, adr + 0x200);
 	ZORAN_WAIT_NOBUSY;
-	return((u8)(portdata & ZORAN_PO_DMASK));
+	return((u_char)(portdata & ZORAN_PO_DMASK));
 }
 
-static void
-isac_write(struct IsdnCardState *cs, u8 off, u8 data)
+static inline void
+writeisac(unsigned long adr, u_char off, u_char data)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
+	register unsigned int portdata;
 
 	ZORAN_WAIT_NOBUSY;
 	
 	/* set address for ISAC */
-	writel(WRITE_ADDR_ISAC | off, adr);
+	writel(WRITE_ADDR_ISAC | off, adr + 0x200);
 	ZORAN_WAIT_NOBUSY;
 
 	/* write data to ISAC */
-	writel(WRITE_DATA_ISAC | data, adr);
+	writel(WRITE_DATA_ISAC | data, adr + 0x200);
 	ZORAN_WAIT_NOBUSY;
 }
 
-static void
-isac_read_fifo(struct IsdnCardState *cs, u8 *data, int size)
+static inline u_char
+readhscx(unsigned long adr, int hscx, u_char off)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
-	int i;
+	register unsigned int portdata;
+
+	ZORAN_WAIT_NOBUSY;
+	/* set address for HSCX */
+	writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
+	ZORAN_WAIT_NOBUSY;
+	
+	/* read data from HSCX */
+	writel(READ_DATA_HSCX, adr + 0x200);
+	ZORAN_WAIT_NOBUSY;
+	return ((u_char)(portdata & ZORAN_PO_DMASK));
+}
+
+static inline void
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
+{
+	register unsigned int portdata;
+
+	ZORAN_WAIT_NOBUSY;
+	/* set address for HSCX */
+	writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
+	ZORAN_WAIT_NOBUSY;
+
+	/* write data to HSCX */
+	writel(WRITE_DATA_HSCX | data, adr + 0x200);
+	ZORAN_WAIT_NOBUSY;
+}
+
+static inline void
+read_fifo_isac(unsigned long adr, u_char * data, int size)
+{
+	register unsigned int portdata;
+	register int i;
 
 	ZORAN_WAIT_NOBUSY;
 	/* read data from ISAC */
 	for (i = 0; i < size; i++) {
 		/* set address for ISAC fifo */
-		writel(WRITE_ADDR_ISAC | 0x1E, adr);
+		writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		writel(READ_DATA_ISAC, adr);
+		writel(READ_DATA_ISAC, adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		data[i] = (u8)(portdata & ZORAN_PO_DMASK);
+		data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
 	}
 }
 
 static void
-isac_write_fifo(struct IsdnCardState *cs, u8 *data, int size)
+write_fifo_isac(unsigned long adr, u_char * data, int size)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
-	int i;
+	register unsigned int portdata;
+	register int i;
 
 	ZORAN_WAIT_NOBUSY;
 	/* write data to ISAC */
 	for (i = 0; i < size; i++) {
 		/* set address for ISAC fifo */
-		writel(WRITE_ADDR_ISAC | 0x1E, adr);
+		writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		writel(WRITE_DATA_ISAC | data[i], adr);
+		writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
 	}
 }
 
-static struct dc_hw_ops isac_ops = {
-	.read_reg   = isac_read,
-	.write_reg  = isac_write,
-	.read_fifo  = isac_read_fifo,
-	.write_fifo = isac_write_fifo,
-};
-
-static u8
-hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
-{
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
-
-	ZORAN_WAIT_NOBUSY;
-	/* set address for HSCX */
-	writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr);
-	ZORAN_WAIT_NOBUSY;
-	
-	/* read data from HSCX */
-	writel(READ_DATA_HSCX, adr);
-	ZORAN_WAIT_NOBUSY;
-	return ((u8)(portdata & ZORAN_PO_DMASK));
-}
-
-static void
-hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 data)
+static inline void
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
-
-	ZORAN_WAIT_NOBUSY;
-	/* set address for HSCX */
-	writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr);
-	ZORAN_WAIT_NOBUSY;
-
-	/* write data to HSCX */
-	writel(WRITE_DATA_HSCX | data, adr);
-	ZORAN_WAIT_NOBUSY;
-}
-
-static void
-hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
-{
-	void *adr = cs->hw.teles0.membase + 0x200;
-	unsigned int portdata;
-	int i;
+	register unsigned int portdata;
+	register int i;
 
 	ZORAN_WAIT_NOBUSY;
 	/* read data from HSCX */
 	for (i = 0; i < size; i++) {
 		/* set address for HSCX fifo */
-		writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr);
+		writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		writel(READ_DATA_HSCX, adr);
+		writel(READ_DATA_HSCX, adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		data[i] = (u8) (portdata & ZORAN_PO_DMASK);
+		data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
 	}
 }
 
-static void
-hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
+static inline void
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
-	void *adr = cs->hw.teles0.membase + 0x200;
 	unsigned int portdata;
-	int i;
+	register int i;
 
 	ZORAN_WAIT_NOBUSY;
 	/* write data to HSCX */
 	for (i = 0; i < size; i++) {
 		/* set address for HSCX fifo */
-		writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr);
+		writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
-		writel(WRITE_DATA_HSCX | data[i], adr);
+		writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
 		ZORAN_WAIT_NOBUSY;
 		udelay(10);
 	}
 }
 
-static struct bc_hw_ops hscx_ops = {
-	.read_reg   = hscx_read,
-	.write_reg  = hscx_write,
-	.read_fifo  = hscx_read_fifo,
-	.write_fifo = hscx_write_fifo,
-};
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+	return (readisac(cs->hw.teles0.membase, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	writeisac(cs->hw.teles0.membase, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	read_fifo_isac(cs->hw.teles0.membase, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	write_fifo_isac(cs->hw.teles0.membase, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return (readhscx(cs->hw.teles0.membase, hscx, offset));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	writehscx(cs->hw.teles0.membase, hscx, offset, value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+
+#include "hscx_irq.c"
 
 static irqreturn_t
 telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-#define MAXCOUNT 20
 	struct IsdnCardState *cs = dev_id;
-	u8 val;
+	u_char hval, ival;
+	u_long flags;
 
-	spin_lock(&cs->lock);
-	val = hscx_read(cs, 1, HSCX_ISTA);
-	if (val)
-		hscx_int_main(cs, val);
-	val = isac_read(cs, ISAC_ISTA);
-	if (val)
-		isac_interrupt(cs, val);
+	spin_lock_irqsave(&cs->lock, flags);
+	hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+	if (hval)
+		hscx_int_main(cs, hval);
+	ival = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+	if ((hval | ival) == 0) {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
+	}
+	if (ival)
+		isac_interrupt(cs, ival);
 	/* Clear interrupt register for Zoran PCI controller */
 	writel(0x70000000, cs->hw.teles0.membase + 0x3C);
 
-	hscx_write(cs, 0, HSCX_MASK, 0xFF);
-	hscx_write(cs, 1, HSCX_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0xFF);
-	isac_write(cs, ISAC_MASK, 0x0);
-	hscx_write(cs, 0, HSCX_MASK, 0x0);
-	hscx_write(cs, 1, HSCX_MASK, 0x0);
-	spin_unlock(&cs->lock);
+	writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+	writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+	writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+	writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
+	writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+	writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static struct card_ops telespci_ops = {
-	.init     = inithscxisac,
-	.release  = hisax_release_resources,
-	.irq_func = telespci_interrupt,
-};
-
-static int __init
-telespci_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
+void
+release_io_telespci(struct IsdnCardState *cs)
 {
-	int rc;
-
-	printk(KERN_INFO "TelesPCI: defined at %#lx IRQ %d\n",
-	       pci_resource_start(pdev, 0), pdev->irq);
-	
-	rc = -EBUSY;
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.teles0.membase = request_mmio(&cs->rs, pci_resource_start(pdev, 0), 4096, "telespci");
-	if (!cs->hw.teles0.membase)
-		goto err;
-
-	/* Initialize Zoran PCI controller */
-	writel(0x00000000, cs->hw.teles0.membase + 0x28);
-	writel(0x01000000, cs->hw.teles0.membase + 0x28);
-	writel(0x01000000, cs->hw.teles0.membase + 0x28);
-	writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
-	writel(0x70000000, cs->hw.teles0.membase + 0x3C);
-	writel(0x61000000, cs->hw.teles0.membase + 0x40);
-	/* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
+	iounmap((void *)cs->hw.teles0.membase);
+}
 
-	cs->card_ops = &telespci_ops;
-	if (hscxisac_setup(cs, &isac_ops, &hscx_ops))
-		goto err;
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
+static int
+TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	u_long flags;
+
+	switch (mt) {
+		case CARD_RESET:
+			return(0);
+		case CARD_RELEASE:
+			release_io_telespci(cs);
+			return(0);
+		case CARD_INIT:
+			spin_lock_irqsave(&cs->lock, flags);
+			inithscxisac(cs, 3);
+			spin_unlock_irqrestore(&cs->lock, flags);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
 }
 
 static struct pci_dev *dev_tel __initdata = NULL;
@@ -273,21 +290,70 @@
 int __init
 setup_telespci(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
 	strcpy(tmp, telespci_revision);
-	printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n",
-	       HiSax_getrev(tmp));
-	dev_tel = pci_find_device(PCI_VENDOR_ID_ZORAN, 
-				  PCI_DEVICE_ID_ZORAN_36120, dev_tel);
-	if (dev_tel) {
-		if (telespci_probe(card->cs, dev_tel) < 0)
-			return 0;
-		return 1;
+	printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_TELESPCI)
+		return (0);
+#if CONFIG_PCI
+	if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
+		if (pci_enable_device(dev_tel))
+			return(0);
+		cs->irq = dev_tel->irq;
+		if (!cs->irq) {
+			printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
+			return(0);
+		}
+		cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0),
+			PAGE_SIZE);
+		printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
+			pci_resource_start(dev_tel, 0), dev_tel->irq);
+	} else {
+		printk(KERN_WARNING "TelesPCI: No PCI card found\n");
+		return(0);
+	}
+#else
+	printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
+	printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
+	return (0);
+#endif /* CONFIG_PCI */
+
+	/* Initialize Zoran PCI controller */
+	writel(0x00000000, cs->hw.teles0.membase + 0x28);
+	writel(0x01000000, cs->hw.teles0.membase + 0x28);
+	writel(0x01000000, cs->hw.teles0.membase + 0x28);
+	writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
+	writel(0x70000000, cs->hw.teles0.membase + 0x3C);
+	writel(0x61000000, cs->hw.teles0.membase + 0x40);
+	/* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
+
+	printk(KERN_INFO
+	       "HiSax: %s config irq:%d mem:%lx\n",
+	       CardType[cs->typ], cs->irq,
+	       cs->hw.teles0.membase);
+
+	setup_isac(cs);
+	cs->readisac = &ReadISAC;
+	cs->writeisac = &WriteISAC;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadHSCX;
+	cs->BC_Write_Reg = &WriteHSCX;
+	cs->BC_Send_Data = &hscx_fill_fifo;
+	cs->cardmsg = &TelesPCI_card_msg;
+	cs->irq_func = &telespci_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ISACVersion(cs, "TelesPCI:");
+	if (HscxVersion(cs, "TelesPCI:")) {
+		printk(KERN_WARNING
+		 "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
+		release_io_telespci(cs);
+		return (0);
 	}
-	printk(KERN_WARNING "TelesPCI: No PCI card found\n");
-	return 0;
+	return (1);
 }
--- diff/drivers/isdn/hisax/w6692.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/w6692.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.12.6.6 2001/09/23 22:24:52 kai Exp $
+/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $
  *
  * Winbond W6692 specific routines
  *
@@ -41,60 +41,10 @@
 
 extern const char *CardType[];
 
-const char *w6692_revision = "$Revision: 1.12.6.6 $";
+const char *w6692_revision = "$Revision: 1.18.2.4 $";
 
 #define DBUSY_TIMER_VALUE 80
 
-static inline u8
-w6692_read_reg(struct IsdnCardState *cs, u8 offset)
-{
-	return (inb(cs->hw.w6692.iobase + offset));
-}
-
-static inline void
-w6692_write_reg(struct IsdnCardState *cs, u8 offset, u8 value)
-{
-	outb(value, cs->hw.w6692.iobase + offset);
-}
-
-static void
-w6692_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
-{
-	insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size);
-}
-
-static inline void
-w6692_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
-{
-	outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size);
-}
-
-static struct dc_hw_ops w6692_dc_hw_ops = {
-	.read_fifo = w6692_read_fifo,
-};
-
-static inline u8
-w6692_bc_read_reg(struct IsdnCardState *cs, int bchan, u8 offset)
-{
-	return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset));
-}
-
-static inline void
-w6692_bc_write_reg(struct IsdnCardState *cs, int bchan, u8 offset, u8 value)
-{
-	outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset);
-}
-
-static void
-w6692_bc_read_fifo(struct IsdnCardState *cs, int bchan, u8 *data, int len)
-{
-	insb(cs->hw.w6692.iobase + W_B_RFIFO + (bchan ? 0x40:0), data, len);
-}
-
-static struct bc_hw_ops w6692_bc_hw_ops = {
-	.read_fifo  = w6692_bc_read_fifo,
-};
-
 static char *W6692Ver[] __initdata =
 {"W6692 V00", "W6692 V01", "W6692 V10",
  "W6692 V11"};
@@ -104,7 +54,7 @@
 {
 	int val;
 
-	val = w6692_read_reg(cs, W_D_RBCH);
+	val = cs->readW6692(cs, W_D_RBCH);
 	printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);
 }
 
@@ -113,7 +63,7 @@
 {
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "ph_command %x", command);
-	w6692_write_reg(cs, W_CIX, command);
+	cs->writeisac(cs, W_CIX, command);
 }
 
 
@@ -152,9 +102,8 @@
 }
 
 static void
-W6692_bh(void *data)
+W6692_bh(struct IsdnCardState *cs)
 {
-	struct IsdnCardState *cs = data;
 	struct PStack *stptr;
 
 	if (!cs)
@@ -164,7 +113,7 @@
 			debugl1(cs, "D-Channel Busy cleared");
 		stptr = cs->stlist;
 		while (stptr != NULL) {
-			L1L2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
 			stptr = stptr->next;
 		}
 	}
@@ -185,22 +134,58 @@
 static void
 W6692_empty_fifo(struct IsdnCardState *cs, int count)
 {
-	recv_empty_fifo_d(cs, count);
-	w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RACK);
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "W6692_empty_fifo");
+
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "W6692_empty_fifo overrun %d",
+				cs->rcvidx + count);
+		cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
+		cs->rcvidx = 0;
+		return;
+	}
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+	cs->readW6692fifo(cs, ptr, count);
+	cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "W6692_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 static void
 W6692_fill_fifo(struct IsdnCardState *cs)
 {
 	int count, more;
-	unsigned char *p;
+	u_char *ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "W6692_fill_fifo");
 
-	p = xmit_fill_fifo_d(cs, W_D_FIFO_THRESH, &count, &more);
-	if (!p)
+	if (!cs->tx_skb)
 		return;
 
-	w6692_write_fifo(cs, p, count);
-	w6692_write_reg(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
+	count = cs->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > W_D_FIFO_THRESH) {
+		more = !0;
+		count = W_D_FIFO_THRESH;
+	}
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeW6692fifo(cs, ptr, count);
+	cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
 	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 		debugl1(cs, "W6692_fill_fifo dbusytimer running");
 		del_timer(&cs->dbusytimer);
@@ -208,13 +193,43 @@
 	init_timer(&cs->dbusytimer);
 	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
 	add_timer(&cs->dbusytimer);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "W6692_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
 }
 
 static void
 W6692B_empty_fifo(struct BCState *bcs, int count)
 {
-	recv_empty_fifo_b(bcs, count);
-	w6692_bc_write_reg(bcs->cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+	u_char *ptr;
+	struct IsdnCardState *cs = bcs->cs;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "W6692B_empty_fifo");
+
+	if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
+		cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+		bcs->hw.w6692.rcvidx = 0;
+		return;
+	}
+	ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;
+	bcs->hw.w6692.rcvidx += count;
+	READW6692BFIFO(cs, bcs->channel, ptr, count);
+	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
+			     bcs->channel + '1', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static void
@@ -222,33 +237,50 @@
 {
 	struct IsdnCardState *cs = bcs->cs;
 	int more, count;
-	unsigned char *p;
+	u_char *ptr;
 
-	p = xmit_fill_fifo_b(bcs, W_B_FIFO_THRESH, &count, &more);
-	if (!p)
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
 		return;
 
-	WRITEW6692BFIFO(cs, bcs->channel, p, count);
-	w6692_bc_write_reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
-}
-
-static void
-reset_xmit(struct BCState *bcs)
-{
-	w6692_bc_write_reg(bcs->cs, bcs->channel, W_B_CMDR,
-			   W_B_CMDR_XRST | W_B_CMDR_RACT);
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > W_B_FIFO_THRESH) {
+		more = 1;
+		count = W_B_FIFO_THRESH;
+	} else
+		count = bcs->tx_skb->len;
+
+	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+		debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " ": " last "), count);
+
+	ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.w6692.count += count;
+	WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
+	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
+	if (cs->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
+			     bcs->channel + '1', count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
 }
 
 static void
-W6692B_interrupt(struct IsdnCardState *cs, u8 bchan)
+W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
 {
-	u8 val;
-	u8 r;
+	u_char val;
+	u_char r;
 	struct BCState *bcs;
+	struct sk_buff *skb;
 	int count;
 
 	bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1);
-	val = w6692_bc_read_reg(cs, bchan, W_B_EXIR);
+	val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
 	debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
 
 	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) {
@@ -256,8 +288,10 @@
 		return;
 	}
 	if (val & W_B_EXI_RME) {	/* RME */
-		r = w6692_bc_read_reg(cs, bchan, W_B_STAR);
-		if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB | W_B_STAR_XDOW)) {
+		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
+		if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "W6692 B STAR %x", r);
 			if ((r & W_B_STAR_RDOV) && bcs->mode)
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "W6692 B RDOV mode=%d",
@@ -265,46 +299,129 @@
 			if (r & W_B_STAR_CRCE)
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "W6692 B CRC error");
-			w6692_bc_write_reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
-			bcs->rcvidx = 0;
+			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
 		} else {
-			count = w6692_bc_read_reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
+			count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
 			if (count == 0)
 				count = W_B_FIFO_THRESH;
 			W6692B_empty_fifo(bcs, count);
-			recv_rme_b(bcs);
+			if ((count = bcs->hw.w6692.rcvidx) > 0) {
+				if (cs->debug & L1_DEB_HSCX_FIFO)
+					debugl1(cs, "W6692 Bchan Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "W6692: Bchan receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
 		}
+		bcs->hw.w6692.rcvidx = 0;
+		schedule_event(bcs, B_RCVBUFREADY);
 	}
 	if (val & W_B_EXI_RMR) {	/* RMR */
 		W6692B_empty_fifo(bcs, W_B_FIFO_THRESH);
-		recv_rpf_b(bcs);
-	}
-	if (val & W_B_EXI_XFR) {	/* XFR */
-		xmit_xpr_b(bcs);
+		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
+		if (r & W_B_STAR_RDOV) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "W6692 B RDOV(RMR) mode=%d",bcs->mode);
+			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
+			if (bcs->mode != L1_MODE_TRANS)
+				bcs->hw.w6692.rcvidx = 0;
+		}
+		if (bcs->mode == L1_MODE_TRANS) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH)))
+				printk(KERN_WARNING "HiSax: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.w6692.rcvidx = 0;
+			schedule_event(bcs, B_RCVBUFREADY);
+		}
 	}
 	if (val & W_B_EXI_XDUN) {	/* XDUN */
-		xmit_xdu_b(bcs, reset_xmit);
+		cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "W6692 B EXIR %x Lost TX", val);
+		if (bcs->mode == 1)
+			W6692B_fill_fifo(bcs);
+		else {
+			/* Here we lost an TX interrupt, so
+			   * restart transmitting the whole frame.
+			 */
+			if (bcs->tx_skb) {
+				skb_push(bcs->tx_skb, bcs->hw.w6692.count);
+				bcs->tx_cnt += bcs->hw.w6692.count;
+				bcs->hw.w6692.count = 0;
+			}
+		}
+		return;
+	}
+	if (val & W_B_EXI_XFR) {	/* XFR */
+		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
+		if (r & W_B_STAR_XDOW) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "W6692 B STAR %x XDOW", r);
+			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+			if (bcs->tx_skb && (bcs->mode != 1)) {
+				skb_push(bcs->tx_skb, bcs->hw.w6692.count);
+				bcs->tx_cnt += bcs->hw.w6692.count;
+				bcs->hw.w6692.count = 0;
+			}
+		}
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+				W6692B_fill_fifo(bcs);
+				return;
+			} else {
+				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
+					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
+					u_long	flags;
+					spin_lock_irqsave(&bcs->aclock, flags);
+					bcs->ackcnt += bcs->hw.w6692.count;
+					spin_unlock_irqrestore(&bcs->aclock, flags);
+					schedule_event(bcs, B_ACKPENDING);
+				}
+				dev_kfree_skb_irq(bcs->tx_skb);
+				bcs->hw.w6692.count = 0;
+				bcs->tx_skb = NULL;
+			}
+		}
+		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+			bcs->hw.w6692.count = 0;
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			W6692B_fill_fifo(bcs);
+		} else {
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			schedule_event(bcs, B_XMTBUFREADY);
+		}
 	}
 }
 
 static irqreturn_t
-w6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-	struct IsdnCardState *cs = dev_id;
-	u8 val, exval, v1;
-	unsigned int count;
-	int icnt = 5;
-
-	spin_lock(&cs->lock);
-
-	val = w6692_read_reg(cs, W_ISTA);
-
+	struct IsdnCardState	*cs = dev_id;
+	u_char			val, exval, v1;
+	struct sk_buff		*skb;
+	u_int			count;
+	u_long			flags;
+	int			icnt = 5;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	val = cs->readW6692(cs, W_ISTA);
+	if (!val) {
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return IRQ_NONE;
+	}
       StartW6692:
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "W6692 ISTA %x", val);
 
 	if (val & W_INT_D_RME) {	/* RME */
-		exval = w6692_read_reg(cs, W_D_RSTA);
+		exval = cs->readW6692(cs, W_D_RSTA);
 		if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
 			if (exval & W_D_RSTA_RDOV)
 				if (cs->debug & L1_DEB_WARN)
@@ -315,58 +432,100 @@
 			if (exval & W_D_RSTA_RMB)
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "W6692 D-channel ABORT");
-			w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
-			cs->rcvidx = 0;
+			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
 		} else {
-			count = w6692_read_reg(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
+			count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
 			if (count == 0)
 				count = W_D_FIFO_THRESH;
 			W6692_empty_fifo(cs, count);
-			recv_rme_d(cs);
+			if ((count = cs->rcvidx) > 0) {
+				cs->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "HiSax: D receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
 		}
+		cs->rcvidx = 0;
+		schedule_event(cs, D_RCVBUFREADY);
 	}
 	if (val & W_INT_D_RMR) {	/* RMR */
 		W6692_empty_fifo(cs, W_D_FIFO_THRESH);
 	}
 	if (val & W_INT_D_XFR) {	/* XFR */
-		xmit_xpr_d(cs);
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			schedule_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len) {
+				W6692_fill_fifo(cs);
+				goto afterXFR;
+			} else {
+				dev_kfree_skb_irq(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			}
+		}
+		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+			cs->tx_cnt = 0;
+			W6692_fill_fifo(cs);
+		} else
+			schedule_event(cs, D_XMTBUFREADY);
 	}
+      afterXFR:
 	if (val & (W_INT_XINT0 | W_INT_XINT1)) {	/* XINT0/1 - never */
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "W6692 spurious XINT!");
 	}
 	if (val & W_INT_D_EXI) {	/* EXI */
-		exval = w6692_read_reg(cs, W_D_EXIR);
+		exval = cs->readW6692(cs, W_D_EXIR);
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "W6692 D_EXIR %02x", exval);
 		if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {	/* Transmit underrun/collision */
-			xmit_xdu_d(cs, NULL);
+			debugl1(cs, "W6692 D-chan underrun/collision");
+			printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n");
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				schedule_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) {	/* Restart frame */
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+				W6692_fill_fifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n");
+				debugl1(cs, "W6692 XDUN/XCOL no skb");
+				cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);
+			}
 		}
 		if (exval & W_D_EXI_RDOV) {	/* RDOV */
 			debugl1(cs, "W6692 D-channel RDOV");
 			printk(KERN_WARNING "HiSax: W6692 D-RDOV\n");
-			w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RRST);
+			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST);
 		}
 		if (exval & W_D_EXI_TIN2) {	/* TIN2 - never */
 			debugl1(cs, "W6692 spurious TIN2 interrupt");
 		}
 		if (exval & W_D_EXI_MOC) {	/* MOC - not supported */
 			debugl1(cs, "W6692 spurious MOC interrupt");
-			v1 = w6692_read_reg(cs, W_MOSR);
+			v1 = cs->readW6692(cs, W_MOSR);
 			debugl1(cs, "W6692 MOSR %02x", v1);
 		}
 		if (exval & W_D_EXI_ISC) {	/* ISC - Level1 change */
-			v1 = w6692_read_reg(cs, W_CIR);
+			v1 = cs->readW6692(cs, W_CIR);
 			if (cs->debug & L1_DEB_ISAC)
 				debugl1(cs, "W6692 ISC CIR=0x%02X", v1);
 			if (v1 & W_CIR_ICC) {
 				cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK;
 				if (cs->debug & L1_DEB_ISAC)
 					debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state);
-				sched_d_event(cs, D_L1STATECHANGE);
+				schedule_event(cs, D_L1STATECHANGE);
 			}
 			if (v1 & W_CIR_SCC) {
-				v1 = w6692_read_reg(cs, W_SQR);
+				v1 = cs->readW6692(cs, W_SQR);
 				debugl1(cs, "W6692 SCC SQR=0x%02X", v1);
 			}
 		}
@@ -385,16 +544,16 @@
 		debugl1(cs, "W6692 B channel 2 interrupt");
 		W6692B_interrupt(cs, 1);
 	}
-	val = w6692_read_reg(cs, W_ISTA);
+	val = cs->readW6692(cs, W_ISTA);
 	if (val && icnt) {
 		icnt--;
 		goto StartW6692;
 	}
 	if (!icnt) {
 		printk(KERN_WARNING "W6692 IRQ LOOP\n");
-		w6692_write_reg(cs, W_IMASK, 0xff);
+		cs->writeW6692(cs, W_IMASK, 0xff);
 	}
-	spin_unlock(&cs->lock);
+	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -403,32 +562,87 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	u_long flags;
 	int val;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_d(cs, skb);
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				W6692_fill_fifo(cs);
+			}
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
-		case (PH_PULL |INDICATION):
-			xmit_pull_ind_d(cs, skb);
+		case (PH_PULL | INDICATION):
+			spin_lock_irqsave(&cs->lock, flags);
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				spin_unlock_irqrestore(&cs->lock, flags);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			W6692_fill_fifo(cs);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_d(st);
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (HW_RESET | REQUEST):
-			if ((cs->dc.w6692.ph_state == W_L1IND_DRD))
+			spin_lock_irqsave(&cs->lock, flags);
+			if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) {
 				ph_command(cs, W_L1CMD_ECK);
-			else {
+				spin_unlock_irqrestore(&cs->lock, flags);
+			} else {
 				ph_command(cs, W_L1CMD_RST);
 				cs->dc.w6692.ph_state = W_L1CMD_RST;
+				spin_unlock_irqrestore(&cs->lock, flags);
 				W6692_new_ph(cs);
 			}
 			break;
 		case (HW_ENABLE | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, W_L1CMD_ECK);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_INFO3 | REQUEST):
+			spin_lock_irqsave(&cs->lock, flags);
 			ph_command(cs, W_L1CMD_AR8);
+			spin_unlock_irqrestore(&cs->lock, flags);
 			break;
 		case (HW_TESTLOOP | REQUEST):
 			val = 0;
@@ -448,7 +662,7 @@
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-				sched_d_event(cs, D_CLEARBUSY);
+				schedule_event(cs, D_CLEARBUSY);
 			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
@@ -457,11 +671,15 @@
 	}
 }
 
-static int
+static void
 setstack_W6692(struct PStack *st, struct IsdnCardState *cs)
 {
 	st->l1.l1hw = W6692_l1hw;
-	return 0;
+}
+
+static void
+DC_Close_W6692(struct IsdnCardState *cs)
+{
 }
 
 static void
@@ -469,10 +687,12 @@
 {
 	struct PStack *stptr;
 	int rbch, star;
+	u_long flags;
 
+	spin_lock_irqsave(&cs->lock, flags);
 	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
-		rbch = w6692_read_reg(cs, W_D_RBCH);
-		star = w6692_read_reg(cs, W_D_STAR);
+		rbch = cs->readW6692(cs, W_D_RBCH);
+		star = cs->readW6692(cs, W_D_STAR);
 		if (cs->debug)
 			debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x",
 				rbch, star);
@@ -480,7 +700,7 @@
 			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 			stptr = cs->stlist;
 			while (stptr != NULL) {
-				L1L2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 				stptr = stptr->next;
 			}
 		} else {
@@ -494,10 +714,13 @@
 				printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n");
 				debugl1(cs, "D-Channel Busy no skb");
 			}
-			w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_XRST);	/* Transmitter reset */
-			cs->card_ops->irq_func(cs->irq, cs, NULL); /* FIXME? */
+			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);	/* Transmitter reset */
+			spin_unlock_irqrestore(&cs->lock, flags);
+			cs->irq_func(cs->irq, cs, NULL);
+			return;
 		}
 	}
+	spin_unlock_irqrestore(&cs->lock, flags);
 }
 
 static void
@@ -514,51 +737,79 @@
 
 	switch (mode) {
 		case (L1_MODE_NULL):
-			w6692_bc_write_reg(cs, bchan, W_B_MODE, 0);
+			cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0);
 			break;
 		case (L1_MODE_TRANS):
-			w6692_bc_write_reg(cs, bchan, W_B_MODE, W_B_MODE_MMS);
+			cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS);
 			break;
 		case (L1_MODE_HDLC):
-			w6692_bc_write_reg(cs, bchan, W_B_MODE, W_B_MODE_ITF);
-			w6692_bc_write_reg(cs, bchan, W_B_ADM1, 0xff);
-			w6692_bc_write_reg(cs, bchan, W_B_ADM2, 0xff);
+			cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF);
+			cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff);
+			cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff);
 			break;
 	}
 	if (mode)
-		w6692_bc_write_reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST |
+		cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST |
 				 W_B_CMDR_RACT | W_B_CMDR_XRST);
-	w6692_bc_write_reg(cs, bchan, W_B_EXIM, 0x00);
+	cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00);
 }
 
 static void
 W6692_l2l1(struct PStack *st, int pr, void *arg)
 {
 	struct sk_buff *skb = arg;
+	struct BCState *bcs = st->l1.bcs; 
+	u_long flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
-			xmit_data_req_b(st->l1.bcs, skb);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			if (bcs->tx_skb) {
+				skb_queue_tail(&bcs->squeue, skb);
+			} else {
+				bcs->tx_skb = skb;
+				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+				bcs->hw.w6692.count = 0;
+				bcs->cs->BC_Send_Data(bcs);
+			}
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | INDICATION):
-			xmit_pull_ind_b(st->l1.bcs, skb);
+			if (bcs->tx_skb) {
+				printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n");
+				break;
+			}
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+			bcs->tx_skb = skb;
+			bcs->hw.w6692.count = 0;
+			bcs->cs->BC_Send_Data(bcs);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			break;
 		case (PH_PULL | REQUEST):
-			xmit_pull_req_b(st);
+			if (!bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 			break;
 		case (PH_ACTIVATE | REQUEST):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			W6692Bmode(st->l1.bcs, st->l1.mode, st->l1.bc);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
+			W6692Bmode(bcs, st->l1.mode, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			W6692Bmode(st->l1.bcs, 0, st->l1.bc);
-			L1L2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			spin_lock_irqsave(&bcs->cs->lock, flags);
+			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+			W6692Bmode(bcs, 0, st->l1.bc);
+			spin_unlock_irqrestore(&bcs->cs->lock, flags);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 			break;
 	}
 }
@@ -567,13 +818,52 @@
 close_w6692state(struct BCState *bcs)
 {
 	W6692Bmode(bcs, 0, bcs->channel);
-	bc_close(bcs);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.w6692.rcvbuf) {
+			kfree(bcs->hw.w6692.rcvbuf);
+			bcs->hw.w6692.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
 }
 
 static int
 open_w6692state(struct IsdnCardState *cs, struct BCState *bcs)
 {
-	return bc_open(bcs);
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+			       "HiSax: No memory for w6692.rcvbuf\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+			       "HiSax: No memory for bcs->blog\n");
+			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.w6692.rcvbuf);
+			bcs->hw.w6692.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.w6692.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
 }
 
 static int
@@ -583,166 +873,224 @@
 	if (open_w6692state(st->l1.hardware, bcs))
 		return (-1);
 	st->l1.bcs = bcs;
-	st->l1.l2l1 = W6692_l2l1;
+	st->l2.l2l1 = W6692_l2l1;
 	setstack_manager(st);
 	bcs->st = st;
 	setstack_l1_B(st);
 	return (0);
 }
 
-static int
-w6692_reset(struct IsdnCardState *cs)
+void resetW6692(struct IsdnCardState *cs)
 {
-	w6692_write_reg(cs, W_D_CTL, W_D_CTL_SRST);
-	schedule_timeout((10*HZ)/1000);
-	w6692_write_reg(cs, W_D_CTL, 0x00);
-	schedule_timeout((10*HZ)/1000);
-	w6692_write_reg(cs, W_IMASK, 0xff);
-	w6692_write_reg(cs, W_D_SAM, 0xff);
-	w6692_write_reg(cs, W_D_TAM, 0xff);
-	w6692_write_reg(cs, W_D_EXIM, 0x00);
-	w6692_write_reg(cs, W_D_MODE, W_D_MODE_RACT);
-	w6692_write_reg(cs, W_IMASK, 0x18);
+	cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
+	mdelay(10);
+	cs->writeW6692(cs, W_D_CTL, 0x00);
+	mdelay(10);
+	cs->writeW6692(cs, W_IMASK, 0xff);
+	cs->writeW6692(cs, W_D_SAM, 0xff);
+	cs->writeW6692(cs, W_D_TAM, 0xff);
+	cs->writeW6692(cs, W_D_EXIM, 0x00);
+	cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
+	cs->writeW6692(cs, W_IMASK, 0x18);
 	if (cs->subtyp == W6692_USR) {
 		/* seems that USR implemented some power control features
 		 * Pin 79 is connected to the oscilator circuit so we
 		 * have to handle it here
 		 */
-		w6692_write_reg(cs, W_PCTL, 0x80);
-		w6692_write_reg(cs, W_XDATA, 0x00);
+		cs->writeW6692(cs, W_PCTL, 0x80);
+		cs->writeW6692(cs, W_XDATA, 0x00);
 	}
-	return 0;
 }
 
-static void
-w6692_init(struct IsdnCardState *cs)
+void __init initW6692(struct IsdnCardState *cs, int part)
 {
-	w6692_reset(cs);
-	ph_command(cs, W_L1CMD_RST);
-	cs->dc.w6692.ph_state = W_L1CMD_RST;
-	W6692_new_ph(cs);
-	ph_command(cs, W_L1CMD_ECK);
-	
-	W6692Bmode(cs->bcs, 0, 0);
-	W6692Bmode(cs->bcs + 1, 0, 0);
+	if (part & 1) {
+		cs->setstack_d = setstack_W6692;
+		cs->DC_Close = DC_Close_W6692;
+		cs->dbusytimer.function = (void *) dbusy_timer_handler;
+		cs->dbusytimer.data = (long) cs;
+		init_timer(&cs->dbusytimer);
+		resetW6692(cs);
+		ph_command(cs, W_L1CMD_RST);
+		cs->dc.w6692.ph_state = W_L1CMD_RST;
+		W6692_new_ph(cs);
+		ph_command(cs, W_L1CMD_ECK);
 
-	/* Reenable all IRQ */
-	w6692_write_reg(cs, W_IMASK, 0x18);
-	w6692_write_reg(cs, W_D_EXIM, 0x00);
-	w6692_bc_write_reg(cs, 0, W_B_EXIM, 0x00);
-	w6692_bc_write_reg(cs, 1, W_B_EXIM, 0x00);
-	/* Reset D-chan receiver and transmitter */
-	w6692_write_reg(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
+		cs->bcs[0].BC_SetStack = setstack_w6692;
+		cs->bcs[1].BC_SetStack = setstack_w6692;
+		cs->bcs[0].BC_Close = close_w6692state;
+		cs->bcs[1].BC_Close = close_w6692state;
+		W6692Bmode(cs->bcs, 0, 0);
+		W6692Bmode(cs->bcs + 1, 0, 0);
+	}
+	if (part & 2) {
+		/* Reenable all IRQ */
+		cs->writeW6692(cs, W_IMASK, 0x18);
+		cs->writeW6692(cs, W_D_EXIM, 0x00);
+		cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00);
+		cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00);
+		/* Reset D-chan receiver and transmitter */
+		cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
+	}
 }
 
+/* Interface functions */
 
-static void
-w6692_release(struct IsdnCardState *cs)
+static u_char
+ReadW6692(struct IsdnCardState *cs, u_char offset)
 {
-	w6692_write_reg(cs, W_IMASK, 0xff);
-	if (cs->subtyp == W6692_USR)
-		w6692_write_reg(cs, W_XDATA, 0x04);
-	hisax_release_resources(cs);
+	return (inb(cs->hw.w6692.iobase + offset));
 }
 
-static struct card_ops w6692_ops = {
-	.init     = w6692_init,
-	.reset    = w6692_reset,
-	.release  = w6692_release,
-	.irq_func = w6692_interrupt,
-};
-
-static struct dc_l1_ops w6692_dc_l1_ops = {
-	.fill_fifo  = W6692_fill_fifo,
-	.open       = setstack_W6692,
-	.bh_func    = W6692_bh,
-	.dbusy_func = dbusy_timer_handler,
-};
-
-static struct bc_l1_ops w6692_bc_l1_ops = {
-	.fill_fifo = W6692B_fill_fifo,
-	.open      = setstack_w6692,
-	.close     = close_w6692state,
-};
+static void
+WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	outb(value, cs->hw.w6692.iobase + offset);
+}
 
-static int id_idx ;
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size);
+}
 
-static struct pci_dev *dev_w6692 __initdata = NULL;
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+	outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size);
+}
 
-static int
-w6692_hw_init(struct IsdnCardState *cs)
+static u_char
+ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset)
 {
-	cs->card_ops = &w6692_ops;
-	cs->dc_hw_ops = &w6692_dc_hw_ops, 
-	cs->bc_hw_ops = &w6692_bc_hw_ops;
-	dc_l1_init(cs, &w6692_dc_l1_ops);
-	cs->bc_l1_ops = &w6692_bc_l1_ops;
-	W6692Version(cs, "W6692:");
-	printk(KERN_INFO "W6692 ISTA=0x%X\n", w6692_read_reg(cs, W_ISTA));
-	printk(KERN_INFO "W6692 IMASK=0x%X\n", w6692_read_reg(cs, W_IMASK));
-	printk(KERN_INFO "W6692 D_EXIR=0x%X\n", w6692_read_reg(cs, W_D_EXIR));
-	printk(KERN_INFO "W6692 D_EXIM=0x%X\n", w6692_read_reg(cs, W_D_EXIM));
-	printk(KERN_INFO "W6692 D_RSTA=0x%X\n", w6692_read_reg(cs, W_D_RSTA));
-	return 0;
+	return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset));
 }
 
-static int __init
-w6692_probe(struct IsdnCardState *cs, struct pci_dev *pdev)
+static void
+WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value)
 {
-	int rc;
+	outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset);
+}
 
-	printk(KERN_INFO "W6692: %s %s at %#lx IRQ %d\n",
-	       id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
-	       pci_resource_start(pdev, 1), pdev->irq);
-	
-	rc = -EBUSY;
-	if (pci_enable_device(pdev))
-		goto err;
-			
-	/* USR ISDN PCI card TA need some special handling */
-	if (cs->subtyp == W6692_WINBOND) {
-		if (pdev->subsystem_vendor == W6692_SV_USR  &&
-		    pdev->subsystem_device == W6692_SD_USR) {
-			cs->subtyp = W6692_USR;
-		}
+static int
+w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	switch (mt) {
+		case CARD_RESET:
+			resetW6692(cs);
+			return (0);
+		case CARD_RELEASE:
+			cs->writeW6692(cs, W_IMASK, 0xff);
+			release_region(cs->hw.w6692.iobase, 256);
+			if (cs->subtyp == W6692_USR) {
+				cs->writeW6692(cs, W_XDATA, 0x04);
+			}
+			return (0);
+		case CARD_INIT:
+			initW6692(cs, 3);
+			return (0);
+		case CARD_TEST:
+			return (0);
 	}
-	cs->irq = pdev->irq;
-	cs->irq_flags |= SA_SHIRQ;
-	cs->hw.w6692.iobase = pci_resource_start(pdev, 1);
-	
-	if (!request_io(&cs->rs, cs->hw.w6692.iobase, 0x100,
-			id_list[cs->subtyp].card_name))
-		goto err;
-
-	w6692_hw_init(cs);
-	return 0;
- err:
-	hisax_release_resources(cs);
-	return rc;
+	return (0);
 }
 
+static int id_idx ;
+
+static struct pci_dev *dev_w6692 __initdata = NULL;
+
 int __init 
 setup_w6692(struct IsdnCard *card)
 {
+	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
+	u_char found = 0;
+	u_char pci_irq = 0;
+	u_int pci_ioaddr = 0;
 
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
 	strcpy(tmp, w6692_revision);
 	printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_W6692)
+		return (0);
+#if CONFIG_PCI
 	while (id_list[id_idx].vendor_id) {
 		dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
 					    id_list[id_idx].device_id,
 					    dev_w6692);
 		if (dev_w6692) {
-			card->cs->subtyp = id_idx;
-			if (w6692_probe(card->cs, dev_w6692) < 0)
-				return 0;
-			return 1;
+			if (pci_enable_device(dev_w6692))
+				continue;
+			cs->subtyp = id_idx;
+			break;
 		}
 		id_idx++;
 	}
-	printk(KERN_WARNING "W6692: No PCI card found\n");
-	return 0;
+	if (dev_w6692) {
+		found = 1;
+		pci_irq = dev_w6692->irq;
+		/* I think address 0 is allways the configuration area */
+		/* and address 1 is the real IO space KKe 03.09.99 */
+		pci_ioaddr = pci_resource_start(dev_w6692, 1);
+		/* USR ISDN PCI card TA need some special handling */
+		if (cs->subtyp == W6692_WINBOND) {
+			if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
+			    (W6692_SD_USR == dev_w6692->subsystem_device)) {
+				cs->subtyp = W6692_USR;
+			}
+		}
+	}
+	if (!found) {
+		printk(KERN_WARNING "W6692: No PCI card found\n");
+		return (0);
+	}
+	cs->irq = pci_irq;
+	if (!cs->irq) {
+		printk(KERN_WARNING "W6692: No IRQ for PCI card found\n");
+		return (0);
+	}
+	if (!pci_ioaddr) {
+		printk(KERN_WARNING "W6692: NO I/O Base Address found\n");
+		return (0);
+	}
+	cs->hw.w6692.iobase = pci_ioaddr;
+	printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
+	       id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
+	       pci_ioaddr, pci_irq);
+	if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) {
+		printk(KERN_WARNING
+		       "HiSax: %s I/O ports %x-%x already in use\n",
+		       id_list[cs->subtyp].card_name,
+		       cs->hw.w6692.iobase,
+		       cs->hw.w6692.iobase + 255);
+		return (0);
+	}
+#else
+	printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
+	printk(KERN_WARNING "HiSax: W6692 unable to config\n");
+	return (0);
+#endif				/* CONFIG_PCI */
+
+	printk(KERN_INFO
+	       "HiSax: %s config irq:%d I/O:%x\n",
+	       id_list[cs->subtyp].card_name, cs->irq,
+	       cs->hw.w6692.iobase);
+
+	INIT_WORK(&cs->tqueue, (void *)(void *) W6692_bh, cs);
+	cs->readW6692 = &ReadW6692;
+	cs->writeW6692 = &WriteW6692;
+	cs->readisacfifo = &ReadISACfifo;
+	cs->writeisacfifo = &WriteISACfifo;
+	cs->BC_Read_Reg = &ReadW6692B;
+	cs->BC_Write_Reg = &WriteW6692B;
+	cs->BC_Send_Data = &W6692B_fill_fifo;
+	cs->cardmsg = &w6692_card_msg;
+	cs->irq_func = &W6692_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	W6692Version(cs, "W6692:");
+	printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
+	printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
+	printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR));
+	printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM));
+	printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA));
+	return (1);
 }
--- diff/drivers/isdn/hisax/w6692.h	2003-01-16 11:30:36.000000000 +0000
+++ source/drivers/isdn/hisax/w6692.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: w6692.h,v 1.2.6.2 2001/09/23 22:24:52 kai Exp $
+/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $
  *
  * Winbond W6692 specific defines
  *
@@ -18,6 +18,9 @@
 
 /* B-channel FIFO read/write routines */
 
+#define READW6692BFIFO(cs,bchan,ptr,count) \
+	insb(cs->hw.w6692.iobase+W_B_RFIFO+(bchan?0x40:0),ptr,count)
+
 #define WRITEW6692BFIFO(cs,bchan,ptr,count) \
 	outsb(cs->hw.w6692.iobase+W_B_XFIFO+(bchan?0x40:0),ptr,count)
 
--- diff/drivers/isdn/hysdn/Kconfig	2003-02-13 11:46:52.000000000 +0000
+++ source/drivers/isdn/hysdn/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config HYSDN
 	tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)"
-	depends on m && PROC_FS
+	depends on m && PROC_FS && BROKEN_ON_SMP
 	help
 	  Say Y here if you have one of Hypercope's active PCI ISDN cards
 	  Champ, Ergo and Metro. You will then get a module called hysdn.
--- diff/drivers/isdn/hysdn/hysdn_proclog.c	2003-06-30 10:07:33.000000000 +0100
+++ source/drivers/isdn/hysdn/hysdn_proclog.c	2004-02-18 09:03:59.000000000 +0000
@@ -233,7 +233,7 @@
 		return (0);
 
 	inf->usage_cnt--;	/* new usage count */
-	(struct log_data **) file->private_data = &inf->next;	/* next structure */
+	file->private_data = &inf->next;	/* next structure */
 	if ((len = strlen(inf->log_start)) <= count) {
 		if (copy_to_user(buf, inf->log_start, len))
 			return -EFAULT;
@@ -276,9 +276,9 @@
 		cli();
 		pd->if_used++;
 		if (pd->log_head)
-			(struct log_data **) filep->private_data = &(pd->log_tail->next);
+			filep->private_data = &pd->log_tail->next;
 		else
-			(struct log_data **) filep->private_data = &(pd->log_head);
+			filep->private_data = &pd->log_head;
 		restore_flags(flags);
 	} else {		/* simultaneous read/write access forbidden ! */
 		unlock_kernel();
--- diff/drivers/isdn/i4l/Kconfig	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -2,25 +2,6 @@
 # Old ISDN4Linux config
 #
 
-config ISDN_NET_SIMPLE
-	bool '  Support raw-IP and other simple protocols'
-	depends on INET
-	help
-	  This options enables 'raw IP over ISDN', 'ethernet over ISDN',
-	  'raw IP with UI header' and 'IP + type field' encapsulations.
-	  
-	  If you never heard of any of those, you probably want to say N.
-
-config ISDN_NET_CISCO
-	bool '  Support CISCO router protocols'
-	depends on INET
-	help
-	  This options enables 'CISCO HDLC' encapsulation with
-	  optional support for CISCO keep-alive frames.
-	  
-	  Unless you want to connect to a Cisco Router in HDLC mode,
-	  you probably want to say N.
-
 config ISDN_PPP
 	bool "Support synchronous PPP"
 	depends on INET
@@ -85,7 +66,7 @@
 
 config ISDN_X25
 	bool "X.25 PLP on top of ISDN"
-	depends on X25 && BROKEN
+	depends on X25
 	help
 	  This feature provides the X.25 protocol over ISDN connections.
 	  See <file:Documentation/isdn/README.x25> for more information
@@ -97,6 +78,7 @@
 
 config ISDN_DRV_LOOP
 	tristate "isdnloop support"
+	depends on BROKEN_ON_SMP
 	help
 	  This driver provides a virtual ISDN card. Its primary purpose is
 	  testing of linklevel features or configuration without getting
@@ -106,7 +88,7 @@
 
 config ISDN_DIVERSION
 	tristate "Support isdn diversion services"
-	depends on BROKEN
+	depends on BROKEN && BROKEN_ON_SMP
 	help
 	  This option allows you to use some supplementary diversion
 	  services in conjunction with the HiSax driver on an EURO/DSS1
@@ -124,3 +106,27 @@
 	  Please read the file <file:Documentation/isdn/README.diversion>.
 
 endmenu
+
+comment "ISDN4Linux hardware drivers"
+	depends on NET && ISDN && ISDN_I4L
+
+source "drivers/isdn/hisax/Kconfig"
+
+
+menu "Active cards"
+	depends on NET && ISDN && ISDN_I4L!=n
+
+source "drivers/isdn/icn/Kconfig"
+
+source "drivers/isdn/pcbit/Kconfig"
+
+source "drivers/isdn/sc/Kconfig"
+
+source "drivers/isdn/act2000/Kconfig"
+
+source "drivers/isdn/tpam/Kconfig"
+
+source "drivers/isdn/hysdn/Kconfig"
+
+endmenu
+
--- diff/drivers/isdn/i4l/Makefile	2003-06-30 10:07:33.000000000 +0100
+++ source/drivers/isdn/i4l/Makefile	2004-02-18 09:03:59.000000000 +0000
@@ -2,18 +2,17 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_ISDN)		+= isdn.o
+obj-$(CONFIG_ISDN_I4L)		+= isdn.o
 obj-$(CONFIG_ISDN_PPP_BSDCOMP)	+= isdn_bsdcomp.o
 
 # Multipart objects.
 
-isdn-y				:= isdn_net_lib.o isdn_fsm.o isdn_tty.o \
-				   isdn_v110.o isdn_common.o
-isdn-$(CONFIG_ISDN_NET_SIMPLE)	+= isdn_net.o
-isdn-$(CONFIG_ISDN_NET_CISCO)	+= isdn_ciscohdlck.o
-isdn-$(CONFIG_ISDN_PPP)		+= isdn_ppp.o isdn_ppp_ccp.o
-isdn-$(CONFIG_ISDN_PPP_VJ)	+= isdn_ppp_vj.o
-isdn-$(CONFIG_ISDN_MPP)		+= isdn_ppp_mp.o
+isdn-y				:= isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
+
+# Optional parts of multipart objects.
+
+isdn-$(CONFIG_ISDN_PPP)		+= isdn_ppp.o
 isdn-$(CONFIG_ISDN_X25)		+= isdn_concap.o isdn_x25iface.o
-isdn-$(CONFIG_ISDN_AUDIO)	+= isdn_audio.o
+isdn-$(CONFIG_ISDN_AUDIO)		+= isdn_audio.o
 isdn-$(CONFIG_ISDN_TTY_FAX)	+= isdn_ttyfax.o
+
--- diff/drivers/isdn/i4l/isdn_audio.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_audio.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,20 +1,21 @@
-/* Linux ISDN subsystem, audio conversion and compression
+/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *           1996      by Christian Mock (cm@tahina.priv.at)
- *           1998      by Armin Schindler (mac@gismo.telekom.de)
+ * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
+ * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
- * DTMF code         by Christian Mock
- * Silence detection by Armin Schindler
  */
 
 #include <linux/isdn.h>
 #include "isdn_audio.h"
 #include "isdn_common.h"
-#include "isdn_tty.h"
+
+char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
 
 /*
  * Misc. lookup-tables.
@@ -168,39 +169,19 @@
 	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
 };
 
-#define NCOEFF           16     /* number of frequencies to be analyzed       */
-#define DTMF_TRESH    25000     /* above this is dtmf                         */
+#define NCOEFF            8     /* number of frequencies to be analyzed       */
+#define DTMF_TRESH     4000     /* above this is dtmf                         */
 #define SILENCE_TRESH   200     /* below this is silence                      */
-#define H2_TRESH      20000     /* 2nd harmonic                               */
 #define AMP_BITS          9     /* bits per sample, reduced to avoid overflow */
 #define LOGRP             0
 #define HIGRP             1
 
-typedef struct {
-	int grp;                /* low/high group     */
-	int k;                  /* k                  */
-	int k2;                 /* k fuer 2. harmonic */
-} dtmf_t;
-
 /* For DTMF recognition:
  * 2 * cos(2 * PI * k / N) precalculated for all k
  */
 static int cos2pik[NCOEFF] =
 {
-	55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
-	38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
-};
-
-static dtmf_t dtmf_tones[8] =
-{
-	{LOGRP, 0, 1},          /*  697 Hz */
-	{LOGRP, 2, 3},          /*  770 Hz */
-	{LOGRP, 4, 5},          /*  852 Hz */
-	{LOGRP, 6, 7},          /*  941 Hz */
-	{HIGRP, 8, 9},          /* 1209 Hz */
-	{HIGRP, 10, 11},        /* 1336 Hz */
-	{HIGRP, 12, 13},        /* 1477 Hz */
-	{HIGRP, 14, 15}         /* 1633 Hz */
+	55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
 };
 
 static char dtmf_matrix[4][4] =
@@ -226,10 +207,8 @@
 	:	"0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
 	:	"memory", "ax");
 #else
-	while (n--) {
-		*buff = table[*buff];
-		buff++;
-	}
+	while (n--)
+		*buff = table[*(unsigned char *)buff], buff++;
 #endif
 }
 
@@ -500,13 +479,25 @@
 			sk2 = sk1;
 			sk1 = sk;
 		}
+		/* Avoid overflows */
+		sk >>= 1;
+		sk2 >>= 1;
+		/* compute |X(k)|**2 */
+		/* report overflows. This should not happen. */
+		/* Comment this out if desired */
+		if (sk < -32768 || sk > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
+		if (sk2 < -32768 || sk2 > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
 		result[k] =
 		    ((sk * sk) >> AMP_BITS) -
 		    ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
 		    ((sk2 * sk2) >> AMP_BITS);
 	}
 	skb_queue_tail(&info->dtmf_queue, skb);
-	mod_timer(&info->read_timer, jiffies + 4);
+	isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
 }
 
 void
@@ -517,31 +508,63 @@
 	dtmf_state *s;
 	int silence;
 	int i;
+	int di;
+	int ch;
 	int grp[2];
 	char what;
 	char *p;
+	int thresh;
 
 	while ((skb = skb_dequeue(&info->dtmf_queue))) {
 		result = (int *) skb->data;
 		s = info->dtmf_state;
-		grp[LOGRP] = grp[HIGRP] = -2;
+		grp[LOGRP] = grp[HIGRP] = -1;
 		silence = 0;
-		for (i = 0; i < 8; i++) {
-			if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
-			    (result[dtmf_tones[i].k2] < H2_TRESH))
-				grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
-			else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
-			      (result[dtmf_tones[i].k2] < SILENCE_TRESH))
+		thresh = 0;
+		for (i = 0; i < NCOEFF; i++) {
+			if (result[i] > DTMF_TRESH) {
+				if (result[i] > thresh)
+					thresh = result[i];
+			}
+			else if (result[i] < SILENCE_TRESH)
 				silence++;
 		}
-		if (silence == 8)
+		if (silence == NCOEFF)
 			what = ' ';
 		else {
-			if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
-				what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
-				if (s->last != ' ' && s->last != '.')
-					s->last = what;	/* min. 1 non-DTMF between DTMF */
-			} else
+			if (thresh > 0)	{
+				thresh = thresh >> 4;  /* touchtones must match within 12 dB */
+				for (i = 0; i < NCOEFF; i++) {
+					if (result[i] < thresh)
+						continue;  /* ignore */
+					/* good level found. This is allowed only one time per group */
+					if (i < NCOEFF / 2) {
+						/* lowgroup*/
+						if (grp[LOGRP] >= 0) {
+							// Bad. Another tone found. */
+							grp[LOGRP] = -1;
+							break;
+						}
+						else
+							grp[LOGRP] = i;
+					}
+					else { /* higroup */
+						if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
+							grp[HIGRP] = -1;
+							break;
+						}
+						else
+							grp[HIGRP] = i - NCOEFF/2;
+					}
+				}
+				if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
+					what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
+					if (s->last != ' ' && s->last != '.')
+						s->last = what;	/* min. 1 non-DTMF between DTMF */
+				} else
+					what = '.';
+			}
+			else
 				what = '.';
 		}
 		if ((what != s->last) && (what != ' ') && (what != '.')) {
@@ -550,17 +573,16 @@
 			*p++ = 0x10;
 			*p = what;
 			skb_trim(skb, 2);
-			if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) {
-				printk(KERN_WARNING
-				       "isdn_audio: insufficient skb_headroom, dropping\n");
-				kfree_skb(skb);
-				return;
-			}
 			ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
 			ISDN_AUDIO_SKB_LOCK(skb) = 0;
-			isdn_tty_queue_tail(info, skb, 2);
-			if (((get_isdn_dev())->modempoll) && (info->rcvsched))
-				mod_timer(&info->read_timer, jiffies + 4);
+			di = info->isdn_driver;
+			ch = info->isdn_channel;
+			__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
+			dev->drv[di]->rcvcount[ch] += 2;
+			/* Schedule dequeuing */
+			if ((dev->modempoll) && (info->rcvsched))
+				isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+			wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
 		} else
 			kfree_skb(skb);
 		s->last = what;
@@ -648,6 +670,8 @@
 isdn_audio_put_dle_code(modem_info * info, u_char code)
 {
 	struct sk_buff *skb;
+	int di;
+	int ch;
 	char *p;
 
 	skb = dev_alloc_skb(2);
@@ -660,18 +684,16 @@
 	p = (char *) skb_put(skb, 2);
 	p[0] = 0x10;
 	p[1] = code;
-	if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) {
-		printk(KERN_WARNING
-		       "isdn_audio: insufficient skb_headroom, dropping\n");
-		kfree_skb(skb);
-		return;
-	}
 	ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
 	ISDN_AUDIO_SKB_LOCK(skb) = 0;
-	isdn_tty_queue_tail(info, skb, 2);
+	di = info->isdn_driver;
+	ch = info->isdn_channel;
+	__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
+	dev->drv[di]->rcvcount[ch] += 2;
 	/* Schedule dequeuing */
-	if (((get_isdn_dev())->modempoll) && (info->rcvsched))
-		mod_timer(&info->read_timer, jiffies + 4);
+	if ((dev->modempoll) && (info->rcvsched))
+		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+	wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
 }
 
 void
@@ -682,7 +704,7 @@
 
 	what = ' ';
 
-	if (s->idx > (u_int)(info->emu.vpar[2] * 800)) { 
+	if (s->idx > (info->emu.vpar[2] * 800)) { 
 		s->idx = 0;
 		if (!s->state) {	/* silence from beginning of rec */ 
 			what = 's';
@@ -690,9 +712,9 @@
 			what = 'q';
 		}
 	}
-	if ((what == 's') || (what == 'q')) {
-		printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
-			(what=='s') ? "silence":"quiet");
-		isdn_audio_put_dle_code(info, what);
-	} 
+		if ((what == 's') || (what == 'q')) {
+			printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
+				(what=='s') ? "silence":"quiet");
+			isdn_audio_put_dle_code(info, what);
+		} 
 }
--- diff/drivers/isdn/i4l/isdn_audio.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_audio.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,6 @@
-/* Linux ISDN subsystem, audio conversion and compression
+/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
  *
@@ -18,6 +20,7 @@
 
 typedef struct dtmf_state {
 	char last;
+	char llast;
 	int idx;
 	int buf[DTMF_NPOINTS];
 } dtmf_state;
--- diff/drivers/isdn/i4l/isdn_common.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_common.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,6 @@
-/* Linux ISDN subsystem, common used functions
+/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
+ *
+ * Linux ISDN subsystem, common used functions (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg
@@ -6,6 +8,7 @@
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #include <linux/config.h>
@@ -16,811 +19,463 @@
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
 #include <linux/smp_lock.h>
-#include <linux/ctype.h>
 #include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_net.h"
 #include "isdn_tty.h"
+#include "isdn_net.h"
 #include "isdn_ppp.h"
 #ifdef CONFIG_ISDN_AUDIO
 #include "isdn_audio.h"
 #endif
+#ifdef CONFIG_ISDN_DIVERSION_MODULE
+#define CONFIG_ISDN_DIVERSION
+#endif
+#ifdef CONFIG_ISDN_DIVERSION
 #include <linux/isdn_divertif.h>
-#include <linux/devfs_fs_kernel.h>
+#endif /* CONFIG_ISDN_DIVERSION */
+#include "isdn_v110.h"
+
+/* Debugflags */
+#undef ISDN_DEBUG_STATCALLB
 
 MODULE_DESCRIPTION("ISDN4Linux: link layer");
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_LICENSE("GPL");
 
-static isdn_dev_t *isdndev;
+isdn_dev *dev;
 
-isdn_dev_t *
-get_isdn_dev(void) {
-	return(isdndev);
-}
-
-/* Description of hardware-level-driver */
-typedef struct isdn_driver {
-	int                 di;
-	char                id[20];
-	atomic_t            refcnt;
-	unsigned long       flags;            /* Misc driver Flags           */
-	unsigned long       features;
-	int                 channels;         /* Number of channels          */
-	wait_queue_head_t   st_waitq;         /* Wait-Queue for status-reads */
-	int                 maxbufsize;       /* Maximum Buffersize supported*/
-	int                 stavail;          /* Chars avail on Status-device*/
-	isdn_if            *interface;        /* Interface to driver         */
-	char                msn2eaz[10][ISDN_MSNLEN];  /*  MSN->EAZ          */
-	spinlock_t          lock;
-	struct isdn_slot   *slots; 
-	struct fsm_inst     fi;
-} isdn_driver_t;
-
-static spinlock_t	drivers_lock = SPIN_LOCK_UNLOCKED;
-static isdn_driver_t	*drivers[ISDN_MAX_DRIVERS];
-
-static void isdn_lock_driver(struct isdn_driver *drv);
-static void isdn_unlock_driver(struct isdn_driver *drv);
-
-/* ====================================================================== */
-
-static void drv_destroy(struct isdn_driver *drv);
-
-static inline struct isdn_driver *
-get_drv(struct isdn_driver *drv)
-{
-	printk("get_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt), 
-	       atomic_read(&drv->refcnt) + 1); 
-	atomic_inc(&drv->refcnt);
-	return drv;
-}
+static char *isdn_revision = "$Revision: 1.1.2.3 $";
 
-static inline void
-put_drv(struct isdn_driver *drv)
-{
-	printk("put_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt),
-	       atomic_read(&drv->refcnt) - 1); 
-	if (atomic_dec_and_test(&drv->refcnt)) {
-		drv_destroy(drv);
-	}
-}
+extern char *isdn_net_revision;
+extern char *isdn_tty_revision;
+#ifdef CONFIG_ISDN_PPP
+extern char *isdn_ppp_revision;
+#else
+static char *isdn_ppp_revision = ": none $";
+#endif
+#ifdef CONFIG_ISDN_AUDIO
+extern char *isdn_audio_revision;
+#else
+static char *isdn_audio_revision = ": none $";
+#endif
+extern char *isdn_v110_revision;
 
-/* ====================================================================== */
-
-static struct fsm slot_fsm;
-static void slot_debug(struct fsm_inst *fi, char *fmt, ...);
-
-static char *slot_st_str[] = {
-	"ST_SLOT_NULL",
-	"ST_SLOT_BOUND",
-	"ST_SLOT_IN",
-	"ST_SLOT_WAIT_DCONN",
-	"ST_SLOT_DCONN",
-	"ST_SLOT_WAIT_BCONN",
-	"ST_SLOT_ACTIVE",
-	"ST_SLOT_WAIT_BHUP",
-	"ST_SLOT_WAIT_DHUP",
-};
+#ifdef CONFIG_ISDN_DIVERSION
+static isdn_divert_if *divert_if; /* = NULL */
+#endif /* CONFIG_ISDN_DIVERSION */
 
-static char *ev_str[] = {
-	"EV_DRV_REGISTER",
-	"EV_STAT_RUN",
-	"EV_STAT_STOP",
-	"EV_STAT_UNLOAD",
-	"EV_STAT_STAVAIL",
-	"EV_STAT_ADDCH",
-	"EV_STAT_ICALL",
-	"EV_STAT_DCONN",
-	"EV_STAT_BCONN",
-	"EV_STAT_BHUP",
-	"EV_STAT_DHUP",
-	"EV_STAT_BSENT",
-	"EV_STAT_CINF",
-	"EV_STAT_CAUSE",
-	"EV_STAT_DISPLAY",
-	"EV_STAT_FAXIND",
-	"EV_STAT_AUDIO",
-	"EV_CMD_CLREAZ",
-	"EV_CMD_SETEAZ",
-	"EV_CMD_SETL2",
-	"EV_CMD_SETL3",
-	"EV_CMD_DIAL",
-	"EV_CMD_ACCEPTD",
-	"EV_CMD_ACCEPTB",
-	"EV_CMD_HANGUP",
-	"EV_DATA_REQ",
-	"EV_DATA_IND",
-	"EV_SLOT_BIND",
-	"EV_SLOT_UNBIND",
-};
 
-static int __slot_command(struct isdn_slot *slot, isdn_ctrl *cmd);
+static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+static void set_global_features(void);
+static int isdn_wildmat(char *s, char *p);
 
-static void isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd);
-static void __isdn_v110_open(struct isdn_slot *slot);
-static void __isdn_v110_close(struct isdn_slot *slot);
-static void __isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *cmd);
-static int  isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb);
-static int  isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb);
 
-static inline int
-do_event_cb(struct isdn_slot *slot, int pr, void *arg)
+static inline void
+isdn_lock_driver(isdn_driver_t *drv)
 {
-	if (slot->event_cb)
-		return slot->event_cb(slot, pr, arg);
-
-	return -ENXIO;
+	try_module_get(drv->interface->owner);
+	drv->locks++;
 }
 
-static int
-slot_bind(struct fsm_inst *fi, int pr, void *arg)
+void
+isdn_lock_drivers(void)
 {
-	struct isdn_slot *slot = fi->userdata;
-	
-	isdn_lock_driver(slot->drv);
-	fsm_change_state(fi, ST_SLOT_BOUND);
+	int i;
 
-	return 0;
+	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+		if (!dev->drv[i])
+			continue;
+		isdn_lock_driver(dev->drv[i]);
+	}
 }
 
-/* just pass through command */
-static int
-slot_command(struct fsm_inst *fi, int pr, void *arg)
+static inline void
+isdn_unlock_driver(isdn_driver_t *drv)
 {
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *c = arg;
-
-	return __slot_command(slot, c);
+	if (drv->locks > 0) {
+		drv->locks--;
+		module_put(drv->interface->owner);
+	}
 }
 
-/* just pass through status */
-static int
-slot_stat(struct fsm_inst *fi, int pr, void *arg)
+void
+isdn_unlock_drivers(void)
 {
-	struct isdn_slot *slot = fi->userdata;
+	int i;
 
-	do_event_cb(slot, pr, arg);
-	return 0;
+	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+		if (!dev->drv[i])
+			continue;
+		isdn_unlock_driver(dev->drv[i]);
+	}
 }
 
-/* just pass through command */
-static int
-slot_setl2(struct fsm_inst *fi, int pr, void *arg)
+#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
+void
+isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 {
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *c = arg;
-
-	isdn_v110_setl2(slot, c);
+	int dumpc;
 
-	return __slot_command(slot, c);
+	printk(KERN_DEBUG "%s(%d) ", s, len);
+	for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
+		printk(" %02x", *p++);
+	printk("\n");
 }
+#endif
 
+/*
+ * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
+ * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
+ */
 static int
-slot_dial(struct fsm_inst *fi, int pr, void *arg)
+isdn_star(char *s, char *p)
 {
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-	int retval;
-
-	retval = __slot_command(slot, ctrl);
-	if (retval >= 0)
-		fsm_change_state(fi, ST_SLOT_WAIT_DCONN);
-
-	return retval;
+	while (isdn_wildmat(s, p)) {
+		if (*++s == '\0')
+			return (2);
+	}
+	return (0);
 }
 
-static int
-slot_acceptd(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-	int retval;
-
-	retval = __slot_command(slot, ctrl);
-	if (retval >= 0)
-		fsm_change_state(fi, ST_SLOT_WAIT_DCONN);
-
-	return retval;
-}
+/*
+ * Shell-type Pattern-matching for incoming caller-Ids
+ * This function gets a string in s and checks, if it matches the pattern
+ * given in p.
+ *
+ * Return:
+ *   0 = match.
+ *   1 = no match.
+ *   2 = no match. Would eventually match, if s would be longer.
+ *
+ * Possible Patterns:
+ *
+ * '?'     matches one character
+ * '*'     matches zero or more characters
+ * [xyz]   matches the set of characters in brackets.
+ * [^xyz]  matches any single character not in the set of characters
+ */
 
 static int
-slot_acceptb(struct fsm_inst *fi, int pr, void *arg)
+isdn_wildmat(char *s, char *p)
 {
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-	int retval;
-
-	retval = __slot_command(slot, ctrl);
-	if (retval >= 0)
-		fsm_change_state(fi, ST_SLOT_WAIT_BCONN);
+	register int last;
+	register int matched;
+	register int reverse;
+	register int nostar = 1;
 
-	return retval;
+	if (!(*s) && !(*p))
+		return(1);
+	for (; *p; s++, p++)
+		switch (*p) {
+			case '\\':
+				/*
+				 * Literal match with following character,
+				 * fall through.
+				 */
+				p++;
+			default:
+				if (*s != *p)
+					return (*s == '\0')?2:1;
+				continue;
+			case '?':
+				/* Match anything. */
+				if (*s == '\0')
+					return (2);
+				continue;
+			case '*':
+				nostar = 0;	
+				/* Trailing star matches everything. */
+				return (*++p ? isdn_star(s, p) : 0);
+			case '[':
+				/* [^....] means inverse character class. */
+				if ((reverse = (p[1] == '^')))
+					p++;
+				for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
+					/* This next line requires a good C compiler. */
+					if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
+						matched = 1;
+				if (matched == reverse)
+					return (1);
+				continue;
+		}
+	return (*s == '\0')?0:nostar;
 }
 
-static int
-slot_actv_hangup(struct fsm_inst *fi, int pr, void *arg)
+int isdn_msncmp( const char * msn1, const char * msn2 )
 {
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-	int retval;
+	char TmpMsn1[ ISDN_MSNLEN ];
+	char TmpMsn2[ ISDN_MSNLEN ];
+	char *p;
 
-	retval = __slot_command(slot, ctrl);
-	if (retval >= 0) {
-		fsm_change_state(fi, ST_SLOT_WAIT_BHUP);
-	}
-	return retval;
-}
+	for ( p = TmpMsn1; *msn1 && *msn1 != ':'; )  // Strip off a SPID
+		*p++ = *msn1++;
+	*p = '\0';
 
-static int
-slot_dconn(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_slot *slot = fi->userdata;
+	for ( p = TmpMsn2; *msn2 && *msn2 != ':'; )  // Strip off a SPID
+		*p++ = *msn2++;
+	*p = '\0';
 
-	fsm_change_state(fi, ST_SLOT_DCONN);
-	do_event_cb(slot, pr, arg);
-	return 0;
+	return isdn_wildmat( TmpMsn1, TmpMsn2 );
 }
 
-static int
-slot_bconn(struct fsm_inst *fi, int pr, void *arg)
+int
+isdn_dc2minor(int di, int ch)
 {
-	struct isdn_slot *slot = fi->userdata;
-
-	fsm_change_state(fi, ST_SLOT_ACTIVE);
-	__isdn_v110_open(slot);
-
-	isdn_info_update();
-
-	do_event_cb(slot, pr, arg);
-	return 0;
+	int i;
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
+			return i;
+	return -1;
 }
 
-static int
-slot_bhup(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_slot *slot = fi->userdata;
-
-	__isdn_v110_close(slot);
-	fsm_change_state(fi, ST_SLOT_WAIT_DHUP);
+static int isdn_timer_cnt1 = 0;
+static int isdn_timer_cnt2 = 0;
+static int isdn_timer_cnt3 = 0;
 
-	do_event_cb(slot, pr, arg);
-	return 0;
-}
-
-static int
-slot_dhup(struct fsm_inst *fi, int pr, void *arg)
+static void
+isdn_timer_funct(ulong dummy)
 {
-	struct isdn_slot *slot = fi->userdata;
-
-	fsm_change_state(fi, ST_SLOT_BOUND);
-
-	do_event_cb(slot, pr, arg);
-	return 0;
+	int tf = dev->tflags;
+	if (tf & ISDN_TIMER_FAST) {
+		if (tf & ISDN_TIMER_MODEMREAD)
+			isdn_tty_readmodem();
+		if (tf & ISDN_TIMER_MODEMPLUS)
+			isdn_tty_modem_escape();
+		if (tf & ISDN_TIMER_MODEMXMIT)
+			isdn_tty_modem_xmit();
+	}
+	if (tf & ISDN_TIMER_SLOW) {
+		if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
+			isdn_timer_cnt1 = 0;
+			if (tf & ISDN_TIMER_NETDIAL)
+				isdn_net_dial();
+		}
+		if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
+			isdn_timer_cnt2 = 0;
+			if (tf & ISDN_TIMER_NETHANGUP)
+				isdn_net_autohup();
+			if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
+				isdn_timer_cnt3 = 0;
+				if (tf & ISDN_TIMER_MODEMRING)
+					isdn_tty_modem_ring();
+			}
+			if (tf & ISDN_TIMER_CARRIER)
+				isdn_tty_carrier_timeout();
+		}
+	}
+	if (tf) 
+		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
 }
 
-static int
-slot_data_req(struct fsm_inst *fi, int pr, void *arg)
+void
+isdn_timer_ctrl(int tf, int onoff)
 {
-	struct isdn_slot *slot = fi->userdata;
-	struct sk_buff *skb = arg;
+	unsigned long flags;
+	int old_tflags;
 
-	return isdn_v110_data_req(slot, skb);
+	spin_lock_irqsave(&dev->timerlock, flags);
+	if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
+		/* If the slow-timer wasn't activated until now */
+		isdn_timer_cnt1 = 0;
+		isdn_timer_cnt2 = 0;
+	}
+	old_tflags = dev->tflags;
+	if (onoff)
+		dev->tflags |= tf;
+	else
+		dev->tflags &= ~tf;
+	if (dev->tflags && !old_tflags)
+		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
+	spin_unlock_irqrestore(&dev->timerlock, flags);
 }
 
-static int
-slot_data_ind(struct fsm_inst *fi, int pr, void *arg)
+/*
+ * Receive a packet from B-Channel. (Called from low-level-module)
+ */
+static void
+isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
 {
-	struct isdn_slot *slot = fi->userdata;
-	struct sk_buff *skb = arg;
+	int i;
 
+	if ((i = isdn_dc2minor(di, channel)) == -1) {
+		dev_kfree_skb(skb);
+		return;
+	}
 	/* Update statistics */
-	slot->ibytes += skb->len;
-
-	return isdn_v110_data_ind(slot, skb);
-}
-
-static int
-slot_bsent(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-
-	__isdn_v110_bsent(slot, pr, ctrl);
-	return 0;
-}
-
-static int
-slot_icall(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_slot *slot = fi->userdata;
-	isdn_ctrl *ctrl = arg;
-	int retval;
-
-	isdn_lock_driver(slot->drv);
-	fsm_change_state(fi, ST_SLOT_IN);
-	slot_debug(fi, "ICALL: %s\n", ctrl->parm.num);
-	if (isdndev->global_flags & ISDN_GLOBAL_STOPPED)
-		return 0;
+	dev->ibytes[i] += skb->len;
 	
-	strcpy(slot->num, ctrl->parm.setup.phone);
-	/* Try to find a network-interface which will accept incoming call */
-	retval = isdn_net_find_icall(slot, &ctrl->parm.setup);
-
-	/* already taken by net now? */
-	if (fi->state != ST_SLOT_IN)
-		goto out;
+	/* First, try to deliver data to network-device */
+	if (isdn_net_rcv_skb(i, skb))
+		return;
 
-	retval = isdn_tty_find_icall(slot, &ctrl->parm.setup);
- out:
-	return 0;
+	/* V.110 handling
+	 * makes sense for async streams only, so it is
+	 * called after possible net-device delivery.
+	 */
+	if (dev->v110[i]) {
+		atomic_inc(&dev->v110use[i]);
+		skb = isdn_v110_decode(dev->v110[i], skb);
+		atomic_dec(&dev->v110use[i]);
+		if (!skb)
+			return;
+	}
+
+	/* No network-device found, deliver to tty or raw-channel */
+	if (skb->len) {
+		if (isdn_tty_rcv_skb(i, di, channel, skb))
+			return;
+		wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
+	} else
+		dev_kfree_skb(skb);
 }
 
-/* should become broadcast later */
-static int
-slot_in_dhup(struct fsm_inst *fi, int pr, void *arg)
+/*
+ * Intercept command from Linklevel to Lowlevel.
+ * If layer 2 protocol is V.110 and this is not supported by current
+ * lowlevel-driver, use driver's transparent mode and handle V.110 in
+ * linklevel instead.
+ */
+int
+isdn_command(isdn_ctrl *cmd)
 {
-	struct isdn_slot *slot = fi->userdata;
-
-	isdn_unlock_driver(slot->drv);
-	fsm_change_state(fi, ST_SLOT_NULL);
-	do_event_cb(slot, pr, arg);
-	return 0;
+	if (cmd->driver == -1) {
+		printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
+		return(1);
+	}
+	if (cmd->command == ISDN_CMD_SETL2) {
+		int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+		unsigned long l2prot = (cmd->arg >> 8) & 255;
+		unsigned long features = (dev->drv[cmd->driver]->interface->features
+						>> ISDN_FEATURE_L2_SHIFT) &
+						ISDN_FEATURE_L2_MASK;
+		unsigned long l2_feature = (1 << l2prot);
+
+		switch (l2prot) {
+			case ISDN_PROTO_L2_V11096:
+			case ISDN_PROTO_L2_V11019:
+			case ISDN_PROTO_L2_V11038:
+			/* If V.110 requested, but not supported by
+			 * HL-driver, set emulator-flag and change
+			 * Layer-2 to transparent
+			 */
+				if (!(features & l2_feature)) {
+					dev->v110emu[idx] = l2prot;
+					cmd->arg = (cmd->arg & 255) |
+						(ISDN_PROTO_L2_TRANS << 8);
+				} else
+					dev->v110emu[idx] = 0;
+		}
+	}
+	return dev->drv[cmd->driver]->interface->command(cmd);
 }
 
-static int
-slot_unbind(struct fsm_inst *fi, int pr, void *arg)
+void
+isdn_all_eaz(int di, int ch)
 {
-	struct isdn_slot *slot = fi->userdata;
 	isdn_ctrl cmd;
 
-	isdn_unlock_driver(slot->drv);
-	fsm_change_state(fi, ST_SLOT_NULL);
-	strcpy(slot->num, "???");
+	if (di < 0)
+		return;
+	cmd.driver = di;
+	cmd.arg = ch;
+	cmd.command = ISDN_CMD_SETEAZ;
 	cmd.parm.num[0] = '\0';
-	isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd);
-	slot->ibytes = 0;
-	slot->obytes = 0;
-	slot->usage = ISDN_USAGE_NONE;
-	put_drv(slot->drv);
-	isdn_info_update();
-	return 0;
+	isdn_command(&cmd);
 }
 
-static struct fsm_node slot_fn_tbl[] = {
-	{ ST_SLOT_NULL,          EV_SLOT_BIND,   slot_bind        },
-	{ ST_SLOT_NULL,          EV_STAT_ICALL,  slot_icall       },
-
-	{ ST_SLOT_BOUND,         EV_CMD_CLREAZ,  slot_command     },
-	{ ST_SLOT_BOUND,         EV_CMD_SETEAZ,  slot_command     },
-	{ ST_SLOT_BOUND,         EV_CMD_SETL2,   slot_setl2       },
-	{ ST_SLOT_BOUND,         EV_CMD_SETL3,   slot_command     },
-	{ ST_SLOT_BOUND,         EV_CMD_DIAL,    slot_dial        },
-	{ ST_SLOT_BOUND,         EV_SLOT_UNBIND, slot_unbind      },
-
-	{ ST_SLOT_IN,            EV_CMD_SETL2,   slot_setl2       },
-	{ ST_SLOT_IN,            EV_CMD_SETL3,   slot_command     },
-	{ ST_SLOT_IN,            EV_CMD_ACCEPTD, slot_acceptd     },
-	{ ST_SLOT_IN,            EV_STAT_DHUP,   slot_in_dhup     },
-
-	{ ST_SLOT_WAIT_DCONN,    EV_STAT_DCONN,  slot_dconn       },
-	{ ST_SLOT_WAIT_DCONN,    EV_STAT_DHUP,   slot_dhup        },
-
-	{ ST_SLOT_DCONN,         EV_CMD_ACCEPTB, slot_acceptb     },
-	{ ST_SLOT_DCONN,         EV_STAT_BCONN,  slot_bconn       },
-
-	{ ST_SLOT_WAIT_BCONN,    EV_STAT_BCONN,  slot_bconn       },
-
-	{ ST_SLOT_ACTIVE,        EV_DATA_REQ,    slot_data_req    },
-	{ ST_SLOT_ACTIVE,        EV_DATA_IND,    slot_data_ind    },
-	{ ST_SLOT_ACTIVE,        EV_CMD_HANGUP,  slot_actv_hangup },
-	{ ST_SLOT_ACTIVE,        EV_STAT_BSENT,  slot_bsent       },
-	{ ST_SLOT_ACTIVE,        EV_STAT_BHUP,   slot_bhup        },
-	{ ST_SLOT_ACTIVE,        EV_STAT_FAXIND, slot_stat        },
-	{ ST_SLOT_ACTIVE,        EV_STAT_AUDIO,  slot_stat        },
-
-	{ ST_SLOT_WAIT_BHUP,     EV_STAT_BHUP,   slot_bhup        },
-
-	{ ST_SLOT_WAIT_DHUP,     EV_STAT_DHUP,   slot_dhup        },
-};
-
-static struct fsm slot_fsm = {
-	.st_cnt = ARRAY_SIZE(slot_st_str),
-	.st_str = slot_st_str,
-	.ev_cnt = ARRAY_SIZE(ev_str),
-	.ev_str = ev_str,
-	.fn_cnt = ARRAY_SIZE(slot_fn_tbl),
-	.fn_tbl = slot_fn_tbl,
-};
-
-static void slot_debug(struct fsm_inst *fi, char *fmt, ...)
-{
-	va_list args;
-	struct isdn_slot *slot = fi->userdata;
-	char buf[128];
-	char *p = buf;
+/*
+ * Begin of a CAPI like LL<->HL interface, currently used only for 
+ * supplementary service (CAPI 2.0 part III)
+ */
+#include <linux/isdn//capicmd.h>
 
-	va_start(args, fmt);
-	p += sprintf(p, "slot (%d:%d): ", slot->di, slot->ch);
-	p += vsprintf(p, fmt, args);
-	va_end(args);
-	printk(KERN_DEBUG "%s\n", buf);
+int
+isdn_capi_rec_hl_msg(capi_msg *cm) {
+	
+	int di;
+	int ch;
+	
+	di = (cm->adr.Controller & 0x7f) -1;
+	ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f);
+	switch(cm->Command) {
+		case CAPI_FACILITY:
+			/* in the moment only handled in tty */
+			return(isdn_tty_capi_facility(cm));
+		default:
+			return(-1);
+	}
 }
 
-/* ====================================================================== */
-
-static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
-
-static struct fsm drv_fsm;
+static int
+isdn_status_callback(isdn_ctrl * c)
+{
+	int di;
+	u_long flags;
+	int i;
+	int r;
+	int retval = 0;
+	isdn_ctrl cmd;
+	isdn_net_dev *p;
 
-enum {
-	ST_DRV_NULL,
-	ST_DRV_LOADED,
-	ST_DRV_RUNNING,
-};
-
-static char *drv_st_str[] = {
-	"ST_DRV_NULL",
-	"ST_DRV_LOADED",
-	"ST_DRV_RUNNING",
-};
-
-#define DRV_FLAG_REJBUS  1
-
-static int __drv_command(struct isdn_driver *drv, isdn_ctrl *cmd);
-
-static int
-isdn_writebuf_skb(struct isdn_slot *slot, struct sk_buff *skb)
-{
-	struct sk_buff *skb2;
-	struct isdn_driver *drv = slot->drv;
-	int hl = drv->interface->hl_hdrlen;
-	int retval;
-
-	if (skb_headroom(skb) >= hl) {
-		retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb);
-		goto out;
-	}
-	skb2 = skb_realloc_headroom(skb, hl);
-	if (!skb2) {
-		retval = -ENOMEM;
-		goto out;
-	}
-	retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb2);
-	if (retval < 0)
-		kfree_skb(skb2);
-	else
-		kfree_skb(skb);
-
- out:
-	if (retval > 0)
-		slot->obytes += retval;
-
-	return retval;
-}
-
-int
-__isdn_drv_lookup(char *drvid)
-{
-	int drvidx;
-
-	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
-		if (!drivers[drvidx])
-			continue;
-
-		if (strcmp(drivers[drvidx]->id, drvid) == 0)
-			return drvidx;
-	}
-	return -1;
-}
-
-int
-isdn_drv_lookup(char *drvid)
-{
-	unsigned long flags;
-	int drvidx;
-
-	spin_lock_irqsave(&drivers_lock, flags);
-	drvidx = __isdn_drv_lookup(drvid);
-	spin_unlock_irqrestore(&drivers_lock, flags);
-	return drvidx;
-}
-
-static void
-drv_destroy(struct isdn_driver *drv)
-{
-	kfree(drv->slots);
-	kfree(drv);
-}
-
-static struct isdn_driver *
-get_drv_by_nr(int di)
-{
-	unsigned long flags;
-	struct isdn_driver *drv;
-	
-	BUG_ON(di < 0 || di >= ISDN_MAX_DRIVERS);
-
-	spin_lock_irqsave(&drivers_lock, flags);
-	drv = drivers[di];
-	if (drv)
-		get_drv(drv);
-	spin_unlock_irqrestore(&drivers_lock, flags);
-	return drv;
-}
-
-char *
-isdn_drv_drvid(int di)
-{
-	if (!drivers[di]) {
-		isdn_BUG();
-		return "";
-	}
-	return drivers[di]->id;
-}
-
-/* 
- * Helper keeping track of the features the drivers support
- */
-static void
-set_global_features(void)
-{
-	unsigned long flags;
-	int drvidx;
-
-	isdndev->global_features = 0;
-	spin_lock_irqsave(&drivers_lock, flags);
-	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
-		if (!drivers[drvidx])
-			continue;
-		if (drivers[drvidx]->fi.state != ST_DRV_RUNNING)
-			continue;
-		isdndev->global_features |= drivers[drvidx]->features;
-	}
-	spin_unlock_irqrestore(&drivers_lock, flags);
-}
-
-/*
- * driver state machine
- */
-static int  isdn_add_channels(struct isdn_driver *, int);
-static void isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb);
-static int  isdn_status_callback(isdn_ctrl * c);
-
-static void isdn_v110_add_features(struct isdn_driver *drv);
-
-static int
-drv_register(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_driver *drv = fi->userdata;
-	isdn_if *iif = arg;
-	
-	fsm_change_state(fi, ST_DRV_LOADED);
-	drv->maxbufsize = iif->maxbufsize;
-	drv->interface = iif;
-	iif->channels = drv->di;
-	iif->rcvcallb_skb = isdn_receive_skb_callback;
-	iif->statcallb = isdn_status_callback;
-
-	isdn_info_update();
-	return(0);
-}
-
-static int
-drv_stat_run(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_driver *drv = fi->userdata;
-	fsm_change_state(fi, ST_DRV_RUNNING);
-
-	drv->features = drv->interface->features;
-	isdn_v110_add_features(drv);
-	set_global_features();
-	return(0);
-}
-
-static int
-drv_stat_stop(struct fsm_inst *fi, int pr, void *arg)
-{
-	fsm_change_state(fi, ST_DRV_LOADED);
-	set_global_features();
-	return(0);
-}
-
-static int
-drv_stat_unload(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_driver *drv = fi->userdata;
-	unsigned long flags;
-
-	spin_lock_irqsave(&drivers_lock, flags);
-	drivers[drv->di] = NULL;
-	spin_unlock_irqrestore(&drivers_lock, flags);
-	put_drv(drv);
-
-	isdndev->channels -= drv->channels;
-
-	isdn_info_update();
-	return 0;
-}
-
-static int
-drv_stat_stavail(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_driver *drv = fi->userdata;
-	unsigned long flags;
-	isdn_ctrl *c = arg;
-	
-	spin_lock_irqsave(&stat_lock, flags);
-	drv->stavail += c->arg;
-	spin_unlock_irqrestore(&stat_lock, flags);
-	wake_up_interruptible(&drv->st_waitq);
-	return 0;
-}
-
-static int
-drv_to_slot(struct fsm_inst *fi, int pr, void *arg)
-{
-	struct isdn_driver *drv = fi->userdata;
-	isdn_ctrl *c = arg;
-	int ch = c->arg & 0xff;
-
-	return fsm_event(&drv->slots[ch].fi, pr, arg);
-}
-
-static struct fsm_node drv_fn_tbl[] = {
-	{ ST_DRV_NULL,    EV_DRV_REGISTER, drv_register     },
-
-	{ ST_DRV_LOADED,  EV_STAT_RUN,     drv_stat_run     },
-	{ ST_DRV_LOADED,  EV_STAT_STAVAIL, drv_stat_stavail },
-	{ ST_DRV_LOADED,  EV_STAT_UNLOAD,  drv_stat_unload  },
-
-	{ ST_DRV_RUNNING, EV_STAT_STOP,    drv_stat_stop    },
-	{ ST_DRV_RUNNING, EV_STAT_STAVAIL, drv_stat_stavail },
-	{ ST_DRV_RUNNING, EV_STAT_ICALL,   drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_DCONN,   drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_BCONN,   drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_BHUP,    drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_DHUP,    drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_BSENT,   drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_CINF,    drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_CAUSE,   drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_DISPLAY, drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_FAXIND,  drv_to_slot      },
-	{ ST_DRV_RUNNING, EV_STAT_AUDIO,   drv_to_slot      },
-};
-
-static struct fsm drv_fsm = {
-	.st_cnt = ARRAY_SIZE(drv_st_str),
-	.st_str = drv_st_str,
-	.ev_cnt = ARRAY_SIZE(ev_str),
-	.ev_str = ev_str,
-	.fn_cnt = ARRAY_SIZE(drv_fn_tbl),
-	.fn_tbl = drv_fn_tbl,
-};
-
-static void drv_debug(struct fsm_inst *fi, char *fmt, ...)
-{
-	va_list args;
-	struct isdn_driver *drv = fi->userdata;
-	char buf[128];
-	char *p = buf;
-
-	va_start(args, fmt);
-	p += sprintf(p, "%s: ", drv->id);
-	p += vsprintf(p, fmt, args);
-	va_end(args);
-	printk(KERN_DEBUG "%s\n", buf);
-}
-
-/* ====================================================================== */
-/* callbacks from hardware driver                                         */
-/* ====================================================================== */
-
-/* Receive a packet from B-Channel. */
-static void
-isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb)
-{
-	struct isdn_driver *drv;
-
-	drv = get_drv_by_nr(di);
-	if (!drv) {
-		/* hardware driver is buggy - driver isn't registered */
-		isdn_BUG();
-		goto out;
-	}
-	/* we short-cut here instead of going through the driver fsm */
-	if (drv->fi.state != ST_DRV_RUNNING) {
-		/* hardware driver is buggy - driver isn't running */
-		isdn_BUG();
-		goto out;
-	}
-	if (fsm_event(&drv->slots[ch].fi, EV_DATA_IND, skb))
-		dev_kfree_skb(skb);
- out:
-	put_drv(drv);
-}
-
-/* Receive status indications */
-static int
-isdn_status_callback(isdn_ctrl *c)
-{
-	struct isdn_driver *drv;
-	int rc;
-
-	drv = get_drv_by_nr(c->driver);
-	if (!drv) {
-		/* hardware driver is buggy - driver isn't registered */
-		isdn_BUG();
-		return 1;
-	}
-	
+	di = c->driver;
+	i = isdn_dc2minor(di, c->arg);
 	switch (c->command) {
+		case ISDN_STAT_BSENT:
+			if (i < 0)
+				return -1;
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (isdn_net_stat_callback(i, c))
+				return 0;
+			if (isdn_v110_stat_callback(i, c))
+				return 0;
+			if (isdn_tty_stat_callback(i, c))
+				return 0;
+			wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
+			break;
 		case ISDN_STAT_STAVAIL:
-			rc = fsm_event(&drv->fi, EV_STAT_STAVAIL, c);
+			dev->drv[di]->stavail += c->arg;
+			wake_up_interruptible(&dev->drv[di]->st_waitq);
 			break;
 		case ISDN_STAT_RUN:
-			rc = fsm_event(&drv->fi, EV_STAT_RUN, c);
+			dev->drv[di]->flags |= DRV_FLAG_RUNNING;
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+				if (dev->drvmap[i] == di)
+					isdn_all_eaz(di, dev->chanmap[i]);
+			set_global_features();
 			break;
 		case ISDN_STAT_STOP:
-			rc = fsm_event(&drv->fi, EV_STAT_STOP, c);
-			break;
-		case ISDN_STAT_UNLOAD:
-			rc = fsm_event(&drv->fi, EV_STAT_UNLOAD, c);
-			break;
-		case ISDN_STAT_ADDCH:
-			rc = fsm_event(&drv->fi, EV_STAT_ADDCH, c);
+			dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
 			break;
 		case ISDN_STAT_ICALL:
-			rc = fsm_event(&drv->fi, EV_STAT_ICALL, c);
-			break;
-		case ISDN_STAT_DCONN:
-			rc = fsm_event(&drv->fi, EV_STAT_DCONN, c);
-			break;
-		case ISDN_STAT_BCONN:
-			rc = fsm_event(&drv->fi, EV_STAT_BCONN, c);
-			break;
-		case ISDN_STAT_BHUP:
-			rc = fsm_event(&drv->fi, EV_STAT_BHUP, c);
-			break;
-		case ISDN_STAT_DHUP:
-			rc = fsm_event(&drv->fi, EV_STAT_DHUP, c);
-			break;
-		case ISDN_STAT_BSENT:
-			rc = fsm_event(&drv->fi, EV_STAT_BSENT, c);
-			break;
-		case ISDN_STAT_CINF:
-			rc = fsm_event(&drv->fi, EV_STAT_CINF, c);
-			break;
-		case ISDN_STAT_CAUSE:
-			rc = fsm_event(&drv->fi, EV_STAT_CAUSE, c);
-			break;
-		case ISDN_STAT_DISPLAY:
-			rc = fsm_event(&drv->fi, EV_STAT_DISPLAY, c);
-			break;
-		case ISDN_STAT_FAXIND:
-			rc = fsm_event(&drv->fi, EV_STAT_FAXIND, c);
-			break;
-		case ISDN_STAT_AUDIO:
-			rc = fsm_event(&drv->fi, EV_STAT_AUDIO, c);
-			break;
-#warning FIXME divert interface
-#if 0
-		case ISDN_STAT_ICALL:
-			/* Find any ttyI, waiting for D-channel setup */
-			if (isdn_tty_stat_callback(i, c)) {
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
 				cmd.driver = di;
 				cmd.arg = c->arg;
-				cmd.command = ISDN_CMD_ACCEPTB;
+				cmd.command = ISDN_CMD_HANGUP;
 				isdn_command(&cmd);
-				break;
+				return 0;
 			}
-			break;
+			/* Try to find a network-interface which will accept incoming call */
+			r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
 			switch (r) {
 				case 0:
+					/* No network-device replies.
+					 * Try ttyI's.
+					 * These return 0 on no match, 1 on match and
+					 * 3 on eventually match, if CID is longer.
+					 */
+                                        if (c->command == ISDN_STAT_ICALL)
+					  if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
+#ifdef CONFIG_ISDN_DIVERSION 
                                          if (divert_if)
-						 if ((retval = divert_if->stat_callback(c))) 
-							 return(retval); /* processed */
-					if ((!retval) && (drivers[di]->flags & DRV_FLAG_REJBUS)) {
+                 	                  if ((retval = divert_if->stat_callback(c))) 
+					    return(retval); /* processed */
+#endif /* CONFIG_ISDN_DIVERSION */                       
+					if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
 						/* No tty responding */
 						cmd.driver = di;
 						cmd.arg = c->arg;
@@ -829,7 +484,21 @@
 						retval = 2;
 					}
 					break;
-				case 1: /* incoming call accepted by net interface */
+				case 1:
+					/* Schedule connection-setup */
+					isdn_net_dial();
+					cmd.driver = di;
+					cmd.arg = c->arg;
+					cmd.command = ISDN_CMD_ACCEPTD;
+					for ( p = dev->netdev; p; p = p->next )
+						if ( p->local->isdn_channel == cmd.arg )
+						{
+							strcpy( cmd.parm.setup.eazmsn, p->local->msn );
+							isdn_command(&cmd);
+							retval = 1;
+							break;
+						}
+					break;
 
 				case 2:	/* For calling back, first reject incoming call ... */
 				case 3:	/* Interface found, but down, reject call actively  */
@@ -844,730 +513,716 @@
 					/* Fall through */
 				case 4:
 					/* ... then start callback. */
+					isdn_net_dial();
 					break;
 				case 5:
 					/* Number would eventually match, if longer */
 					retval = 3;
 					break;
 			}
-			dbg_statcallb("ICALL: ret=%d\n", retval);
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
+#endif
 			return retval;
 			break;
+		case ISDN_STAT_CINF:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (strcmp(c->parm.num, "0"))
+				isdn_net_stat_callback(i, c);
+			isdn_tty_stat_callback(i, c);
+			break;
+		case ISDN_STAT_CAUSE:
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
+#endif
+			printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
+			       dev->drvid[di], c->arg, c->parm.num);
+			isdn_tty_stat_callback(i, c);
+#ifdef CONFIG_ISDN_DIVERSION
+                        if (divert_if)
+                         divert_if->stat_callback(c); 
+#endif /* CONFIG_ISDN_DIVERSION */
+			break;
+		case ISDN_STAT_DISPLAY:
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
+#endif
+			isdn_tty_stat_callback(i, c);
+#ifdef CONFIG_ISDN_DIVERSION
+                        if (divert_if)
+                         divert_if->stat_callback(c); 
+#endif /* CONFIG_ISDN_DIVERSION */
+			break;
+		case ISDN_STAT_DCONN:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			/* Find any net-device, waiting for D-channel setup */
+			if (isdn_net_stat_callback(i, c))
+				break;
+			isdn_v110_stat_callback(i, c);
+			/* Find any ttyI, waiting for D-channel setup */
+			if (isdn_tty_stat_callback(i, c)) {
+				cmd.driver = di;
+				cmd.arg = c->arg;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				isdn_command(&cmd);
+				break;
+			}
+			break;
 		case ISDN_STAT_DHUP:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->online &= ~(1 << (c->arg));
+			isdn_info_update();
+			/* Signal hangup to network-devices */
+			if (isdn_net_stat_callback(i, c))
+				break;
+			isdn_v110_stat_callback(i, c);
+			if (isdn_tty_stat_callback(i, c))
+				break;
+#ifdef CONFIG_ISDN_DIVERSION
                         if (divert_if)
-				divert_if->stat_callback(c); 
+                         divert_if->stat_callback(c); 
+#endif /* CONFIG_ISDN_DIVERSION */
+			break;
+			break;
+		case ISDN_STAT_BCONN:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
+#endif
+			/* Signal B-channel-connect to network-devices */
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->online |= (1 << (c->arg));
+			isdn_info_update();
+			if (isdn_net_stat_callback(i, c))
+				break;
+			isdn_v110_stat_callback(i, c);
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_BHUP:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->online &= ~(1 << (c->arg));
+			isdn_info_update();
+#ifdef CONFIG_ISDN_X25
+			/* Signal hangup to network-devices */
+			if (isdn_net_stat_callback(i, c))
+				break;
+#endif
+			isdn_v110_stat_callback(i, c);
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_NODCH:
+			if (i < 0)
+				return -1;
+#ifdef ISDN_DEBUG_STATCALLB
+			printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
+#endif
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (isdn_net_stat_callback(i, c))
+				break;
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_ADDCH:
+			spin_lock_irqsave(&dev->lock, flags);
+			if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				return -1;
+			}
+			spin_unlock_irqrestore(&dev->lock, flags);
+			isdn_info_update();
 			break;
 		case ISDN_STAT_DISCH:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&dev->lock, flags);
 			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-				if ((slots[i].di == di) &&
-				    (slots[i].ch == c->arg)) {
-					if (c->parm.num[0])
-						slots[i].usage &= ~ISDN_USAGE_DISABLED;
-					else if (USG_NONE(isdn_slot_usage(i)))
-						slots[i].usage |= ISDN_USAGE_DISABLED;
-					else 
-						retval = -1;
-					break;
+				if ((dev->drvmap[i] == di) &&
+				    (dev->chanmap[i] == c->arg)) {
+				    if (c->parm.num[0])
+				      dev->usage[i] &= ~ISDN_USAGE_DISABLED;
+				    else
+				      if (USG_NONE(dev->usage[i])) {
+					dev->usage[i] |= ISDN_USAGE_DISABLED;
+				      }
+				      else 
+					retval = -1;
+				    break;
 				}
-			restore_flags(flags);
+			spin_unlock_irqrestore(&dev->lock, flags);
+			isdn_info_update();
+			break;
+		case ISDN_STAT_UNLOAD:
+			while (dev->drv[di]->locks > 0) {
+				isdn_unlock_driver(dev->drv[di]);
+			}
+			spin_lock_irqsave(&dev->lock, flags);
+			isdn_tty_stat_callback(i, c);
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+				if (dev->drvmap[i] == di) {
+					dev->drvmap[i] = -1;
+					dev->chanmap[i] = -1;
+					dev->usage[i] &= ~ISDN_USAGE_DISABLED;
+				}
+			dev->drivers--;
+			dev->channels -= dev->drv[di]->channels;
+			kfree(dev->drv[di]->rcverr);
+			kfree(dev->drv[di]->rcvcount);
+			for (i = 0; i < dev->drv[di]->channels; i++)
+				skb_queue_purge(&dev->drv[di]->rpqueue[i]);
+			kfree(dev->drv[di]->rpqueue);
+			kfree(dev->drv[di]->rcv_waitq);
+			kfree(dev->drv[di]);
+			dev->drv[di] = NULL;
+			dev->drvid[di][0] = '\0';
+			isdn_info_update();
+			set_global_features();
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return 0;
+		case ISDN_STAT_L1ERR:
 			break;
 		case CAPI_PUT_MESSAGE:
 			return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
+#ifdef CONFIG_ISDN_TTY_FAX
+		case ISDN_STAT_FAXIND:
+			isdn_tty_stat_callback(i, c);
+			break;
+#endif
+#ifdef CONFIG_ISDN_AUDIO
+		case ISDN_STAT_AUDIO:
+			isdn_tty_stat_callback(i, c);
+			break;
+#endif
+#ifdef CONFIG_ISDN_DIVERSION
 	        case ISDN_STAT_PROT:
 	        case ISDN_STAT_REDIR:
                         if (divert_if)
-				return(divert_if->stat_callback(c));
-#endif
+                          return(divert_if->stat_callback(c));
+#endif /* CONFIG_ISDN_DIVERSION */
 		default:
-			rc = 1;
+			return -1;
 	}
-	put_drv(drv);
-	return rc;
+	return 0;
 }
 
-/* ====================================================================== */
-
 /*
- * Register a new ISDN interface
+ * Get integer from char-pointer, set pointer to end of number
  */
 int
-register_isdn(isdn_if *iif)
-{
-	struct isdn_driver *drv;
-	unsigned long flags;
-	int drvidx;
-
-	drv = kmalloc(sizeof(*drv), GFP_ATOMIC);
-	if (!drv) {
-		printk(KERN_WARNING "register_isdn: out of mem\n");
-		goto fail;
-	}
-	memset(drv, 0, sizeof(*drv));
-
-	atomic_set(&drv->refcnt, 0);
-	spin_lock_init(&drv->lock);
-	init_waitqueue_head(&drv->st_waitq);
-	drv->fi.fsm = &drv_fsm;
-	drv->fi.state = ST_DRV_NULL;
-	drv->fi.debug = 1;
-	drv->fi.userdata = drv;
-	drv->fi.printdebug = drv_debug;
-
-	spin_lock_irqsave(&drivers_lock, flags);
-	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
-		if (!drivers[drvidx])
-			break;
-
-	if (drvidx == ISDN_MAX_DRIVERS)
-		goto fail_unlock;
-
-	if (!strlen(iif->id))
-		sprintf(iif->id, "line%d", drvidx);
-
-	if (__isdn_drv_lookup(iif->id) >= 0)
-		goto fail_unlock;
-
-	strcpy(drv->id, iif->id);
-	if (isdn_add_channels(drv, iif->channels))
-		goto fail_unlock;
-
-	drv->di = drvidx;
-	drivers[drvidx] = get_drv(drv);
-	spin_unlock_irqrestore(&drivers_lock, flags);
-
-	fsm_event(&drv->fi, EV_DRV_REGISTER, iif);
-	return 1;
-	
- fail_unlock:
-	spin_unlock_irqrestore(&drivers_lock, flags);
-	kfree(drv);
- fail:
-	return 0;
-}
-
-/* ====================================================================== */
-
-#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
-static isdn_divert_if *divert_if; /* = NULL */
-#else
-#define divert_if ((isdn_divert_if *) NULL)
-#endif
-
-static int isdn_wildmat(char *s, char *p);
-
-static void
-isdn_lock_driver(struct isdn_driver *drv)
-{
-	// FIXME don't ignore return value
-	try_module_get(drv->interface->owner);
-}
-
-static void
-isdn_unlock_driver(struct isdn_driver *drv)
-{
-	module_put(drv->interface->owner);
-}
-
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void
-isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
+isdn_getnum(char **p)
 {
-	int dumpc;
+	int v = -1;
 
-	printk(KERN_DEBUG "%s(%d) ", s, len);
-	for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
-		printk(" %02x", *p++);
-	printk("\n");
+	while (*p[0] >= '0' && *p[0] <= '9')
+		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
+	return v;
 }
-#endif
 
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-static int
-isdn_star(char *s, char *p)
-{
-	while (isdn_wildmat(s, p)) {
-		if (*++s == '\0')
-			return (2);
-	}
-	return (0);
-}
+#define DLE 0x10
 
 /*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p.
+ * isdn_readbchan() tries to get data from the read-queue.
+ * It MUST be called with interrupts off.
  *
- * Return:
- *   0 = match.
- *   1 = no match.
- *   2 = no match. Would eventually match, if s would be longer.
- *
- * Possible Patterns:
- *
- * '?'     matches one character
- * '*'     matches zero or more characters
- * [xyz]   matches the set of characters in brackets.
- * [^xyz]  matches any single character not in the set of characters
+ * Be aware that this is not an atomic operation when sleep != 0, even though 
+ * interrupts are turned off! Well, like that we are currently only called
+ * on behalf of a read system call on raw device files (which are documented
+ * to be dangerous and for for debugging purpose only). The inode semaphore
+ * takes care that this is not called for the same minor device number while
+ * we are sleeping, but access is not serialized against simultaneous read()
+ * from the corresponding ttyI device. Can other ugly events, like changes
+ * of the mapping (di,ch)<->minor, happen during the sleep? --he 
  */
-
-static int
-isdn_wildmat(char *s, char *p)
+int
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
 {
-	register int last;
-	register int matched;
-	register int reverse;
-	register int nostar = 1;
+	int count;
+	int count_pull;
+	int count_put;
+	int dflag;
+	struct sk_buff *skb;
+	u_char *cp;
 
-	if (!(*s) && !(*p))
-		return(1);
-	for (; *p; s++, p++)
-		switch (*p) {
-			case '\\':
-				/*
-				 * Literal match with following character,
-				 * fall through.
-				 */
-				p++;
-			default:
-				if (*s != *p)
-					return (*s == '\0')?2:1;
-				continue;
-			case '?':
-				/* Match anything. */
-				if (*s == '\0')
-					return (2);
-				continue;
-			case '*':
-				nostar = 0;	
-				/* Trailing star matches everything. */
-				return (*++p ? isdn_star(s, p) : 0);
-			case '[':
-				/* [^....] means inverse character class. */
-				if ((reverse = (p[1] == '^')))
+	if (!dev->drv[di])
+		return 0;
+	if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
+		if (sleep)
+			interruptible_sleep_on(sleep);
+		else
+			return 0;
+	}
+	if (len > dev->drv[di]->rcvcount[channel])
+		len = dev->drv[di]->rcvcount[channel];
+	cp = buf;
+	count = 0;
+	while (len) {
+		if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+			break;
+#ifdef CONFIG_ISDN_AUDIO
+		if (ISDN_AUDIO_SKB_LOCK(skb))
+			break;
+		ISDN_AUDIO_SKB_LOCK(skb) = 1;
+		if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
+			char *p = skb->data;
+			unsigned long DLEmask = (1 << channel);
+
+			dflag = 0;
+			count_pull = count_put = 0;
+			while ((count_pull < skb->len) && (len > 0)) {
+				len--;
+				if (dev->drv[di]->DLEflag & DLEmask) {
+					*cp++ = DLE;
+					dev->drv[di]->DLEflag &= ~DLEmask;
+				} else {
+					*cp++ = *p;
+					if (*p == DLE) {
+						dev->drv[di]->DLEflag |= DLEmask;
+						(ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+					}
 					p++;
-				for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
-					/* This next line requires a good C compiler. */
-					if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
-						matched = 1;
-				if (matched == reverse)
-					return (1);
-				continue;
+					count_pull++;
+				}
+				count_put++;
+			}
+			if (count_pull >= skb->len)
+				dflag = 1;
+		} else {
+#endif
+			/* No DLE's in buff, so simply copy it */
+			dflag = 1;
+			if ((count_pull = skb->len) > len) {
+				count_pull = len;
+				dflag = 0;
+			}
+			count_put = count_pull;
+			memcpy(cp, skb->data, count_put);
+			cp += count_put;
+			len -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
 		}
-	return (*s == '\0')?0:nostar;
-}
-
-int isdn_msncmp( const char * msn1, const char * msn2 )
-{
-	char TmpMsn1[ ISDN_MSNLEN ];
-	char TmpMsn2[ ISDN_MSNLEN ];
-	char *p;
-
-	for ( p = TmpMsn1; *msn1 && *msn1 != ':'; )  // Strip off a SPID
-		*p++ = *msn1++;
-	*p = '\0';
-
-	for ( p = TmpMsn2; *msn2 && *msn2 != ':'; )  // Strip off a SPID
-		*p++ = *msn2++;
-	*p = '\0';
-
-	return isdn_wildmat( TmpMsn1, TmpMsn2 );
-}
-
-static int
-__drv_command(struct isdn_driver *drv, isdn_ctrl *c)
-{
-#ifdef ISDN_DEBUG_COMMAND
-	switch (c->command) {
-	case ISDN_CMD_SETL2: 
-		printk(KERN_DEBUG "ISDN_CMD_SETL2 %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_SETL3: 
-		printk(KERN_DEBUG "ISDN_CMD_SETL3 %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_DIAL: 
-		printk(KERN_DEBUG "ISDN_CMD_DIAL %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_ACCEPTD: 
-		printk(KERN_DEBUG "ISDN_CMD_ACCEPTD %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_ACCEPTB: 
-		printk(KERN_DEBUG "ISDN_CMD_ACCEPTB %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_HANGUP: 
-		printk(KERN_DEBUG "ISDN_CMD_HANGUP %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_CLREAZ: 
-		printk(KERN_DEBUG "ISDN_CMD_CLREAZ %d/%ld\n", c->driver, c->arg & 0xff); break;
-	case ISDN_CMD_SETEAZ: 
-		printk(KERN_DEBUG "ISDN_CMD_SETEAZ %d/%ld\n", c->driver, c->arg & 0xff); break;
-	default:
-		printk(KERN_DEBUG "%s: cmd = %d\n", __FUNCTION__, c->command);
-	}
 #endif
-	return drv->interface->command(c);
-}
-
-static int
-__slot_command(struct isdn_slot *slot, isdn_ctrl *cmd)
-{
-	struct isdn_driver *drv = slot->drv;
-
-	return __drv_command(drv, cmd);
-}
-
-/*
- * Begin of a CAPI like LL<->HL interface, currently used only for 
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-
-int
-isdn_capi_rec_hl_msg(capi_msg *cm)
-{
-	switch(cm->Command) {
-	case CAPI_FACILITY:
-		/* in the moment only handled in tty */
-		return isdn_tty_capi_facility(cm);
-	default:
-		return -1;
+		count += count_put;
+		if (fp) {
+			memset(fp, 0, count_put);
+			fp += count_put;
+		}
+		if (dflag) {
+			/* We got all the data in this buff.
+			 * Now we can dequeue it.
+			 */
+			if (fp)
+				*(fp - 1) = 0xff;
+#ifdef CONFIG_ISDN_AUDIO
+			ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+			skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+			dev_kfree_skb(skb);
+		} else {
+			/* Not yet emptied this buff, so it
+			 * must stay in the queue, for further calls
+			 * but we pull off the data we got until now.
+			 */
+			skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+			ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+		}
+		dev->drv[di]->rcvcount[channel] -= count_put;
 	}
+	return count;
 }
 
-/*
- * Get integer from char-pointer, set pointer to end of number
- */
-int
-isdn_getnum(char **p)
+static __inline int
+isdn_minor2drv(int minor)
 {
-	int v = -1;
-
-	while (*p[0] >= '0' && *p[0] <= '9')
-		v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
-	return v;
+	return (dev->drvmap[minor]);
 }
 
-static struct isdn_slot *
-get_slot_by_minor(int minor)
+static __inline int
+isdn_minor2chan(int minor)
 {
-	int di, ch;
-	struct isdn_driver *drv;
-
-	for (di = 0; di < ISDN_MAX_DRIVERS; di++) {
-		drv = get_drv_by_nr(di);
-		if (!drv)
-			continue;
-
-		for (ch = 0; ch < drv->channels; ch++) {
-			if (minor-- == 0)
-				goto found;
-		}
-		put_drv(drv);
-	}
-	return NULL;
-
- found:
-	return drv->slots + ch;
-}
-
-static inline void
-put_slot(struct isdn_slot *slot)
-{
-	put_drv(slot->drv);
+	return (dev->chanmap[minor]);
 }
 
 static char *
 isdn_statstr(void)
 {
 	static char istatbuf[2048];
-	struct isdn_slot *slot;
 	char *p;
 	int i;
 
 	sprintf(istatbuf, "idmap:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "%s ", slot->drv->id);
-			put_slot(slot);
-		} else {
-			sprintf(p, "- ");
-		}
+		sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
 		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\nchmap:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "%d ", slot->ch);
-			put_slot(slot);
-		} else {
-			sprintf(p, "-1 ");
-		}
+		sprintf(p, "%d ", dev->chanmap[i]);
 		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\ndrmap:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "%d ", slot->di);
-			put_slot(slot);
-		} else {
-			sprintf(p, "-1 ");
-		}
+		sprintf(p, "%d ", dev->drvmap[i]);
+		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\nusage:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "%d ", slot->usage);
-			put_slot(slot);
-		} else {
-			sprintf(p, "0 ");
-		}
+		sprintf(p, "%d ", dev->usage[i]);
 		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\nflags:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "0 ");
-			put_slot(slot);
+		if (dev->drv[i]) {
+			sprintf(p, "%ld ", dev->drv[i]->online);
+			p = istatbuf + strlen(istatbuf);
 		} else {
 			sprintf(p, "? ");
+			p = istatbuf + strlen(istatbuf);
 		}
-		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\nphone:\t");
 	p = istatbuf + strlen(istatbuf);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		slot = get_slot_by_minor(i);
-		if (slot) {
-			sprintf(p, "%s ", slot->num);
-			put_slot(slot);
-		} else {
-			sprintf(p, " ");
-		}
+		sprintf(p, "%s ", dev->num[i]);
 		p = istatbuf + strlen(istatbuf);
 	}
 	sprintf(p, "\n");
 	return istatbuf;
 }
 
-/* 
- * /dev/isdninfo
- */
+/* Module interface-code */
 
 void
 isdn_info_update(void)
 {
-	infostruct *p = isdndev->infochain;
-
-	while (p) {
-		*(p->private) = 1;
-		p = (infostruct *) p->next;
-	}
-	wake_up_interruptible(&(isdndev->info_waitq));
-}
-
-static int
-isdn_status_open(struct inode *ino, struct file *filep)
-{
-	infostruct *p;
-	
-	p = kmalloc(sizeof(infostruct), GFP_KERNEL);
-	if (!p)
-		return -ENOMEM;
-
-	p->next = (char *) isdndev->infochain;
-	p->private = (char *) &(filep->private_data);
-	isdndev->infochain = p;
-	/* At opening we allow a single update */
-	filep->private_data = (char *) 1;
-
-	return 0;
-}
-
-static int
-isdn_status_release(struct inode *ino, struct file *filep)
-{
-	infostruct *p = isdndev->infochain;
-	infostruct *q = NULL;
-	
-	lock_kernel();
-
-	while (p) {
-		if (p->private == (char *) &(filep->private_data)) {
-			if (q)
-				q->next = p->next;
-			else
-				isdndev->infochain = (infostruct *) (p->next);
-			kfree(p);
-			goto out;
-		}
-		q = p;
-		p = (infostruct *) (p->next);
-	}
-	printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+	infostruct *p = dev->infochain;
 
- out:
-	unlock_kernel();
-	return 0;
+	while (p) {
+		*(p->private) = 1;
+		p = (infostruct *) p->next;
+	}
+	wake_up_interruptible(&(dev->info_waitq));
 }
 
 static ssize_t
-isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
+	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	int len = 0;
+	int drvidx;
+	int chidx;
 	int retval;
-	size_t len = 0;
 	char *p;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
-	if (!file->private_data) {
-		if (file->f_flags & O_NONBLOCK)
-			return  -EAGAIN;
-		interruptible_sleep_on(&(isdndev->info_waitq));
-	}
 	lock_kernel();
-	p = isdn_statstr();
-	file->private_data = 0;
-	if ((len = strlen(p)) <= count) {
-		if (copy_to_user(buf, p, len)) {
-			retval = -EFAULT;
+	if (minor == ISDN_MINOR_STATUS) {
+		if (!file->private_data) {
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
+			interruptible_sleep_on(&(dev->info_waitq));
+		}
+		p = isdn_statstr();
+		file->private_data = 0;
+		if ((len = strlen(p)) <= count) {
+			if (copy_to_user(buf, p, len)) {
+				retval = -EFAULT;
+				goto out;
+			}
+			*off += len;
+			retval = len;
+			goto out;
+		}
+		retval = 0;
+		goto out;
+	}
+	if (!dev->drivers) {
+		retval = -ENODEV;
+		goto out;
+	}
+	if (minor <= ISDN_MINOR_BMAX) {
+		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
+		drvidx = isdn_minor2drv(minor);
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
 			goto out;
 		}
+		chidx = isdn_minor2chan(minor);
+		if (!(p = kmalloc(count, GFP_KERNEL))) {
+			retval = -ENOMEM;
+			goto out;
+		}
+		len = isdn_readbchan(drvidx, chidx, p, 0, count,
+				     &dev->drv[drvidx]->rcv_waitq[chidx]);
 		*off += len;
+		if (copy_to_user(buf,p,len)) 
+			len = -EFAULT;
+		kfree(p);
 		retval = len;
 		goto out;
 	}
-	retval = 0;
-	goto out;
-
+	if (minor <= ISDN_MINOR_CTRLMAX) {
+		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!dev->drv[drvidx]->stavail) {
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
+			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+		}
+		if (dev->drv[drvidx]->interface->readstat) {
+			if (count > dev->drv[drvidx]->stavail)
+				count = dev->drv[drvidx]->stavail;
+			len = dev->drv[drvidx]->interface->
+				readstat(buf, count, 1, drvidx,
+					 isdn_minor2chan(minor));
+		} else {
+			len = 0;
+		}
+		if (len)
+			dev->drv[drvidx]->stavail -= len;
+		else
+			dev->drv[drvidx]->stavail = 0;
+		*off += len;
+		retval = len;
+		goto out;
+	}
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
+		goto out;
+	}
+#endif
+	retval = -ENODEV;
  out:
 	unlock_kernel();
 	return retval;
 }
 
 static ssize_t
-isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
-{
-	return -EPERM;
-}
-
-static unsigned int
-isdn_status_poll(struct file *file, poll_table *wait)
-{
-	unsigned int mask = 0;
-
-	poll_wait(file, &(isdndev->info_waitq), wait);
-	lock_kernel();
-	if (file->private_data)
-		mask |= POLLIN | POLLRDNORM;
-	unlock_kernel();
-	return mask;
-}
-
-static int
-isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
-{
-	static unsigned long zero_ul = 0UL;
-	int ret;
-	struct isdn_slot *slot;
-
-	switch (cmd) {
-	case IIOCGETDVR:
-		return (TTY_DV +
-			(NET_DV << 8) +
-			(INF_DV << 16));
-	case IIOCGETCPS:
-		if (arg) {
-			ulong *p = (ulong *) arg;
-			int i;
-			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-				return ret;
-			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-				slot = get_slot_by_minor(i);
-				if (slot) {
-					put_user(slot->ibytes, p++);
-					put_user(slot->obytes, p++);
-					put_slot(slot);
-				} else {
-					put_user(zero_ul, p++);
-					put_user(zero_ul, p++);
-				}
-			}
-			return 0;
-		} else
-			return -EINVAL;
-		break;
-	case IIOCNETGPN:
-		return isdn_net_ioctl(inode, file, cmd, arg);
-	default:
-		return -EINVAL;
-	}
-}
-
-static struct file_operations isdn_status_fops =
-{
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= isdn_status_read,
-	.write		= isdn_status_write,
-	.poll		= isdn_status_poll,
-	.ioctl		= isdn_status_ioctl,
-	.open		= isdn_status_open,
-	.release	= isdn_status_release,
-};
-
-/*
- * /dev/isdnctrlX
- */
-
-static int
-isdn_ctrl_open(struct inode *ino, struct file *file)
-{
-	unsigned int minor = iminor(ino);
-	struct isdn_slot *slot = get_slot_by_minor(minor - ISDN_MINOR_CTRL);
-
-	if (!slot)
-		return -ENODEV;
-
-	isdn_lock_driver(slot->drv);
-	file->private_data = slot;
-
-	return 0;
-}
-
-static int
-isdn_ctrl_release(struct inode *ino, struct file *file)
-{
-	struct isdn_slot *slot = file->private_data;
-
-	if (isdndev->profd == current)
-		isdndev->profd = NULL;
-
-	isdn_unlock_driver(slot->drv);
-	put_slot(slot);
-
-	return 0;
-}
-
-static ssize_t
-isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
 {
-	struct isdn_slot *slot = file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	size_t len = 0;
+	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+	int chidx;
+	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
-	if (!slot->drv->interface->readstat) {
-		isdn_BUG();
-		return 0;
-	}
- 	add_wait_queue(&slot->drv->st_waitq, &wait);
-	for (;;) {
-		spin_lock_irqsave(&stat_lock, flags);
-		len = slot->drv->stavail;
-		spin_unlock_irqrestore(&stat_lock, flags);
-		if (len > 0)
-			break;
-		if (signal_pending(current)) {
-			len = -ERESTARTSYS;
-			break;
+	if (minor == ISDN_MINOR_STATUS)
+		return -EPERM;
+	if (!dev->drivers)
+		return -ENODEV;
+
+	lock_kernel();
+	if (minor <= ISDN_MINOR_BMAX) {
+		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
+		drvidx = isdn_minor2drv(minor);
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
 		}
-		if (file->f_flags & O_NONBLOCK) {
-			len = -EAGAIN;
-			break;
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
+			goto out;
 		}
-		schedule();
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&slot->drv->st_waitq, &wait);
-	
-	if (len < 0)
-		return len;
-	
-	if (count > len)
-		count = len;
-		
-	len = slot->drv->interface->readstat(buf, count, 1, slot->di, 
-					     slot->ch);
-
-	spin_lock_irqsave(&stat_lock, flags);
-	if (len) {
-		slot->drv->stavail -= len;
-	} else {
-		isdn_BUG();
-		slot->drv->stavail = 0;
+		chidx = isdn_minor2chan(minor);
+		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
+			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
+		retval = count;
+		goto out;
 	}
-	spin_unlock_irqrestore(&stat_lock, flags);
-
-	*off += len;
-	return len;
-}
-
-static ssize_t
-isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
-{
-	struct isdn_slot *slot = file->private_data;
-	int retval;
-
-	if (off != &file->f_pos) {
-		retval = -ESPIPE;
+	if (minor <= ISDN_MINOR_CTRLMAX) {
+		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		/*
+		 * We want to use the isdnctrl device to load the firmware
+		 *
+		 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
+		 return -ENODEV;
+		 */
+		if (dev->drv[drvidx]->interface->writecmd)
+			retval = dev->drv[drvidx]->interface->
+				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
+		else
+			retval = count;
 		goto out;
 	}
-	if (!slot->drv->interface->writecmd) {
-		retval = -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
 		goto out;
 	}
-	retval = slot->drv->interface->writecmd(buf, count, 1, slot->di, 
-						slot->ch);
-
+#endif
+	retval = -ENODEV;
  out:
+	unlock_kernel();
 	return retval;
 }
 
 static unsigned int
-isdn_ctrl_poll(struct file *file, poll_table *wait)
+isdn_poll(struct file *file, poll_table * wait)
 {
-	struct isdn_slot *slot = file->private_data;
 	unsigned int mask = 0;
+	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
-	poll_wait(file, &slot->drv->st_waitq, wait);
-	mask = POLLOUT | POLLWRNORM;
-	if (slot->drv->stavail)
-		mask |= POLLIN | POLLRDNORM;
-
+	lock_kernel();
+	if (minor == ISDN_MINOR_STATUS) {
+		poll_wait(file, &(dev->info_waitq), wait);
+		/* mask = POLLOUT | POLLWRNORM; */
+		if (file->private_data) {
+			mask |= POLLIN | POLLRDNORM;
+		}
+		goto out;
+	}
+	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+		if (drvidx < 0) {
+			/* driver deregistered while file open */
+			mask = POLLHUP;
+			goto out;
+		}
+		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+		mask = POLLOUT | POLLWRNORM;
+		if (dev->drv[drvidx]->stavail) {
+			mask |= POLLIN | POLLRDNORM;
+		}
+		goto out;
+	}
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		mask = isdn_ppp_poll(file, wait);
+		goto out;
+	}
+#endif
+	mask = POLLERR;
+ out:
+	unlock_kernel();
 	return mask;
 }
 
 
 static int
-isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
+	uint minor = MINOR(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
+	int chidx;
 	int ret;
 	int i;
 	char *p;
-	/* save stack space */
-	union {
-		char bname[20];
+	char *s;
+	union iocpar {
+		char name[10];
+		char bname[22];
 		isdn_ioctl_struct iocts;
+		isdn_net_ioctl_phone phone;
+		isdn_net_ioctl_cfg cfg;
 	} iocpar;
 
-#define iocts iocpar.iocts
+#define name  iocpar.name
 #define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
 
+	if (minor == ISDN_MINOR_STATUS) {
+		switch (cmd) {
+			case IIOCGETDVR:
+				return (TTY_DV +
+					(NET_DV << 8) +
+					(INF_DV << 16));
+			case IIOCGETCPS:
+				if (arg) {
+					ulong *p = (ulong *) arg;
+					int i;
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+						return ret;
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						put_user(dev->ibytes[i], p++);
+						put_user(dev->obytes[i], p++);
+					}
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+#ifdef CONFIG_NETDEVICES
+			case IIOCNETGPN:
+				/* Get peer phone number of a connected 
+				 * isdn network interface */
+				if (arg) {
+					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+						return -EFAULT;
+					return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+				} else
+					return -EINVAL;
+#endif
+			default:
+				return -EINVAL;
+		}
+	}
+	if (!dev->drivers)
+		return -ENODEV;
+	if (minor <= ISDN_MINOR_BMAX) {
+		drvidx = isdn_minor2drv(minor);
+		if (drvidx < 0)
+			return -ENODEV;
+		chidx = isdn_minor2chan(minor);
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
+			return -ENODEV;
+		return 0;
+	}
+	if (minor <= ISDN_MINOR_CTRLMAX) {
 /*
  * isdn net devices manage lots of configuration variables as linked lists.
  * Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1575,257 +1230,497 @@
  * manipulating the lists and ioctl's sleeping while accessing the lists
  * are serialized by means of a semaphore.
  */
-	switch (cmd) {
-	case IIOCNETAIF:
-	case IIOCNETASL:
-	case IIOCNETDIF:
-	case IIOCNETSCF:
-	case IIOCNETGCF:
-	case IIOCNETANM:
-	case IIOCNETGNM:
-	case IIOCNETDNM:
-	case IIOCNETDIL:
-	case IIOCNETALN:
-	case IIOCNETDLN:
-	case IIOCNETHUP:
-		return isdn_net_ioctl(inode, file, cmd, arg);
-	case IIOCSETVER:
-		isdndev->net_verbose = arg;
-		printk(KERN_INFO "isdn: Verbose-Level is %d\n", isdndev->net_verbose);
-		return 0;
-	case IIOCSETGST:
-		if (arg) {
-			isdndev->global_flags |= ISDN_GLOBAL_STOPPED;
-			isdn_net_hangup_all();
-		} else {
-			isdndev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-		}
-		return 0;
-	case IIOCSETBRJ:
-		drvidx = -1;
-		if (arg) {
-			char *p;
-			if (copy_from_user((char *) &iocts, (char *) arg,
-					   sizeof(isdn_ioctl_struct)))
-				return -EFAULT;
-			if (strlen(iocts.drvid)) {
-				if ((p = strchr(iocts.drvid, ',')))
-					*p = 0;
-				drvidx = isdn_drv_lookup(iocts.drvid);
-			}
-		}
-		if (drvidx == -1)
-			return -ENODEV;
-		if (iocts.arg)
-			drivers[drvidx]->flags |= DRV_FLAG_REJBUS;
-		else
-			drivers[drvidx]->flags &= ~DRV_FLAG_REJBUS;
-		return 0;
-	case IIOCSIGPRF:
-		isdndev->profd = current;
-		return 0;
-		break;
-	case IIOCGETPRF:
-		/* Get all Modem-Profiles */
-		if (arg) {
-			char *p = (char *) arg;
-			int i;
-
-			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-				if (copy_to_user(p, isdn_mdm.info[i].emu.profile,
-						 ISDN_MODEM_NUMREG))
-					return -EFAULT;
-				p += ISDN_MODEM_NUMREG;
-				if (copy_to_user(p, isdn_mdm.info[i].emu.pmsn, ISDN_MSNLEN))
-					return -EFAULT;
-				p += ISDN_MSNLEN;
-				if (copy_to_user(p, isdn_mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
-					return -EFAULT;
-				p += ISDN_LMSNLEN;
-			}
-			return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
-		} else
-			return -EINVAL;
-		break;
-	case IIOCSETPRF:
-		/* Set all Modem-Profiles */
-		if (arg) {
-			char *p = (char *) arg;
-			int i;
-
-			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-				if (copy_from_user(isdn_mdm.info[i].emu.profile, p,
-						   ISDN_MODEM_NUMREG))
+		switch (cmd) {
+			case IIOCNETDWRSET:
+				printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+				return(-EINVAL);
+			case IIOCNETLCR:
+				printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+				return -ENODEV;
+#ifdef CONFIG_NETDEVICES
+			case IIOCNETAIF:
+				/* Add a network-interface */
+				if (arg) {
+					if (copy_from_user(name, (char *) arg, sizeof(name)))
+						return -EFAULT;
+					s = name;
+				} else {
+					s = NULL;
+				}
+				ret = down_interruptible(&dev->sem);
+				if( ret ) return ret;
+				if ((s = isdn_net_new(s, NULL))) {
+					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+						ret = -EFAULT;
+					} else {
+						ret = 0;
+					}
+				} else
+					ret = -ENODEV;
+				up(&dev->sem);
+				return ret;
+			case IIOCNETASL:
+				/* Add a slave to a network-interface */
+				if (arg) {
+					if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+						return -EFAULT;
+				} else
+					return -EINVAL;
+				ret = down_interruptible(&dev->sem);
+				if( ret ) return ret;
+				if ((s = isdn_net_newslave(bname))) {
+					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+						ret = -EFAULT;
+					} else {
+						ret = 0;
+					}
+				} else
+					ret = -ENODEV;
+				up(&dev->sem);
+				return ret;
+			case IIOCNETDIF:
+				/* Delete a network-interface */
+				if (arg) {
+					if (copy_from_user(name, (char *) arg, sizeof(name)))
+						return -EFAULT;
+					ret = down_interruptible(&dev->sem);
+					if( ret ) return ret;
+					ret = isdn_net_rm(name);
+					up(&dev->sem);
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETSCF:
+				/* Set configurable parameters of a network-interface */
+				if (arg) {
+					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+						return -EFAULT;
+					return isdn_net_setcfg(&cfg);
+				} else
+					return -EINVAL;
+			case IIOCNETGCF:
+				/* Get configurable parameters of a network-interface */
+				if (arg) {
+					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+						return -EFAULT;
+					if (!(ret = isdn_net_getcfg(&cfg))) {
+						if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+							return -EFAULT;
+					}
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETANM:
+				/* Add a phone-number to a network-interface */
+				if (arg) {
+					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+						return -EFAULT;
+					ret = down_interruptible(&dev->sem);
+					if( ret ) return ret;
+					ret = isdn_net_addphone(&phone);
+					up(&dev->sem);
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETGNM:
+				/* Get list of phone-numbers of a network-interface */
+				if (arg) {
+					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+						return -EFAULT;
+					ret = down_interruptible(&dev->sem);
+					if( ret ) return ret;
+					ret = isdn_net_getphones(&phone, (char *) arg);
+					up(&dev->sem);
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETDNM:
+				/* Delete a phone-number of a network-interface */
+				if (arg) {
+					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+						return -EFAULT;
+					ret = down_interruptible(&dev->sem);
+					if( ret ) return ret;
+					ret = isdn_net_delphone(&phone);
+					up(&dev->sem);
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETDIL:
+				/* Force dialing of a network-interface */
+				if (arg) {
+					if (copy_from_user(name, (char *) arg, sizeof(name)))
+						return -EFAULT;
+					return isdn_net_force_dial(name);
+				} else
+					return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+			case IIOCNETALN:
+				if (!arg)
+					return -EINVAL;
+				if (copy_from_user(name, (char *) arg, sizeof(name)))
 					return -EFAULT;
-				p += ISDN_MODEM_NUMREG;
-				if (copy_from_user(isdn_mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
+				return isdn_ppp_dial_slave(name);
+			case IIOCNETDLN:
+				if (!arg)
+					return -EINVAL;
+				if (copy_from_user(name, (char *) arg, sizeof(name)))
 					return -EFAULT;
-				p += ISDN_LMSNLEN;
-				if (copy_from_user(isdn_mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
+				return isdn_ppp_hangup_slave(name);
+#endif
+			case IIOCNETHUP:
+				/* Force hangup of a network-interface */
+				if (!arg)
+					return -EINVAL;
+				if (copy_from_user(name, (char *) arg, sizeof(name)))
 					return -EFAULT;
-				p += ISDN_MSNLEN;
-			}
-			return 0;
-		} else
-			return -EINVAL;
-		break;
-	case IIOCSETMAP:
-	case IIOCGETMAP:
-		/* Set/Get MSN->EAZ-Mapping for a driver */
-		if (arg) {
-
-			if (copy_from_user((char *) &iocts,
-					   (char *) arg,
-					   sizeof(isdn_ioctl_struct)))
-				return -EFAULT;
-			drvidx = isdn_drv_lookup(iocts.drvid);
-			if (drvidx == -1)
-				return -ENODEV;
-			if (cmd == IIOCSETMAP) {
-				int loop = 1;
-
-				p = (char *) iocts.arg;
-				i = 0;
-				while (loop) {
-					int j = 0;
-
-					while (1) {
-						if ((ret = get_user(bname[j], p++)))
-							return ret;
-						switch (bname[j]) {
-						case '\0':
-							loop = 0;
-							/* Fall through */
-						case ',':
-							bname[j] = '\0';
-							strcpy(drivers[drvidx]->msn2eaz[i], bname);
-							j = ISDN_MSNLEN;
-							break;
-						default:
-							j++;
-						}
-						if (j >= ISDN_MSNLEN)
-							break;
+				return isdn_net_force_hangup(name);
+				break;
+#endif                          /* CONFIG_NETDEVICES */
+			case IIOCSETVER:
+				dev->net_verbose = arg;
+				printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+				return 0;
+			case IIOCSETGST:
+				if (arg)
+					dev->global_flags |= ISDN_GLOBAL_STOPPED;
+				else
+					dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+				printk(KERN_INFO "isdn: Global Mode %s\n",
+				       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+				return 0;
+			case IIOCSETBRJ:
+				drvidx = -1;
+				if (arg) {
+					int i;
+					char *p;
+					if (copy_from_user((char *) &iocts, (char *) arg,
+					     sizeof(isdn_ioctl_struct)))
+						return -EFAULT;
+					if (strlen(iocts.drvid)) {
+						if ((p = strchr(iocts.drvid, ',')))
+							*p = 0;
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
 					}
-					if (++i > 9)
-						break;
 				}
-			} else {
-				p = (char *) iocts.arg;
-				for (i = 0; i < 10; i++) {
-					sprintf(bname, "%s%s",
-						strlen(drivers[drvidx]->msn2eaz[i]) ?
-						drivers[drvidx]->msn2eaz[i] : "_",
-						(i < 9) ? "," : "\0");
-					if (copy_to_user(p, bname, strlen(bname) + 1))
+				if (drvidx == -1)
+					return -ENODEV;
+				if (iocts.arg)
+					dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+				else
+					dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+				return 0;
+			case IIOCSIGPRF:
+				dev->profd = current;
+				return 0;
+				break;
+			case IIOCGETPRF:
+				/* Get all Modem-Profiles */
+				if (arg) {
+					char *p = (char *) arg;
+					int i;
+
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+						   * ISDN_MAX_CHANNELS)))
+						return ret;
+
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+						      ISDN_MODEM_NUMREG))
+							return -EFAULT;
+						p += ISDN_MODEM_NUMREG;
+						if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+							return -EFAULT;
+						p += ISDN_MSNLEN;
+						if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+							return -EFAULT;
+						p += ISDN_LMSNLEN;
+					}
+					return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+				} else
+					return -EINVAL;
+				break;
+			case IIOCSETPRF:
+				/* Set all Modem-Profiles */
+				if (arg) {
+					char *p = (char *) arg;
+					int i;
+
+					if ((ret = verify_area(VERIFY_READ, (void *) arg,
+					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+						   * ISDN_MAX_CHANNELS)))
+						return ret;
+
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+						     ISDN_MODEM_NUMREG))
+							return -EFAULT;
+						p += ISDN_MODEM_NUMREG;
+						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
+							return -EFAULT;
+						p += ISDN_LMSNLEN;
+						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
+							return -EFAULT;
+						p += ISDN_MSNLEN;
+					}
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			case IIOCSETMAP:
+			case IIOCGETMAP:
+				/* Set/Get MSN->EAZ-Mapping for a driver */
+				if (arg) {
+
+					if (copy_from_user((char *) &iocts,
+							    (char *) arg,
+					     sizeof(isdn_ioctl_struct)))
 						return -EFAULT;
-					p += strlen(bname);
-				}
-			}
-			return 0;
-		} else
-			return -EINVAL;
-	case IIOCDBGVAR:
-		if (arg) {
-			if (copy_to_user((char *) arg, (char *) &isdndev, sizeof(ulong)))
-				return -EFAULT;
-			return 0;
-		} else
-			return -EINVAL;
-		break;
-	default:
-		if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
-			cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
-		else
-			return -EINVAL;
-		if (arg) {
-			if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
-				return -EFAULT;
-			drvidx = isdn_drv_lookup(iocts.drvid);
-			if (drvidx == -1)
-				return -ENODEV;
-			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					       sizeof(isdn_ioctl_struct))))
-				return ret;
-			c.driver = drvidx;
-			c.command = ISDN_CMD_IOCTL;
-			c.arg = cmd;
-			memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-			ret = __drv_command(drivers[drvidx], &c);
-			memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
-			if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
-				return -EFAULT;
-			return ret;
-		} else
-			return -EINVAL;
+					if (strlen(iocts.drvid)) {
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
+					} else
+						drvidx = 0;
+					if (drvidx == -1)
+						return -ENODEV;
+					if (cmd == IIOCSETMAP) {
+						int loop = 1;
+
+						p = (char *) iocts.arg;
+						i = 0;
+						while (loop) {
+							int j = 0;
+
+							while (1) {
+								if ((ret = verify_area(VERIFY_READ, p, 1)))
+									return ret;
+								get_user(bname[j], p++);
+								switch (bname[j]) {
+									case '\0':
+										loop = 0;
+										/* Fall through */
+									case ',':
+										bname[j] = '\0';
+										strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+										j = ISDN_MSNLEN;
+										break;
+									default:
+										j++;
+								}
+								if (j >= ISDN_MSNLEN)
+									break;
+							}
+							if (++i > 9)
+								break;
+						}
+					} else {
+						p = (char *) iocts.arg;
+						for (i = 0; i < 10; i++) {
+							sprintf(bname, "%s%s",
+								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+								dev->drv[drvidx]->msn2eaz[i] : "_",
+								(i < 9) ? "," : "\0");
+							if (copy_to_user(p, bname, strlen(bname) + 1))
+								return -EFAULT;
+							p += strlen(bname);
+						}
+					}
+					return 0;
+				} else
+					return -EINVAL;
+			case IIOCDBGVAR:
+				if (arg) {
+					if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+						return -EFAULT;
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+					cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+				else
+					return -EINVAL;
+				if (arg) {
+					int i;
+					char *p;
+					if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+						return -EFAULT;
+					if (strlen(iocts.drvid)) {
+						if ((p = strchr(iocts.drvid, ',')))
+							*p = 0;
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
+					} else
+						drvidx = 0;
+					if (drvidx == -1)
+						return -ENODEV;
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					     sizeof(isdn_ioctl_struct))))
+						return ret;
+					c.driver = drvidx;
+					c.command = ISDN_CMD_IOCTL;
+					c.arg = cmd;
+					memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+					ret = isdn_command(&c);
+					memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+					if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+						return -EFAULT;
+					return ret;
+				} else
+					return -EINVAL;
+		}
 	}
-#undef iocts
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
+#endif
+	return -ENODEV;
+
+#undef name
 #undef bname
+#undef iocts
+#undef phone
+#undef cfg
 }
 
-static struct file_operations isdn_ctrl_fops =
-{
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= isdn_ctrl_read,
-	.write		= isdn_ctrl_write,
-	.poll		= isdn_ctrl_poll,
-	.ioctl		= isdn_ctrl_ioctl,
-	.open		= isdn_ctrl_open,
-	.release	= isdn_ctrl_release,
-};
-
-
 /*
- * file_operations for major 45, /dev/isdn*
- * stolen from drivers/char/misc.c
+ * Open the device code.
  */
-
 static int
-isdn_open(struct inode * inode, struct file * file)
+isdn_open(struct inode *ino, struct file *filep)
 {
-	int minor = iminor(inode);
-	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
-	
-	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX)
-		new_fops = fops_get(&isdn_ctrl_fops);
+	uint minor = MINOR(ino->i_rdev);
+	int drvidx;
+	int chidx;
+	int retval = -ENODEV;
+
+
+	if (minor == ISDN_MINOR_STATUS) {
+		infostruct *p;
+
+		if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
+			p->next = (char *) dev->infochain;
+			p->private = (char *) &(filep->private_data);
+			dev->infochain = p;
+			/* At opening we allow a single update */
+			filep->private_data = (char *) 1;
+			retval = 0;
+			goto out;
+		} else {
+			retval = -ENOMEM;
+			goto out;
+		}
+	}
+	if (!dev->channels)
+		goto out;
+	if (minor <= ISDN_MINOR_BMAX) {
+		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
+		drvidx = isdn_minor2drv(minor);
+		if (drvidx < 0)
+			goto out;
+		chidx = isdn_minor2chan(minor);
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
+			goto out;
+		if (!(dev->drv[drvidx]->online & (1 << chidx)))
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
+	}
+	if (minor <= ISDN_MINOR_CTRLMAX) {
+		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+		if (drvidx < 0)
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
+	}
 #ifdef CONFIG_ISDN_PPP
-	else if (minor >= ISDN_MINOR_PPP && minor <= ISDN_MINOR_PPPMAX)
-		new_fops = fops_get(&isdn_ppp_fops);
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
+		if (retval == 0)
+			isdn_lock_drivers();
+		goto out;
+	}
 #endif
-	else if (minor == ISDN_MINOR_STATUS)
-		new_fops = fops_get(&isdn_status_fops);
+ out:
+	return retval;
+}
 
-	if (!new_fops)
-		goto out;
+static int
+isdn_close(struct inode *ino, struct file *filep)
+{
+	uint minor = MINOR(ino->i_rdev);
 
-	err = 0;
-	old_fops = file->f_op;
-	file->f_op = new_fops;
-	if (file->f_op->open) {
-		err = file->f_op->open(inode,file);
-		if (err) {
-			fops_put(file->f_op);
-			file->f_op = fops_get(old_fops);
+	lock_kernel();
+	if (minor == ISDN_MINOR_STATUS) {
+		infostruct *p = dev->infochain;
+		infostruct *q = NULL;
+
+		while (p) {
+			if (p->private == (char *) &(filep->private_data)) {
+				if (q)
+					q->next = p->next;
+				else
+					dev->infochain = (infostruct *) (p->next);
+				kfree(p);
+				goto out;
+			}
+			q = p;
+			p = (infostruct *) (p->next);
 		}
+		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+		goto out;
+	}
+	isdn_unlock_drivers();
+	if (minor <= ISDN_MINOR_BMAX)
+		goto out;
+	if (minor <= ISDN_MINOR_CTRLMAX) {
+		if (dev->profd == current)
+			dev->profd = NULL;
+		goto out;
 	}
-	fops_put(old_fops);
-	
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+#endif
+
  out:
-	return err;
+	unlock_kernel();
+	return 0;
 }
 
 static struct file_operations isdn_fops =
 {
-	.owner		= THIS_MODULE,
-	.open		= isdn_open,
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		isdn_read,
+	write:		isdn_write,
+	poll:		isdn_poll,
+	ioctl:		isdn_ioctl,
+	open:		isdn_open,
+	release:	isdn_close,
 };
 
 char *
 isdn_map_eaz2msn(char *msn, int di)
 {
-	struct isdn_driver *this = drivers[di];
+	isdn_driver_t *this = dev->drv[di];
 	int i;
 
 	if (strlen(msn) == 1) {
@@ -1841,118 +1736,281 @@
  * Find an unused ISDN-channel, whose feature-flags match the
  * given L2- and L3-protocols.
  */
-struct isdn_slot *
-isdn_get_free_slot(int usage, int l2_proto, int l3_proto,
-		   int pre_dev, int pre_chan, char *msn)
-{
-	struct isdn_driver *drv;
-	struct isdn_slot *slot;
-	int di, ch;
-	unsigned long flags;
-	unsigned long features;
-
-	features = ((1 << l2_proto) | (0x10000 << l3_proto));
-
-	for (di = 0; di < ISDN_MAX_DRIVERS; di++) {
-		if (pre_dev >= 0 && pre_dev != di)
-			continue;
-
-		drv = get_drv_by_nr(di);
-		if (!drv)
-			continue;
-
-		if (drv->fi.state != ST_DRV_RUNNING)
-			goto put;
-
-		if ((drv->features & features) != features)
-			goto put;
-
-		spin_lock_irqsave(&drv->lock, flags);
-		for (ch = 0; ch < drv->channels; ch++) {
-			if (pre_chan >= 0 && pre_chan != ch)
-				continue;
+#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
 
-			slot = &drv->slots[ch];
+/*
+ * This function must be called with holding the dev->lock.
+ */
+int
+isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
+		      ,int pre_chan, char *msn)
+{
+	int i;
+	ulong features;
+	ulong vfeatures;
 
-			if (!USG_NONE(slot->usage))
+	features = ((1 << l2_proto) | (0x10000 << l3_proto));
+	vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
+		     ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
+	/* If Layer-2 protocol is V.110, accept drivers with
+	 * transparent feature even if these don't support V.110
+	 * because we can emulate this in linklevel.
+	 */
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		if (USG_NONE(dev->usage[i]) &&
+		    (dev->drvmap[i] != -1)) {
+			int d = dev->drvmap[i];
+			if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
+			((pre_dev != d) || (pre_chan != dev->chanmap[i])))
 				continue;
-
-			if (slot->usage & ISDN_USAGE_DISABLED)
+			if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
 				continue;
+			if (dev->usage[i] & ISDN_USAGE_DISABLED)
+			        continue; /* usage not allowed */
+			if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
+				if (((dev->drv[d]->interface->features & features) == features) ||
+				    (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
+				     (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
+					if ((pre_dev < 0) || (pre_chan < 0)) {
+						dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
+						dev->usage[i] |= usage;
+						isdn_info_update();
+						return i;
+					} else {
+						if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
+							dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
+							dev->usage[i] |= usage;
+							isdn_info_update();
+							return i;
+						}
+					}
+				}
+			}
+		}
+	return -1;
+}
 
-			if (strcmp(isdn_map_eaz2msn(msn, drv->di), "-") == 0)
-				continue;
+/*
+ * Set state of ISDN-channel to 'unused'
+ */
+void
+isdn_free_channel(int di, int ch, int usage)
+{
+	int i;
 
-			goto found;
-			
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
+		    (dev->drvmap[i] == di) &&
+		    (dev->chanmap[i] == ch)) {
+			dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
+			strcpy(dev->num[i], "???");
+			dev->ibytes[i] = 0;
+			dev->obytes[i] = 0;
+// 20.10.99 JIM, try to reinitialize v110 !
+			dev->v110emu[i] = 0;
+			atomic_set(&(dev->v110use[i]), 0);
+			isdn_v110_close(dev->v110[i]);
+			dev->v110[i] = NULL;
+// 20.10.99 JIM, try to reinitialize v110 !
+			isdn_info_update();
+			skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
 		}
-		spin_unlock_irqrestore(&drv->lock, flags);
-
-	put:
-		put_drv(drv);
-	}
-	return NULL;
+}
 
- found:
-	slot->usage = usage;
-	spin_unlock_irqrestore(&drv->lock, flags);
+/*
+ * Cancel Exclusive-Flag for ISDN-channel
+ */
+void
+isdn_unexclusive_channel(int di, int ch)
+{
+	int i;
 
-	isdn_info_update();
-	fsm_event(&slot->fi, EV_SLOT_BIND, NULL);
-	return slot;
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		if ((dev->drvmap[i] == di) &&
+		    (dev->chanmap[i] == ch)) {
+			dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
+			isdn_info_update();
+			return;
+		}
 }
 
 /*
- * Set state of ISDN-channel to 'unused'
+ *  writebuf replacement for SKB_ABLE drivers
  */
-void
-isdn_slot_free(struct isdn_slot *slot)
+static int
+isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
+		   int user)
 {
-	fsm_event(&slot->fi, EV_SLOT_UNBIND, NULL);
+	int ret;
+	int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+	struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
+
+	if (!skb)
+		return 0;
+	skb_reserve(skb, hl);
+	if (user)
+		copy_from_user(skb_put(skb, len), buf, len);
+	else
+		memcpy(skb_put(skb, len), buf, len);
+	ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
+	if (ret <= 0)
+		dev_kfree_skb(skb);
+	if (ret > 0)
+		dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
+	return ret;
 }
 
 /*
  * Return: length of data on success, -ERRcode on failure.
  */
 int
-isdn_slot_write(struct isdn_slot *slot, struct sk_buff *skb)
+isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
 {
-	return fsm_event(&slot->fi, EV_DATA_REQ, skb);
+	int ret;
+	struct sk_buff *nskb = NULL;
+	int v110_ret = skb->len;
+	int idx = isdn_dc2minor(drvidx, chan);
+
+	if (dev->v110[idx]) {
+		atomic_inc(&dev->v110use[idx]);
+		nskb = isdn_v110_encode(dev->v110[idx], skb);
+		atomic_dec(&dev->v110use[idx]);
+		if (!nskb)
+			return 0;
+		v110_ret = *((int *)nskb->data);
+		skb_pull(nskb, sizeof(int));
+		if (!nskb->len) {
+			dev_kfree_skb(nskb);
+			return v110_ret;
+		}
+		/* V.110 must always be acknowledged */
+		ack = 1;
+		ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
+	} else {
+		int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+
+		if( skb_headroom(skb) < hl ){
+			/* 
+			 * This should only occur when new HL driver with
+			 * increased hl_hdrlen was loaded after netdevice
+			 * was created and connected to the new driver.
+			 *
+			 * The V.110 branch (re-allocates on its own) does
+			 * not need this
+			 */
+			struct sk_buff * skb_tmp;
+
+			skb_tmp = skb_realloc_headroom(skb, hl);
+			printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
+			if (!skb_tmp) return -ENOMEM; /* 0 better? */
+			ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
+			if( ret > 0 ){
+				dev_kfree_skb(skb);
+			} else {
+				dev_kfree_skb(skb_tmp);
+			}
+		} else {
+			ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+		}
+	}
+	if (ret > 0) {
+		dev->obytes[idx] += ret;
+		if (dev->v110[idx]) {
+			atomic_inc(&dev->v110use[idx]);
+			dev->v110[idx]->skbuser++;
+			atomic_dec(&dev->v110use[idx]);
+			/* For V.110 return unencoded data length */
+			ret = v110_ret;
+			/* if the complete frame was send we free the skb;
+			   if not upper function will requeue the skb */ 
+			if (ret == skb->len)
+				dev_kfree_skb(skb);
+		}
+	} else
+		if (dev->v110[idx])
+			dev_kfree_skb(nskb);
+	return ret;
 }
 
-static int
-isdn_add_channels(struct isdn_driver *drv, int n)
+int
+isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
 {
-	struct isdn_slot *slot;
-	int ch;
+	int j, k, m;
 
-       	if (n < 1)
-		return 0;
+	init_waitqueue_head(&d->st_waitq);
+	if (d->flags & DRV_FLAG_RUNNING)
+		return -1;
+       	if (n < 1) return 0;
 
-	if (isdndev->channels + n > ISDN_MAX_CHANNELS) {
+	m = (adding) ? d->channels + n : n;
+
+	if (dev->channels + n > ISDN_MAX_CHANNELS) {
 		printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
 		       ISDN_MAX_CHANNELS);
-		return -EBUSY;
+		return -1;
 	}
-	isdndev->channels += n;
-	drv->slots = kmalloc(sizeof(struct isdn_slot) * n, GFP_ATOMIC);
-	if (!drv->slots)
-		return -ENOMEM;
-	memset(drv->slots, 0, sizeof(struct isdn_slot) * n);
-	for (ch = 0; ch < n; ch++) {
-		slot = drv->slots + ch;
-
-		slot->ch = ch;
-		slot->di = drv->di;
-		slot->drv = drv;
-		strcpy(slot->num, "???");
-		slot->fi.fsm = &slot_fsm;
-		slot->fi.state = ST_SLOT_NULL;
-		slot->fi.debug = 1;
-		slot->fi.userdata = slot;
-		slot->fi.printdebug = slot_debug;
+
+	if ((adding) && (d->rcverr))
+		kfree(d->rcverr);
+	if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+		printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
+		return -1;
+	}
+	memset((char *) d->rcverr, 0, sizeof(int) * m);
+
+	if ((adding) && (d->rcvcount))
+		kfree(d->rcvcount);
+	if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+		printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
+		if (!adding) kfree(d->rcverr);
+		return -1;
+	}
+	memset((char *) d->rcvcount, 0, sizeof(int) * m);
+
+	if ((adding) && (d->rpqueue)) {
+		for (j = 0; j < d->channels; j++)
+			skb_queue_purge(&d->rpqueue[j]);
+		kfree(d->rpqueue);
+	}
+	if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_ATOMIC))) {
+		printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+		if (!adding) {
+			kfree(d->rcvcount);
+			kfree(d->rcverr);
+		}
+		return -1; 
 	}
-	drv->channels = n;
+	for (j = 0; j < m; j++) {
+		skb_queue_head_init(&d->rpqueue[j]);
+	}
+
+	if ((adding) && (d->rcv_waitq))
+		kfree(d->rcv_waitq);
+	d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_ATOMIC);
+	if (!d->rcv_waitq) {
+		printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
+		if (!adding) {
+			kfree(d->rpqueue);
+			kfree(d->rcvcount);
+			kfree(d->rcverr);
+		}
+		return -1;
+	}
+	d->snd_waitq = d->rcv_waitq + m;
+	for (j = 0; j < m; j++) {
+		init_waitqueue_head(&d->rcv_waitq[j]);
+		init_waitqueue_head(&d->snd_waitq[j]);
+	}
+
+	dev->channels += n;
+	for (j = d->channels; j < m; j++)
+		for (k = 0; k < ISDN_MAX_CHANNELS; k++)
+			if (dev->chanmap[k] < 0) {
+				dev->chanmap[k] = j;
+				dev->drvmap[k] = drvidx;
+				break;
+			}
+	d->channels = m;
 	return 0;
 }
 
@@ -1960,63 +2018,68 @@
  * Low-level-driver registration
  */
 
-#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
+static void
+set_global_features(void)
+{
+	int drvidx;
+
+	dev->global_features = 0;
+	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+		if (!dev->drv[drvidx])
+			continue;
+		if (dev->drv[drvidx]->interface)
+			dev->global_features |= dev->drv[drvidx]->interface->features;
+	}
+}
+
+#ifdef CONFIG_ISDN_DIVERSION
 
-/*
- * map_drvname
- */
 static char *map_drvname(int di)
 {
-	if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) 
-		return(NULL);
-	return(isdndev->drvid[di]); /* driver name */
-}
+  if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) 
+    return(NULL);
+  return(dev->drvid[di]); /* driver name */
+} /* map_drvname */
 
-/*
- * map_namedrv
- */
 static int map_namedrv(char *id)
-{
-	int i;
+{  int i;
 
-	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
-		if (!strcmp(dev->drvid[i],id)) 
-			return(i);
-	}
-	return(-1);
-}
+   for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+    { if (!strcmp(dev->drvid[i],id)) 
+        return(i);
+    }
+   return(-1);
+} /* map_namedrv */
 
-/*
- * DIVERT_REG_NAME
- */
 int DIVERT_REG_NAME(isdn_divert_if *i_div)
 {
-	if (i_div->if_magic != DIVERT_IF_MAGIC) 
-		return(DIVERT_VER_ERR);
-	switch (i_div->cmd) {
-		case DIVERT_CMD_REL:
-			if (divert_if != i_div) 
-				return(DIVERT_REL_ERR);
-			divert_if = NULL; /* free interface */
-			MOD_DEC_USE_COUNT;
-			return(DIVERT_NO_ERR);
-		case DIVERT_CMD_REG:
-			if (divert_if) 
-				return(DIVERT_REG_ERR);
-			i_div->ll_cmd = isdn_command; /* set command function */
-			i_div->drv_to_name = map_drvname; 
-			i_div->name_to_drv = map_namedrv; 
-			MOD_INC_USE_COUNT;
-			divert_if = i_div; /* remember interface */
-			return(DIVERT_NO_ERR);
-		default:
-			return(DIVERT_CMD_ERR);   
-	}
-}
+  if (i_div->if_magic != DIVERT_IF_MAGIC) 
+    return(DIVERT_VER_ERR);
+  switch (i_div->cmd)
+    {
+      case DIVERT_CMD_REL:
+        if (divert_if != i_div) 
+          return(DIVERT_REL_ERR);
+        divert_if = NULL; /* free interface */
+        return(DIVERT_NO_ERR);
+
+      case DIVERT_CMD_REG:
+        if (divert_if) 
+          return(DIVERT_REG_ERR);
+        i_div->ll_cmd = isdn_command; /* set command function */
+        i_div->drv_to_name = map_drvname; 
+        i_div->name_to_drv = map_namedrv; 
+        divert_if = i_div; /* remember interface */
+        return(DIVERT_NO_ERR);
+
+      default:
+        return(DIVERT_CMD_ERR);   
+    }
+} /* DIVERT_REG_NAME */
 
 EXPORT_SYMBOL(DIVERT_REG_NAME);
 
-#endif
+#endif /* CONFIG_ISDN_DIVERSION */
 
 
 EXPORT_SYMBOL(register_isdn);
@@ -2026,159 +2089,80 @@
 #endif
 
 int
-isdn_slot_maxbufsize(struct isdn_slot *slot)
-{
-	return slot->drv->maxbufsize;
-}
-
-int
-isdn_slot_hdrlen(struct isdn_slot *slot)
-{
-	return slot->drv->interface->hl_hdrlen;
-}
-
-char *
-isdn_slot_map_eaz2msn(struct isdn_slot *slot, char *msn)
-{
-	return isdn_map_eaz2msn(msn, slot->di);
-}
-
-int
-isdn_slot_command(struct isdn_slot *slot, int cmd, isdn_ctrl *ctrl)
+register_isdn(isdn_if * i)
 {
-	ctrl->command = cmd;
-	ctrl->driver = slot->di;
+	isdn_driver_t *d;
+	int j;
+	ulong flags;
+	int drvidx;
 
-	switch (cmd) {
-	case ISDN_CMD_SETL2:
-	case ISDN_CMD_SETL3:
-	case ISDN_CMD_PROT_IO:
-		ctrl->arg &= ~0xff; ctrl->arg |= slot->ch;
-		break;
-	case ISDN_CMD_DIAL:
-		if (isdndev->global_flags & ISDN_GLOBAL_STOPPED)
-			return -EBUSY;
-
-		/* fall through */
-	default:
-		ctrl->arg = slot->ch;
-		break;
-	}
-	switch (cmd) {
-	case ISDN_CMD_CLREAZ:
-		return fsm_event(&slot->fi, EV_CMD_CLREAZ, ctrl);
-	case ISDN_CMD_SETEAZ:
-		return fsm_event(&slot->fi, EV_CMD_SETEAZ, ctrl);
-	case ISDN_CMD_SETL2:
-		return fsm_event(&slot->fi, EV_CMD_SETL2, ctrl);
-	case ISDN_CMD_SETL3:
-		return fsm_event(&slot->fi, EV_CMD_SETL3, ctrl);
-	case ISDN_CMD_DIAL:
-		return fsm_event(&slot->fi, EV_CMD_DIAL, ctrl);
-	case ISDN_CMD_ACCEPTD:
-		return fsm_event(&slot->fi, EV_CMD_ACCEPTD, ctrl);
-	case ISDN_CMD_ACCEPTB:
-		return fsm_event(&slot->fi, EV_CMD_ACCEPTB, ctrl);
-	case ISDN_CMD_HANGUP:
-		return fsm_event(&slot->fi, EV_CMD_HANGUP, ctrl);
+	if (dev->drivers >= ISDN_MAX_DRIVERS) {
+		printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
+		       ISDN_MAX_DRIVERS);
+		return 0;
 	}
-	HERE;
-	return -1;
-}
-
-int
-isdn_slot_dial(struct isdn_slot *slot, struct dial_info *dial)
-{
-	isdn_ctrl cmd;
-	int retval;
-	char *msn = isdn_slot_map_eaz2msn(slot, dial->msn);
-
-	/* check for DOV */
-	if (dial->si1 == 7 && tolower(dial->phone[0]) == 'v') { /* DOV call */
-		dial->si1 = 1;
-		dial->phone++; /* skip v/V */
+	if (!i->writebuf_skb) {
+		printk(KERN_WARNING "register_isdn: No write routine given.\n");
+		return 0;
 	}
+	if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
+		printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
+		return 0;
+	}
+	memset((char *) d, 0, sizeof(isdn_driver_t));
 
-	strcpy(slot->num, dial->phone);
-	slot->usage |= ISDN_USAGE_OUTGOING;
-	isdn_info_update();
-
-	retval = isdn_slot_command(slot, ISDN_CMD_CLREAZ, &cmd);
-	if (retval)
-		return retval;
-
-	strcpy(cmd.parm.num, msn);
-	retval = isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd);
-
-	cmd.arg = dial->l2_proto << 8;
-	cmd.parm.fax = dial->fax;
-	retval = isdn_slot_command(slot, ISDN_CMD_SETL2, &cmd);
-	if (retval)
-		return retval;
-
-	cmd.arg = dial->l3_proto << 8;
-	retval = isdn_slot_command(slot, ISDN_CMD_SETL3, &cmd);
-	if (retval)
-		return retval;
-
-	cmd.parm.setup.si1 = dial->si1;
-	cmd.parm.setup.si2 = dial->si2;
-	strcpy(cmd.parm.setup.eazmsn, msn);
-	strcpy(cmd.parm.setup.phone, dial->phone);
-
-	printk(KERN_INFO "ISDN: Dialing %s -> %s (SI %d/%d) (B %d/%d)\n",
-	       cmd.parm.setup.eazmsn, cmd.parm.setup.phone,
-	       cmd.parm.setup.si1, cmd.parm.setup.si2,
-	       dial->l2_proto, dial->l3_proto);
-
-	return isdn_slot_command(slot, ISDN_CMD_DIAL, &cmd);
-}
-
-int
-isdn_hard_header_len(void)
-{
-	int drvidx;
-	int max = 0;
-	
-	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
-		if (drivers[drvidx] && 
-		    max < drivers[drvidx]->interface->hl_hdrlen) {
-			max = drivers[drvidx]->interface->hl_hdrlen;
-		}
+	d->maxbufsize = i->maxbufsize;
+	d->pktcount = 0;
+	d->stavail = 0;
+	d->flags = DRV_FLAG_LOADED;
+	d->online = 0;
+	d->interface = i;
+	d->channels = 0;
+	spin_lock_irqsave(&dev->lock, flags);
+	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
+		if (!dev->drv[drvidx])
+			break;
+	if (isdn_add_channels(d, drvidx, i->channels, 0)) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		kfree(d);
+		return 0;
 	}
-	return max;
+	i->channels = drvidx;
+	i->rcvcallb_skb = isdn_receive_skb_callback;
+	i->statcallb = isdn_status_callback;
+	if (!strlen(i->id))
+		sprintf(i->id, "line%d", drvidx);
+	for (j = 0; j < drvidx; j++)
+		if (!strcmp(i->id, dev->drvid[j]))
+			sprintf(i->id, "line%d", drvidx);
+	dev->drv[drvidx] = d;
+	strcpy(dev->drvid[drvidx], i->id);
+	isdn_info_update();
+	dev->drivers++;
+	set_global_features();
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 1;
 }
 
-static void isdn_init_devfs(void)
-{
-	devfs_mk_dir("isdn");
+/*
+ *****************************************************************************
+ * And now the modules code.
+ *****************************************************************************
+ */
 
-#ifdef CONFIG_ISDN_PPP
+static char *
+isdn_getrev(const char *revision)
 {
-	int i;
-
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_PPP + i),
-				0600 | S_IFCHR, "isdn/ippp%d", i);
-}
-#endif
-
-	devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_STATUS),
-			0600 | S_IFCHR, "isdn/isdninfo");
-	devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_CTRL),
-			0600 | S_IFCHR, "isdn/isdnctrl");
-}
+	char *rev;
+	char *p;
 
-static void isdn_cleanup_devfs(void)
-{
-#ifdef CONFIG_ISDN_PPP
-	int i;
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++) 
-		devfs_remove("isdn/ippp%d", i);
-#endif
-	devfs_remove("isdn/isdninfo");
-	devfs_remove("isdn/isdnctrl");
-	devfs_remove("isdn");
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
 }
 
 /*
@@ -2186,64 +2170,72 @@
  */
 static int __init isdn_init(void)
 {
-	int retval;
-
-	retval = fsm_new(&slot_fsm);
-	if (retval)
-		goto err;
-
-	retval = fsm_new(&drv_fsm);
-	if (retval)
-		goto err_slot_fsm;
-
-	isdndev = vmalloc(sizeof(*isdndev));
-	if (!isdndev) {
-		retval = -ENOMEM;
-		goto err_drv_fsm;
-	}
-	memset(isdndev, 0, sizeof(*isdndev));
-	init_MUTEX(&isdndev->sem);
-	init_waitqueue_head(&isdndev->info_waitq);
+	int i;
+	char tmprev[50];
 
-	retval = register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops);
-	if (retval) {
+	if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
+		printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
+		return -EIO;
+	}
+	memset((char *) dev, 0, sizeof(isdn_dev));
+	init_timer(&dev->timer);
+	dev->timer.function = isdn_timer_funct;
+	spin_lock_init(&dev->lock);
+	spin_lock_init(&dev->timerlock);
+#ifdef MODULE
+	dev->owner = THIS_MODULE;
+#endif
+	init_MUTEX(&dev->sem);
+	init_waitqueue_head(&dev->info_waitq);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		dev->drvmap[i] = -1;
+		dev->chanmap[i] = -1;
+		dev->m_idx[i] = -1;
+		strcpy(dev->num[i], "???");
+		init_waitqueue_head(&dev->mdm.info[i].open_wait);
+		init_waitqueue_head(&dev->mdm.info[i].close_wait);
+	}
+	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
-		goto err_vfree;
+		vfree(dev);
+		return -EIO;
 	}
-	isdn_init_devfs();
-	retval = isdn_tty_init();
-	if (retval < 0) {
+	if ((isdn_tty_modem_init()) < 0) {
 		printk(KERN_WARNING "isdn: Could not register tty devices\n");
-		goto err_cleanup_devfs;
+		vfree(dev);
+		unregister_chrdev(ISDN_MAJOR, "isdn");
+		return -EIO;
 	}
 #ifdef CONFIG_ISDN_PPP
-	retval = isdn_ppp_init();
-	if (retval < 0) {
+	if (isdn_ppp_init() < 0) {
 		printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
-		goto err_tty_modem;
+		isdn_tty_exit();
+		unregister_chrdev(ISDN_MAJOR, "isdn");
+		vfree(dev);
+		return -EIO;
 	}
 #endif                          /* CONFIG_ISDN_PPP */
 
-	isdn_net_lib_init();
-	printk(KERN_NOTICE "ISDN subsystem initialized\n");
-	isdn_info_update();
-	return 0;
+	strcpy(tmprev, isdn_revision);
+	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
+	strcpy(tmprev, isdn_tty_revision);
+	printk("%s/", isdn_getrev(tmprev));
+	strcpy(tmprev, isdn_net_revision);
+	printk("%s/", isdn_getrev(tmprev));
+	strcpy(tmprev, isdn_ppp_revision);
+	printk("%s/", isdn_getrev(tmprev));
+	strcpy(tmprev, isdn_audio_revision);
+	printk("%s/", isdn_getrev(tmprev));
+	strcpy(tmprev, isdn_v110_revision);
+	printk("%s", isdn_getrev(tmprev));
 
-#ifdef CONFIG_ISDN_PPP
- err_tty_modem:
-	isdn_tty_exit();
+#ifdef MODULE
+	printk(" loaded\n");
+#else
+	printk("\n");
 #endif
- err_cleanup_devfs:
-	isdn_cleanup_devfs();
-	unregister_chrdev(ISDN_MAJOR, "isdn");
- err_vfree:
-	vfree(isdndev);
- err_drv_fsm:
-	fsm_free(&drv_fsm);
- err_slot_fsm:
-	fsm_free(&slot_fsm);
- err:
-	return retval;
+	isdn_info_update();
+	return 0;
 }
 
 /*
@@ -2254,141 +2246,17 @@
 #ifdef CONFIG_ISDN_PPP
 	isdn_ppp_cleanup();
 #endif
-	isdn_net_lib_exit();
-
+	if (isdn_net_rmall() < 0) {
+		printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
+		return;
+	}
 	isdn_tty_exit();
 	unregister_chrdev(ISDN_MAJOR, "isdn");
-	isdn_cleanup_devfs();
-	vfree(isdndev);
-	fsm_free(&drv_fsm);
-	fsm_free(&slot_fsm);
+	del_timer(&dev->timer);
+	/* call vfree with interrupts enabled, else it will hang */
+	vfree(dev);
+	printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
 }
 
 module_init(isdn_init);
 module_exit(isdn_exit);
-
-static void
-isdn_v110_add_features(struct isdn_driver *drv)
-{
-	unsigned long features = drv->features >> ISDN_FEATURE_L2_SHIFT;
-
-	if (features & ISDN_FEATURE_L2_TRANS)
-		drv->features |= (ISDN_FEATURE_L2_V11096|
-				  ISDN_FEATURE_L2_V11019|
-				  ISDN_FEATURE_L2_V11038) << 
-			ISDN_FEATURE_L2_SHIFT;
-}
-
-static void
-__isdn_v110_open(struct isdn_slot *slot)
-{
-	if (!slot->iv110.v110emu)
-		return;
-
-	isdn_v110_open(slot, &slot->iv110);
-}
-
-static void
-__isdn_v110_close(struct isdn_slot *slot)
-{
-	if (!slot->iv110.v110emu)
-		return;
-
-	isdn_v110_close(slot, &slot->iv110);
-}
-
-static void
-__isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *c)
-{
-	if (!slot->iv110.v110emu) {
-		do_event_cb(slot, pr, c);
-		return;
-	}
-	isdn_v110_bsent(slot, &slot->iv110);
-}
-
-/*
- * Intercept command from Linklevel to Lowlevel.
- * If layer 2 protocol is V.110 and this is not supported by current
- * lowlevel-driver, use driver's transparent mode and handle V.110 in
- * linklevel instead.
- */
-static void
-isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd)
-{
-	struct isdn_driver *drv = slot->drv;
-
-	unsigned long l2prot = (cmd->arg >> 8) & 255;
-	unsigned long l2_feature = 1 << l2prot;
-	unsigned long features = drv->interface->features >> 
-		ISDN_FEATURE_L2_SHIFT;
-	
-	switch (l2prot) {
-	case ISDN_PROTO_L2_V11096:
-	case ISDN_PROTO_L2_V11019:
-	case ISDN_PROTO_L2_V11038:
-		/* If V.110 requested, but not supported by
-		 * HL-driver, set emulator-flag and change
-		 * Layer-2 to transparent
-		 */
-		if (!(features & l2_feature)) {
-			slot->iv110.v110emu = l2prot;
-			cmd->arg = (cmd->arg & 255) |
-				(ISDN_PROTO_L2_TRANS << 8);
-		} else
-			slot->iv110.v110emu = 0;
-	}
-}
-
-static int
-isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb)
-{
-	if (!slot->iv110.v110emu)
-		goto recv;
-		
-	skb = isdn_v110_decode(slot->iv110.v110, skb);
-	if (!skb)
-		return 0;
-
-recv:
-	if (slot->event_cb)
-		slot->event_cb(slot, EV_DATA_IND, skb);
-	return 0;
-}
-
-static int
-isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb)
-{
-	int retval, v110_ret;
-	struct sk_buff *nskb = NULL;
-
-	if (!slot->iv110.v110emu)
-		return isdn_writebuf_skb(slot, skb);
-
-	atomic_inc(&slot->iv110.v110use);
-	nskb = isdn_v110_encode(slot->iv110.v110, skb);
-	atomic_dec(&slot->iv110.v110use);
-	if (!nskb)
-		return -ENOMEM;
-
-	v110_ret = *(int *)nskb->data;
-	skb_pull(nskb, sizeof(int));
-	if (!nskb->len) {
-		dev_kfree_skb(nskb);
-		return v110_ret;
-	}
-	
-	retval = isdn_writebuf_skb(slot, nskb);
-	if (retval <= 0) {
-		dev_kfree_skb(nskb);
-		return retval;
-	}
-	dev_kfree_skb(skb);
-
-	atomic_inc(&slot->iv110.v110use);
-	slot->iv110.v110->skbuser++;
-	atomic_dec(&slot->iv110.v110use);
-
-	/* For V.110 return unencoded data length */
-	return v110_ret;
-}
--- diff/drivers/isdn/i4l/isdn_common.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_common.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,7 @@
-/* Linux ISDN subsystem, common used functions and debugging-switches
+/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem
+ * common used functions and debugging-switches (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
@@ -9,9 +12,6 @@
  *
  */
 
-#include <linux/isdn.h>
-#include "isdn_v110.h"
-
 #undef  ISDN_DEBUG_MODEM_OPEN
 #undef  ISDN_DEBUG_MODEM_IOCTL
 #undef  ISDN_DEBUG_MODEM_WAITSENT
@@ -21,129 +21,27 @@
 #undef  ISDN_DEBUG_MODEM_VOICE
 #undef  ISDN_DEBUG_AT
 #undef  ISDN_DEBUG_NET_DUMP
-#define  ISDN_DEBUG_NET_DIAL
-#define  ISDN_DEBUG_NET_ICALL
-#define  ISDN_DEBUG_STATCALLB
-#define  ISDN_DEBUG_COMMAND
-
-#ifdef ISDN_DEBUG_NET_DIAL
-#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
-#else
-#define dbg_net_dial(arg...) do {} while (0)
-#endif
-
-#ifdef ISDN_DEBUG_NET_ICALL
-#define dbg_net_icall(arg...) printk(KERN_DEBUG arg)
-#else
-#define dbg_net_icall(arg...) do {} while (0)
-#endif
-
-#ifdef ISDN_DEBUG_STATCALLB
-#define dbg_statcallb(arg...) printk(KERN_DEBUG arg)
-#else
-#define dbg_statcallb(arg...) do {} while (0)
-#endif
-
-#define isdn_BUG() \
-do { printk(KERN_WARNING "ISDN BUG at %s:%d\n", __FILE__, __LINE__); \
-} while(0)
-
-#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__)
-
-extern struct list_head isdn_net_devs;
+#undef  ISDN_DEBUG_NET_DIAL
+#undef  ISDN_DEBUG_NET_ICALL
 
 /* Prototypes */
-extern void isdn_MOD_INC_USE_COUNT(void);
-extern void isdn_MOD_DEC_USE_COUNT(void);
 extern void isdn_lock_drivers(void);
 extern void isdn_unlock_drivers(void);
+extern void isdn_free_channel(int di, int ch, int usage);
+extern void isdn_all_eaz(int di, int ch);
+extern int  isdn_command(isdn_ctrl *);
+extern int  isdn_dc2minor(int di, int ch);
 extern void isdn_info_update(void);
 extern char *isdn_map_eaz2msn(char *msn, int di);
-extern int isdn_getnum(char **);
-extern int isdn_msncmp( const char *,  const char *);
+extern void isdn_timer_ctrl(int tf, int onoff);
+extern void isdn_unexclusive_channel(int di, int ch);
+extern int  isdn_getnum(char **);
+extern int  isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
+extern int  isdn_get_free_channel(int, int, int, int, int, char *);
+extern int  isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
+extern int  register_isdn(isdn_if * i);
+extern int  isdn_msncmp( const char *,  const char *);
+extern int  isdn_add_channels(isdn_driver_t *, int, int, int);
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
 extern void isdn_dumppkt(char *, u_char *, int, int);
-#else
-static inline void isdn_dumppkt(char *s, u_char *d, int l, int m) { }
 #endif
-
-struct isdn_slot {
-	int               di;                  /* driver index               */
-	struct isdn_driver *drv;               /* driver                     */
-	int               ch;                  /* channel index (per driver) */
-	int               usage;               /* how is it used             */
-	char              num[ISDN_MSNLEN];    /* the current phone number   */
-	unsigned long     ibytes;              /* Statistics incoming bytes  */
-	unsigned long     obytes;              /* Statistics outgoing bytes  */
-	struct isdn_v110  iv110;               /* For V.110                  */
-	void             *priv;                /* pointer to isdn_net_dev    */
-	int             (*event_cb)(struct isdn_slot *, int pr, void *arg);
-	struct fsm_inst   fi;
-};
-
-struct dial_info {
-	int            l2_proto;
-	int            l3_proto;
-	struct T30_s  *fax;
-	unsigned char  si1;
-	unsigned char  si2;
-	unsigned char *msn;
-	unsigned char *phone;
-};
-
-struct isdn_slot *isdn_get_free_slot(int, int, int, int, int, char *);
-void  isdn_slot_free(struct isdn_slot *);
-int   isdn_slot_command(struct isdn_slot *, int cmd, isdn_ctrl *);
-int   isdn_slot_dial(struct isdn_slot *, struct dial_info *dial);
-char *isdn_slot_map_eaz2msn(struct isdn_slot *, char *msn);
-int   isdn_slot_write(struct isdn_slot *, struct sk_buff *);
-int   isdn_slot_hdrlen(struct isdn_slot *);
-int   isdn_slot_maxbufsize(struct isdn_slot *);
-int   isdn_hard_header_len(void);
-
-int   isdn_drv_lookup(char *drvid);
-char *isdn_drv_drvid(int di);
-
-enum {
-	ST_SLOT_NULL,
-	ST_SLOT_BOUND,
-	ST_SLOT_IN,
-	ST_SLOT_WAIT_DCONN,
-	ST_SLOT_DCONN,
-	ST_SLOT_WAIT_BCONN,
-	ST_SLOT_ACTIVE,
-	ST_SLOT_WAIT_BHUP,
-	ST_SLOT_WAIT_DHUP,
-};
-
-enum {
-	EV_DRV_REGISTER,
-	EV_STAT_RUN,
-	EV_STAT_STOP,
-	EV_STAT_UNLOAD,
-	EV_STAT_STAVAIL,
-	EV_STAT_ADDCH,
-	EV_STAT_ICALL,
-	EV_STAT_DCONN,
-	EV_STAT_BCONN,
-	EV_STAT_BHUP,
-	EV_STAT_DHUP,
-	EV_STAT_BSENT,
-	EV_STAT_CINF,
-	EV_STAT_CAUSE,
-	EV_STAT_DISPLAY,
-	EV_STAT_FAXIND,
-	EV_STAT_AUDIO,
-	EV_CMD_CLREAZ,
-	EV_CMD_SETEAZ,
-	EV_CMD_SETL2,
-	EV_CMD_SETL3,
-	EV_CMD_DIAL,
-	EV_CMD_ACCEPTD,
-	EV_CMD_ACCEPTB,
-	EV_CMD_HANGUP,
-	EV_DATA_REQ,
-	EV_DATA_IND,
-	EV_SLOT_BIND,
-	EV_SLOT_UNBIND,
-};
--- diff/drivers/isdn/i4l/isdn_concap.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_concap.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,12 +1,16 @@
-/* Linux ISDN subsystem, protocol encapsulation
+/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ * 
+ * Linux ISDN subsystem, protocol encapsulation
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 /* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
  * stuff goes here. Stuff that depends only on the concap protocol goes to
  * another -- protocol specific -- source file.
+ *
  */
 
 
@@ -15,7 +19,7 @@
 #include "isdn_net.h"
 #include <linux/concap.h>
 #include "isdn_concap.h"
-#include <linux/if_arp.h>
+
 
 /* The following set of device service operations are for encapsulation
    protocols that require for reliable datalink semantics. That means:
@@ -35,8 +39,7 @@
    */
 
 
-static int
-isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
 {
 	struct net_device *ndev = concap -> net_dev;
 	isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
@@ -55,8 +58,7 @@
 }
 
 
-static int
-isdn_concap_dl_connect_req(struct concap_proto *concap)
+int isdn_concap_dl_connect_req(struct concap_proto *concap)
 {
 	struct net_device *ndev = concap -> net_dev;
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -69,8 +71,7 @@
 	return ret;
 }
 
-static int
-isdn_concap_dl_disconn_req(struct concap_proto *concap)
+int isdn_concap_dl_disconn_req(struct concap_proto *concap)
 {
 	IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
 
@@ -97,8 +98,7 @@
    this sourcefile does not need to include any protocol specific header
    files. For now:
    */
-struct concap_proto *
-isdn_concap_new( int encap )
+struct concap_proto * isdn_concap_new( int encap )
 {
 	switch ( encap ) {
 	case ISDN_NET_ENCAP_X25IFACE:
@@ -106,146 +106,3 @@
 	}
 	return NULL;
 }
-
-static int
-isdn_x25_open(isdn_net_local *lp)
-{
-	struct net_device * dev = & lp -> netdev -> dev;
-	struct concap_proto * cprot = lp -> netdev -> ind_priv;
-	struct concap_proto * dops = lp -> inl_priv;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();                  /* Avoid glitch on writes to CMD regs */
-	if( cprot -> pops && dops )
-		cprot -> pops -> restart ( cprot, dev, dops );
-	restore_flags(flags);
-	return 0;
-}
-
-static void
-isdn_x25_close(isdn_net_local *lp)
-{
-	struct concap_proto * cprot = lp -> netdev -> ind_priv;
-
-	if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
-}
-
-static void
-isdn_x25_connected(isdn_net_local *lp)
-{
-	struct concap_proto *cprot = lp -> netdev -> ind_priv;
-	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
-
-	/* try if there are generic concap receiver routines */
-	if( pops )
-		if( pops->connect_ind)
-			pops->connect_ind(cprot);
-
-	isdn_net_device_wake_queue(lp);
-}
-
-static void
-isdn_x25_disconnected(isdn_net_local *lp)
-{
-	struct concap_proto *cprot = lp -> netdev -> ind_priv;
-	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
-
-	/* try if there are generic encap protocol
-	   receiver routines and signal the closure of
-	   the link */
-	if( pops  &&  pops -> disconn_ind )
-		pops -> disconn_ind(cprot);
-}
-
-static int
-isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-/* At this point hard_start_xmit() passes control to the encapsulation
-   protocol (if present).
-   For X.25 auto-dialing is completly bypassed because:
-   - It does not conform with the semantics of a reliable datalink
-     service as needed by X.25 PLP.
-   - I don't want that the interface starts dialing when the network layer
-     sends a message which requests to disconnect the lapb link (or if it
-     sends any other message not resulting in data transmission).
-   Instead, dialing will be initiated by the encapsulation protocol entity
-   when a dl_establish request is received from the upper layer.
-*/
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
-	struct concap_proto * cprot = lp -> netdev -> ind_priv;
-	int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
-
-	if (ret)
-		netif_stop_queue(dev);
-		
-	return ret;
-}
-
-static void 
-isdn_x25_receive(isdn_net_dev *p, isdn_net_local *olp, struct sk_buff *skb)
-{
-	isdn_net_local *lp = &p->local;
-	struct concap_proto *cprot = lp -> netdev -> ind_priv;
-
-	/* try if there are generic sync_device receiver routines */
-	if(cprot) 
-		if(cprot -> pops)
-			if( cprot -> pops -> data_ind) {
-				cprot -> pops -> data_ind(cprot,skb);
-				return;
-			}
-}
-
-static void
-isdn_x25_init(struct net_device *dev)
-{
-	unsigned long flags;
-
-	isdn_net_local *lp = dev->priv;
-
-	/* ... ,  prepare for configuration of new one ... */
-	switch ( lp->p_encap ){
-	case ISDN_NET_ENCAP_X25IFACE:
-		lp -> inl_priv = &isdn_concap_reliable_dl_dops;
-	}
-	/* ... and allocate new one ... */
-	p -> cprot = isdn_concap_new( cfg -> p_encap );
-	/* p -> cprot == NULL now if p_encap is not supported
-	   by means of the concap_proto mechanism */
-	if (!p->cprot)
-		return -EINVAL;
-
-	return 0;
-}
-
-static void
-isdn_x25_cleanup(isdn_net_dev *p)
-{
-	isdn_net_local *lp = &p->local;
-	struct concap_proto * cprot = p -> cprot;
-	unsigned long flags;
-	
-	/* delete old encapsulation protocol if present ... */
-	save_flags(flags);
-	cli(); /* avoid races with incoming events trying to
-		  call cprot->pops methods */
-	if( cprot && cprot -> pops )
-		cprot -> pops -> proto_del ( cprot );
-	p -> cprot = NULL;
-	lp -> inl_priv = NULL;
-	restore_flags(flags);
-}
-
-struct isdn_netif_ops isdn_x25_ops = {
-	.hard_start_xmit     = isdn_x25_start_xmit,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_X25,
-	.receive             = isdn_x25_receive,
-	.connected           = isdn_x25_connected,
-	.disconnected        = isdn_x25_disconnected,
-	.init                = isdn_x25_init,
-	.cleanup             = isdn_x25_cleanup,
-	.open                = isdn_x25_open,
-	.close               = isdn_x25_close,
-};
--- diff/drivers/isdn/i4l/isdn_concap.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_concap.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,12 +1,14 @@
-/* Linux ISDN subsystem, protocol encapsulation
+/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, protocol encapsulation
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 extern struct concap_device_ops isdn_concap_reliable_dl_dops;
 extern struct concap_device_ops isdn_concap_demand_dial_dops;
+extern struct concap_proto * isdn_concap_new( int );
 
-struct concap_proto *isdn_concap_new(int);
 
-extern struct isdn_netif_ops isdn_x25_ops;
--- diff/drivers/isdn/i4l/isdn_net.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_net.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,150 +1,3223 @@
-/* Linux ISDN subsystem, network interfaces and related functions (linklevel).
+/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
  * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
+ * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
+ * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 
+ *                                       guy@traverse.com.au
+ * Outgoing calls - looks for a 'V' in first char of dialed number
+ * Incoming calls - checks first character of eaz as follows:
+ *   Numeric - accept DATA only - original functionality
+ *   'V'     - accept VOICE (DOV) only
+ *   'B'     - accept BOTH DATA and DOV types
+ *
+ * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
+ *           for info on the protocol, see 
+ *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
  */
 
+#include <linux/config.h>
 #include <linux/isdn.h>
-#include <linux/inetdevice.h>
 #include <net/arp.h>
+#include <net/dst.h>
+#include <net/pkt_sched.h>
+#include <linux/inetdevice.h>
 #include "isdn_common.h"
-#include "isdn_net_lib.h"
 #include "isdn_net.h"
+#ifdef CONFIG_ISDN_PPP
+#include "isdn_ppp.h"
+#endif
+#ifdef CONFIG_ISDN_X25
+#include <linux/concap.h>
+#include "isdn_concap.h"
+#endif
+
+
+/*
+ * Outline of new tbusy handling: 
+ *
+ * Old method, roughly spoken, consisted of setting tbusy when entering
+ * isdn_net_start_xmit() and at several other locations and clearing
+ * it from isdn_net_start_xmit() thread when sending was successful.
+ *
+ * With 2.3.x multithreaded network core, to prevent problems, tbusy should
+ * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
+ * condition is detected. Other threads (in particular isdn_net_stat_callb())
+ * are only allowed to clear tbusy.
+ *
+ * -HE
+ */
+
+/*
+ * About SOFTNET:
+ * Most of the changes were pretty obvious and basically done by HE already.
+ *
+ * One problem of the isdn net device code is that is uses struct net_device
+ * for masters and slaves. However, only master interface are registered to 
+ * the network layer, and therefore, it only makes sense to call netif_* 
+ * functions on them.
+ *
+ * --KG
+ */
+
+/* 
+ * Find out if the netdevice has been ifup-ed yet.
+ * For slaves, look at the corresponding master.
+ */
+static __inline__ int isdn_net_device_started(isdn_net_dev *n)
+{
+	isdn_net_local *lp = n->local;
+	struct net_device *dev;
+	
+	if (lp->master) 
+		dev = lp->master;
+	else
+		dev = &n->dev;
+	return netif_running(dev);
+}
+
+/*
+ * wake up the network -> net_device queue.
+ * For slaves, wake the corresponding master interface.
+ */
+static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
+{
+	if (lp->master) 
+		netif_wake_queue(lp->master);
+	else
+		netif_wake_queue(&lp->netdev->dev);
+}
+
+/*
+ * stop the network -> net_device queue.
+ * For slaves, stop the corresponding master interface.
+ */
+static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
+{
+	if (lp->master)
+		netif_stop_queue(lp->master);
+	else
+		netif_stop_queue(&lp->netdev->dev);
+}
+
+/*
+ * find out if the net_device which this lp belongs to (lp can be
+ * master or slave) is busy. It's busy iff all (master and slave) 
+ * queues are busy
+ */
+static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
+{
+	isdn_net_local *nlp;
+	isdn_net_dev *nd;
+	unsigned long flags;
+
+	if (!isdn_net_lp_busy(lp))
+		return 0;
+
+	if (lp->master)
+		nd = ((isdn_net_local *) lp->master->priv)->netdev;
+	else
+		nd = lp->netdev;
+	
+	spin_lock_irqsave(&nd->queue_lock, flags);
+	nlp = lp->next;
+	while (nlp != lp) {
+		if (!isdn_net_lp_busy(nlp)) {
+			spin_unlock_irqrestore(&nd->queue_lock, flags);
+			return 0;
+		}
+		nlp = nlp->next;
+	}
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+	return 1;
+}
+
+static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
+{
+	atomic_inc(&lp->frame_cnt);
+	if (isdn_net_device_busy(lp))
+		isdn_net_device_stop_queue(lp);
+}
+
+static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+{
+	atomic_dec(&lp->frame_cnt);
+
+	if (!(isdn_net_device_busy(lp))) {
+		if (!skb_queue_empty(&lp->super_tx_queue)) {
+			schedule_work(&lp->tqueue);
+		} else {
+			isdn_net_device_wake_queue(lp);
+		}
+       }                                                                      
+}
+
+static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+{
+	atomic_set(&lp->frame_cnt, 0);
+}
+
+/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just 
+ * to be safe.
+ * For 2.3.x we push it up to 20 secs, because call establishment
+ * (in particular callback) may take such a long time, and we 
+ * don't want confusing messages in the log. However, there is a slight
+ * possibility that this large timeout will break other things like MPPP,
+ * which might rely on the tx timeout. If so, we'll find out this way...
+ */
+
+#define ISDN_NET_TX_TIMEOUT (20*HZ) 
+
+/* Prototypes */
+
+int isdn_net_force_dial_lp(isdn_net_local *);
+static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
+
+static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
+static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
+
+char *isdn_net_revision = "$Revision: 1.1.2.2 $";
 
-// ISDN_NET_ENCAP_IPTYP
-// ethernet type field
-// ======================================================================
+ /*
+  * Code for raw-networking over ISDN
+  */
 
+static void
+isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
+{
+	if(skb) {
+
+		u_short proto = ntohs(skb->protocol);
+
+		printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
+		       dev->name,
+		       (reason != NULL) ? reason : "unknown",
+		       (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
+		
+		dst_link_failure(skb);
+	}
+	else {  /* dial not triggered by rawIP packet */
+		printk(KERN_DEBUG "isdn_net: %s: %s\n",
+			   dev->name,
+			   (reason != NULL) ? reason : "reason unknown");
+	}
+}
+
+static void
+isdn_net_reset(struct net_device *dev)
+{
+#ifdef CONFIG_ISDN_X25
+	struct concap_device_ops * dops =
+		( (isdn_net_local *) dev->priv ) -> dops;
+	struct concap_proto * cprot =
+		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+#endif
+#ifdef CONFIG_ISDN_X25
+	if( cprot && cprot -> pops && dops )
+		cprot -> pops -> restart ( cprot, dev, dops );
+#endif
+}
+
+/* Open/initialize the board. */
 static int
-isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
-		   unsigned short type, void *daddr, void *saddr, 
-		   unsigned plen)
+isdn_net_open(struct net_device *dev)
+{
+	int i;
+	struct net_device *p;
+	struct in_device *in_dev;
+
+	/* moved here from isdn_net_reset, because only the master has an
+	   interface associated which is supposed to be started. BTW:
+	   we need to call netif_start_queue, not netif_wake_queue here */
+	netif_start_queue(dev);
+
+	isdn_net_reset(dev);
+	/* Fill in the MAC-level header (not needed, but for compatibility... */
+	for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
+		dev->dev_addr[i] = 0xfc;
+	if ((in_dev = dev->ip_ptr) != NULL) {
+		/*
+		 *      Any address will do - we take the first
+		 */
+		struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa != NULL)
+			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+	}
+
+	/* If this interface has slaves, start them also */
+
+	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
+		while (p) {
+			isdn_net_reset(p);
+			p = (((isdn_net_local *) p->priv)->slave);
+		}
+	}
+	isdn_lock_drivers();
+	return 0;
+}
+
+/*
+ * Assign an ISDN-channel to a net-interface
+ */
+static void
+isdn_net_bind_channel(isdn_net_local * lp, int idx)
 {
-	put_u16(skb_push(skb, 2), type);
-	return 2;
+	lp->flags |= ISDN_NET_CONNECTED;
+	lp->isdn_device = dev->drvmap[idx];
+	lp->isdn_channel = dev->chanmap[idx];
+	dev->rx_netdev[idx] = lp->netdev;
+	dev->st_netdev[idx] = lp->netdev;
 }
 
+/*
+ * unbind a net-interface (resets interface after an error)
+ */
 static void
-isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev, 
-		   struct sk_buff *skb)
+isdn_net_unbind_channel(isdn_net_local * lp)
+{
+	skb_queue_purge(&lp->super_tx_queue);
+
+	if (!lp->master) {	/* reset only master device */
+		/* Moral equivalent of dev_purge_queues():
+		   BEWARE! This chunk of code cannot be called from hardware
+		   interrupt handler. I hope it is true. --ANK
+		 */
+		qdisc_reset(lp->netdev->dev.qdisc);
+	}
+	lp->dialstate = 0;
+	dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
+	dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
+	isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
+	lp->flags &= ~ISDN_NET_CONNECTED;
+	lp->isdn_device = -1;
+	lp->isdn_channel = -1;
+}
+
+/*
+ * Perform auto-hangup and cps-calculation for net-interfaces.
+ *
+ * auto-hangup:
+ * Increment idle-counter (this counter is reset on any incoming or
+ * outgoing packet), if counter exceeds configured limit either do a
+ * hangup immediately or - if configured - wait until just before the next
+ * charge-info.
+ *
+ * cps-calculation (needed for dynamic channel-bundling):
+ * Since this function is called every second, simply reset the
+ * byte-counter of the interface after copying it to the cps-variable.
+ */
+unsigned long last_jiffies = -HZ;
+
+void
+isdn_net_autohup()
 {
-	u16 protocol;
+	isdn_net_dev *p = dev->netdev;
+	int anymore;
+
+	anymore = 0;
+	while (p) {
+		isdn_net_local *l = p->local;
+		if (jiffies == last_jiffies)
+			l->cps = l->transcount;
+		else
+			l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
+		l->transcount = 0;
+		if (dev->net_verbose > 3)
+			printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
+		if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
+			anymore = 1;
+			l->huptimer++;
+			/*
+			 * if there is some dialmode where timeout-hangup
+			 * should _not_ be done, check for that here
+			 */
+			if ((l->onhtime) &&
+			    (l->huptimer > l->onhtime))
+			{
+				if (l->hupflags & ISDN_MANCHARGE &&
+				    l->hupflags & ISDN_CHARGEHUP) {
+					while (time_after(jiffies, l->chargetime + l->chargeint))
+						l->chargetime += l->chargeint;
+					if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
+						if (l->outgoing || l->hupflags & ISDN_INHUP)
+							isdn_net_hangup(&p->dev);
+				} else if (l->outgoing) {
+					if (l->hupflags & ISDN_CHARGEHUP) {
+						if (l->hupflags & ISDN_WAITCHARGE) {
+							printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
+							       l->name, l->hupflags);
+							isdn_net_hangup(&p->dev);
+						} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
+							printk(KERN_DEBUG
+							       "isdn_net: %s: chtime = %lu, chint = %d\n",
+							       l->name, l->chargetime, l->chargeint);
+							isdn_net_hangup(&p->dev);
+						}
+					} else
+						isdn_net_hangup(&p->dev);
+				} else if (l->hupflags & ISDN_INHUP)
+					isdn_net_hangup(&p->dev);
+			}
+
+			if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
+				isdn_net_hangup(&p->dev);
+				break;
+			}
+		}
+		p = (isdn_net_dev *) p->next;
+	}
+	last_jiffies = jiffies;
+	isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
+}
 
-	get_u16(skb->data, &protocol);
-	skb_pull(skb, 2);
-	isdn_netif_rx(idev, skb, protocol);
+static void isdn_net_lp_disconnected(isdn_net_local *lp)
+{
+	isdn_net_rm_from_bundle(lp);
 }
 
-struct isdn_netif_ops isdn_iptyp_ops = {
-	.hard_start_xmit     = isdn_net_start_xmit,
-	.hard_header         = isdn_iptyp_header,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_PPP,
-	.addr_len            = 2,
-	.receive             = isdn_iptyp_receive,
-};
+/*
+ * Handle status-messages from ISDN-interfacecard.
+ * This function is called from within the main-status-dispatcher
+ * isdn_status_callback, which itself is called from the low-level driver.
+ * Return: 1 = Event handled, 0 = not for us or unknown Event.
+ */
+int
+isdn_net_stat_callback(int idx, isdn_ctrl *c)
+{
+	isdn_net_dev *p = dev->st_netdev[idx];
+	int cmd = c->command;
 
-// ISDN_NET_ENCAP_UIHDLC
-// HDLC with UI-Frames (for ispa with -h1 option) */
-// ======================================================================
+	if (p) {
+		isdn_net_local *lp = p->local;
+#ifdef CONFIG_ISDN_X25
+		struct concap_proto *cprot = lp -> netdev -> cprot;
+		struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
+		switch (cmd) {
+			case ISDN_STAT_BSENT:
+				/* A packet has successfully been sent out */
+				if ((lp->flags & ISDN_NET_CONNECTED) &&
+				    (!lp->dialstate)) {
+					isdn_net_dec_frame_cnt(lp);
+					lp->stats.tx_packets++;
+					lp->stats.tx_bytes += c->parm.length;
+				}
+				return 1;
+			case ISDN_STAT_DCONN:
+				/* D-Channel is up */
+				switch (lp->dialstate) {
+					case 4:
+					case 7:
+					case 8:
+						lp->dialstate++;
+						return 1;
+					case 12:
+						lp->dialstate = 5;
+						return 1;
+				}
+				break;
+			case ISDN_STAT_DHUP:
+				/* Either D-Channel-hangup or error during dialout */
+#ifdef CONFIG_ISDN_X25
+				/* If we are not connencted then dialing had
+				   failed. If there are generic encap protocol
+				   receiver routines signal the closure of
+				   the link*/
+
+				if( !(lp->flags & ISDN_NET_CONNECTED)
+				    && pops && pops -> disconn_ind )
+					pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
+				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
+					if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
+						isdn_net_ciscohdlck_disconnected(lp);
+#ifdef CONFIG_ISDN_PPP
+					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+						isdn_ppp_free(lp);
+#endif
+					isdn_net_lp_disconnected(lp);
+					isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
+					printk(KERN_INFO "%s: remote hangup\n", lp->name);
+					printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
+					       lp->charge);
+					isdn_net_unbind_channel(lp);
+					return 1;
+				}
+				break;
+#ifdef CONFIG_ISDN_X25
+			case ISDN_STAT_BHUP:
+				/* B-Channel-hangup */
+				/* try if there are generic encap protocol
+				   receiver routines and signal the closure of
+				   the link */
+				if( pops  &&  pops -> disconn_ind ){
+						pops -> disconn_ind(cprot);
+						return 1;
+					}
+				break;
+#endif /* CONFIG_ISDN_X25 */
+			case ISDN_STAT_BCONN:
+				/* B-Channel is up */
+				isdn_net_zero_frame_cnt(lp);
+				switch (lp->dialstate) {
+					case 5:
+					case 6:
+					case 7:
+					case 8:
+					case 9:
+					case 10:
+					case 12:
+						if (lp->dialstate <= 6) {
+							dev->usage[idx] |= ISDN_USAGE_OUTGOING;
+							isdn_info_update();
+						} else
+							dev->rx_netdev[idx] = p;
+						lp->dialstate = 0;
+						isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
+						if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
+							isdn_net_ciscohdlck_connected(lp);
+						if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
+							if (lp->master) { /* is lp a slave? */
+								isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
+								isdn_net_add_to_bundle(nd, lp);
+							}
+						}
+						printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+						/* If first Chargeinfo comes before B-Channel connect,
+						 * we correct the timestamp here.
+						 */
+						lp->chargetime = jiffies;
+
+						/* reset dial-timeout */
+						lp->dialstarted = 0;
+						lp->dialwait_timer = 0;
+
+#ifdef CONFIG_ISDN_PPP
+						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+							isdn_ppp_wakeup_daemon(lp);
+#endif
+#ifdef CONFIG_ISDN_X25
+						/* try if there are generic concap receiver routines */
+						if( pops )
+							if( pops->connect_ind)
+								pops->connect_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
+						/* ppp needs to do negotiations first */
+						if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+							isdn_net_device_wake_queue(lp);
+						return 1;
+				}
+				break;
+			case ISDN_STAT_NODCH:
+				/* No D-Channel avail. */
+				if (lp->dialstate == 4) {
+					lp->dialstate--;
+					return 1;
+				}
+				break;
+			case ISDN_STAT_CINF:
+				/* Charge-info from TelCo. Calculate interval between
+				 * charge-infos and set timestamp for last info for
+				 * usage by isdn_net_autohup()
+				 */
+				lp->charge++;
+				if (lp->hupflags & ISDN_HAVECHARGE) {
+					lp->hupflags &= ~ISDN_WAITCHARGE;
+					lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
+				}
+				if (lp->hupflags & ISDN_WAITCHARGE)
+					lp->hupflags |= ISDN_HAVECHARGE;
+				lp->chargetime = jiffies;
+				printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
+				       lp->name, lp->chargetime);
+				return 1;
+		}
+	}
+	return 0;
+}
 
+/*
+ * Perform dialout for net-interfaces and timeout-handling for
+ * D-Channel-up and B-Channel-up Messages.
+ * This function is initially called from within isdn_net_start_xmit() or
+ * or isdn_net_find_icall() after initializing the dialstate for an
+ * interface. If further calls are needed, the function schedules itself
+ * for a timer-callback via isdn_timer_function().
+ * The dialstate is also affected by incoming status-messages from
+ * the ISDN-Channel which are handled in isdn_net_stat_callback() above.
+ */
+void
+isdn_net_dial(void)
+{
+	isdn_net_dev *p = dev->netdev;
+	int anymore = 0;
+	int i;
+	isdn_ctrl cmd;
+        u_char *phone_number;
+
+	while (p) {
+		isdn_net_local *lp = p->local;
+
+#ifdef ISDN_DEBUG_NET_DIAL
+		if (lp->dialstate)
+			printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
+#endif
+		switch (lp->dialstate) {
+			case 0:
+				/* Nothing to do for this interface */
+				break;
+			case 1:
+				/* Initiate dialout. Set phone-number-pointer to first number
+				 * of interface.
+				 */
+				lp->dial = lp->phone[1];
+				if (!lp->dial) {
+					printk(KERN_WARNING "%s: phone number deleted?\n",
+					       lp->name);
+					isdn_net_hangup(&p->dev);
+					break;
+				}
+				anymore = 1;
+
+				if(lp->dialtimeout > 0)
+					if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
+						lp->dialstarted = jiffies;
+						lp->dialwait_timer = 0;
+					}
+
+				lp->dialstate++;
+				/* Fall through */
+			case 2:
+				/* Prepare dialing. Clear EAZ, then set EAZ. */
+				cmd.driver = lp->isdn_device;
+				cmd.arg = lp->isdn_channel;
+				cmd.command = ISDN_CMD_CLREAZ;
+				isdn_command(&cmd);
+				sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
+				cmd.command = ISDN_CMD_SETEAZ;
+				isdn_command(&cmd);
+				lp->dialretry = 0;
+				anymore = 1;
+				lp->dialstate++;
+				/* Fall through */
+			case 3:
+				/* Setup interface, dial current phone-number, switch to next number.
+				 * If list of phone-numbers is exhausted, increment
+				 * retry-counter.
+				 */
+				if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
+					char *s;
+					if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+						s = "dial suppressed: isdn system stopped";
+					else
+						s = "dial suppressed: dialmode `off'";
+					isdn_net_unreachable(&p->dev, 0, s);
+					isdn_net_hangup(&p->dev);
+					break;
+				}
+				cmd.driver = lp->isdn_device;
+				cmd.command = ISDN_CMD_SETL2;
+				cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
+				isdn_command(&cmd);
+				cmd.driver = lp->isdn_device;
+				cmd.command = ISDN_CMD_SETL3;
+				cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+				isdn_command(&cmd);
+				cmd.driver = lp->isdn_device;
+				cmd.arg = lp->isdn_channel;
+				if (!lp->dial) {
+					printk(KERN_WARNING "%s: phone number deleted?\n",
+					       lp->name);
+					isdn_net_hangup(&p->dev);
+					break;
+				}
+				if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
+					lp->dialstate = 4;
+					printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
+				} else {
+					if(lp->dialtimeout > 0)
+						if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
+							lp->dialwait_timer = jiffies + lp->dialwait;
+							lp->dialstarted = 0;
+							isdn_net_unreachable(&p->dev, 0, "dial: timed out");
+							isdn_net_hangup(&p->dev);
+							break;
+						}
+
+					cmd.driver = lp->isdn_device;
+					cmd.command = ISDN_CMD_DIAL;
+					cmd.parm.setup.si2 = 0;
+
+                                        /* check for DOV */
+                                        phone_number = lp->dial->num;
+                                        if ((*phone_number == 'v') ||
+					    (*phone_number == 'V')) { /* DOV call */
+                                                cmd.parm.setup.si1 = 1;
+                                        } else { /* DATA call */
+                                                cmd.parm.setup.si1 = 7;
+					}
+
+					strcpy(cmd.parm.setup.phone, phone_number);
+					/*
+					 * Switch to next number or back to start if at end of list.
+					 */
+					if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
+						lp->dial = lp->phone[1];
+						lp->dialretry++;
+
+						if (lp->dialretry > lp->dialmax) {
+							if (lp->dialtimeout == 0) {
+								lp->dialwait_timer = jiffies + lp->dialwait;
+								lp->dialstarted = 0;
+								isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times");
+							}
+							isdn_net_hangup(&p->dev);
+							break;
+						}
+					}
+					sprintf(cmd.parm.setup.eazmsn, "%s",
+						isdn_map_eaz2msn(lp->msn, cmd.driver));
+					i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
+					if (i >= 0) {
+						strcpy(dev->num[i], cmd.parm.setup.phone);
+						dev->usage[i] |= ISDN_USAGE_OUTGOING;
+						isdn_info_update();
+					}
+					printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+					       lp->dialretry, cmd.parm.setup.phone,
+					       (cmd.parm.setup.si1 == 1) ? "DOV" : "");
+					lp->dtimer = 0;
+#ifdef ISDN_DEBUG_NET_DIAL
+					printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
+					       lp->isdn_channel);
+#endif
+					isdn_command(&cmd);
+				}
+				lp->huptimer = 0;
+				lp->outgoing = 1;
+				if (lp->chargeint) {
+					lp->hupflags |= ISDN_HAVECHARGE;
+					lp->hupflags &= ~ISDN_WAITCHARGE;
+				} else {
+					lp->hupflags |= ISDN_WAITCHARGE;
+					lp->hupflags &= ~ISDN_HAVECHARGE;
+				}
+				anymore = 1;
+				lp->dialstate =
+				    (lp->cbdelay &&
+				     (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
+				break;
+			case 4:
+				/* Wait for D-Channel-connect.
+				 * If timeout, switch back to state 3.
+				 * Dialmax-handling moved to state 3.
+				 */
+				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					lp->dialstate = 3;
+				anymore = 1;
+				break;
+			case 5:
+				/* Got D-Channel-Connect, send B-Channel-request */
+				cmd.driver = lp->isdn_device;
+				cmd.arg = lp->isdn_channel;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				anymore = 1;
+				lp->dtimer = 0;
+				lp->dialstate++;
+				isdn_command(&cmd);
+				break;
+			case 6:
+				/* Wait for B- or D-Channel-connect. If timeout,
+				 * switch back to state 3.
+				 */
+#ifdef ISDN_DEBUG_NET_DIAL
+				printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
+#endif
+				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					lp->dialstate = 3;
+				anymore = 1;
+				break;
+			case 7:
+				/* Got incoming Call, setup L2 and L3 protocols,
+				 * then wait for D-Channel-connect
+				 */
+#ifdef ISDN_DEBUG_NET_DIAL
+				printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
+#endif
+				cmd.driver = lp->isdn_device;
+				cmd.command = ISDN_CMD_SETL2;
+				cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
+				isdn_command(&cmd);
+				cmd.driver = lp->isdn_device;
+				cmd.command = ISDN_CMD_SETL3;
+				cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+				isdn_command(&cmd);
+				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
+					isdn_net_hangup(&p->dev);
+				else {
+					anymore = 1;
+					lp->dialstate++;
+				}
+				break;
+			case 9:
+				/* Got incoming D-Channel-Connect, send B-Channel-request */
+				cmd.driver = lp->isdn_device;
+				cmd.arg = lp->isdn_channel;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				isdn_command(&cmd);
+				anymore = 1;
+				lp->dtimer = 0;
+				lp->dialstate++;
+				break;
+			case 8:
+			case 10:
+				/*  Wait for B- or D-channel-connect */
+#ifdef ISDN_DEBUG_NET_DIAL
+				printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
+#endif
+				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					isdn_net_hangup(&p->dev);
+				else
+					anymore = 1;
+				break;
+			case 11:
+				/* Callback Delay */
+				if (lp->dtimer++ > lp->cbdelay)
+					lp->dialstate = 1;
+				anymore = 1;
+				break;
+			case 12:
+				/* Remote does callback. Hangup after cbdelay, then wait for incoming
+				 * call (in state 4).
+				 */
+				if (lp->dtimer++ > lp->cbdelay)
+				{
+					printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
+					lp->dtimer = 0;
+					lp->dialstate = 4;
+					cmd.driver = lp->isdn_device;
+					cmd.command = ISDN_CMD_HANGUP;
+					cmd.arg = lp->isdn_channel;
+					isdn_command(&cmd);
+					isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
+				}
+				anymore = 1;
+				break;
+			default:
+				printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
+				       lp->dialstate, lp->name);
+		}
+		p = (isdn_net_dev *) p->next;
+	}
+	isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
+}
+
+/*
+ * Perform hangup for a net-interface.
+ */
+void
+isdn_net_hangup(struct net_device *d)
+{
+	isdn_net_local *lp = (isdn_net_local *) d->priv;
+	isdn_ctrl cmd;
+#ifdef CONFIG_ISDN_X25
+	struct concap_proto *cprot = lp -> netdev -> cprot;
+	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
+
+	if (lp->flags & ISDN_NET_CONNECTED) {
+		if (lp->slave != NULL) {
+			isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
+			if (slp->flags & ISDN_NET_CONNECTED) {
+				printk(KERN_INFO
+					"isdn_net: hang up slave %s before %s\n",
+					slp->name, lp->name);
+				isdn_net_hangup(lp->slave);
+			}
+		}
+		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
+#ifdef CONFIG_ISDN_PPP
+		if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+			isdn_ppp_free(lp);
+#endif
+		isdn_net_lp_disconnected(lp);
+#ifdef CONFIG_ISDN_X25
+		/* try if there are generic encap protocol
+		   receiver routines and signal the closure of
+		   the link */
+		if( pops && pops -> disconn_ind )
+		  pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
+
+		cmd.driver = lp->isdn_device;
+		cmd.command = ISDN_CMD_HANGUP;
+		cmd.arg = lp->isdn_channel;
+		isdn_command(&cmd);
+		printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
+		isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
+	}
+	isdn_net_unbind_channel(lp);
+}
+
+typedef struct {
+	unsigned short source;
+	unsigned short dest;
+} ip_ports;
+
+static void
+isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
+{
+	u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+	unsigned short proto = ntohs(skb->protocol);
+	int data_ofs;
+	ip_ports *ipp;
+	char addinfo[100];
+
+	addinfo[0] = '\0';
+	/* This check stolen from 2.1.72 dev_queue_xmit_nit() */
+	if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
+		/* fall back to old isdn_net_log_packet method() */
+		char * buf = skb->data;
+
+		printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+		p = buf;
+		proto = ETH_P_IP;
+		switch (lp->p_encap) {
+			case ISDN_NET_ENCAP_IPTYP:
+				proto = ntohs(*(unsigned short *) &buf[0]);
+				p = &buf[2];
+				break;
+			case ISDN_NET_ENCAP_ETHER:
+				proto = ntohs(*(unsigned short *) &buf[12]);
+				p = &buf[14];
+				break;
+			case ISDN_NET_ENCAP_CISCOHDLC:
+				proto = ntohs(*(unsigned short *) &buf[2]);
+				p = &buf[4];
+				break;
+#ifdef CONFIG_ISDN_PPP
+			case ISDN_NET_ENCAP_SYNCPPP:
+				proto = ntohs(skb->protocol);
+				p = &buf[IPPP_MAX_HEADER];
+				break;
+#endif
+		}
+	}
+	data_ofs = ((p[0] & 15) * 4);
+	switch (proto) {
+		case ETH_P_IP:
+			switch (p[9]) {
+				case 1:
+					strcpy(addinfo, " ICMP");
+					break;
+				case 2:
+					strcpy(addinfo, " IGMP");
+					break;
+				case 4:
+					strcpy(addinfo, " IPIP");
+					break;
+				case 6:
+					ipp = (ip_ports *) (&p[data_ofs]);
+					sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
+						ntohs(ipp->dest));
+					break;
+				case 8:
+					strcpy(addinfo, " EGP");
+					break;
+				case 12:
+					strcpy(addinfo, " PUP");
+					break;
+				case 17:
+					ipp = (ip_ports *) (&p[data_ofs]);
+					sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
+						ntohs(ipp->dest));
+					break;
+				case 22:
+					strcpy(addinfo, " IDP");
+					break;
+			}
+			printk(KERN_INFO
+				"OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+
+			       p[12], p[13], p[14], p[15],
+			       p[16], p[17], p[18], p[19],
+			       addinfo);
+			break;
+		case ETH_P_ARP:
+			printk(KERN_INFO
+				"OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+			       p[14], p[15], p[16], p[17],
+			       p[24], p[25], p[26], p[27]);
+			break;
+	}
+}
+
+/*
+ * this function is used to send supervisory data, i.e. data which was
+ * not received from the network layer, but e.g. frames from ipppd, CCP
+ * reset frames etc.
+ */
+void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
+{
+	if (in_irq()) {
+		// we can't grab the lock from irq context, 
+		// so we just queue the packet
+		skb_queue_tail(&lp->super_tx_queue, skb);
+		schedule_work(&lp->tqueue);
+		return;
+	}
+
+	spin_lock_bh(&lp->xmit_lock);
+	if (!isdn_net_lp_busy(lp)) {
+		isdn_net_writebuf_skb(lp, skb);
+	} else {
+		skb_queue_tail(&lp->super_tx_queue, skb);
+	}
+	spin_unlock_bh(&lp->xmit_lock);
+}
+
+/*
+ * called from tq_immediate
+ */
+static void isdn_net_softint(void *private)
+{
+	isdn_net_local *lp = private;
+	struct sk_buff *skb;
+
+	spin_lock_bh(&lp->xmit_lock);
+	while (!isdn_net_lp_busy(lp)) {
+		skb = skb_dequeue(&lp->super_tx_queue);
+		if (!skb)
+			break;
+		isdn_net_writebuf_skb(lp, skb);                                
+	}
+	spin_unlock_bh(&lp->xmit_lock);
+}
+
+/* 
+ * all frames sent from the (net) LL to a HL driver should go via this function
+ * it's serialized by the caller holding the lp->xmit_lock spinlock
+ */
+void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
+{
+	int ret;
+	int len = skb->len;     /* save len */
+
+	/* before obtaining the lock the caller should have checked that
+	   the lp isn't busy */
+	if (isdn_net_lp_busy(lp)) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		goto error;
+	}
+
+	if (!(lp->flags & ISDN_NET_CONNECTED)) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		goto error;
+	}
+	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
+	if (ret != len) {
+		/* we should never get here */
+		printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+		goto error;
+	}
+	
+	lp->transcount += len;
+	isdn_net_inc_frame_cnt(lp);
+	return;
+
+ error:
+	dev_kfree_skb(skb);
+	lp->stats.tx_errors++;
+
+}
+
+
+/*
+ *  Helper function for isdn_net_start_xmit.
+ *  When called, the connection is already established.
+ *  Based on cps-calculation, check if device is overloaded.
+ *  If so, and if a slave exists, trigger dialing for it.
+ *  If any slave is online, deliver packets using a simple round robin
+ *  scheme.
+ *
+ *  Return: 0 on success, !0 on failure.
+ */
+
+static int
+isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
+{
+	isdn_net_dev *nd;
+	isdn_net_local *slp;
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	int retv = 0;
+
+	if (((isdn_net_local *) (ndev->priv))->master) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* For the other encaps the header has already been built */
+#ifdef CONFIG_ISDN_PPP
+	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+		return isdn_ppp_xmit(skb, ndev);
+	}
+#endif
+	nd = ((isdn_net_local *) ndev->priv)->netdev;
+	lp = isdn_net_get_locked_lp(nd);
+	if (!lp) {
+		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
+		return 1;
+	}
+	/* we have our lp locked from now on */
+
+	/* Reset hangup-timeout */
+	lp->huptimer = 0; // FIXME?
+	isdn_net_writebuf_skb(lp, skb);
+	spin_unlock_bh(&lp->xmit_lock);
+
+	/* the following stuff is here for backwards compatibility.
+	 * in future, start-up and hangup of slaves (based on current load)
+	 * should move to userspace and get based on an overall cps
+	 * calculation
+	 */
+	if (lp->cps > lp->triggercps) {
+		if (lp->slave) {
+			if (!lp->sqfull) {
+				/* First time overload: set timestamp only */
+				lp->sqfull = 1;
+				lp->sqfull_stamp = jiffies;
+			} else {
+				/* subsequent overload: if slavedelay exceeded, start dialing */
+				if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
+					slp = lp->slave->priv;
+					if (!(slp->flags & ISDN_NET_CONNECTED)) {
+						isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+					}
+				}
+			}
+		}
+	} else {
+		if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
+			lp->sqfull = 0;
+		}
+		/* this is a hack to allow auto-hangup for slaves on moderate loads */
+		nd->queue = nd->local;
+	}
+
+	return retv;
+
+}
+
+static void
+isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
+{
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	if (!skb)
+		return;
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+		int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
+		if (pullsize > 0) {
+			printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
+			skb_pull(skb, pullsize);
+		}
+	}
+}
+
+
+void isdn_net_tx_timeout(struct net_device * ndev)
+{
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+	printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
+	if (!lp->dialstate){
+		lp->stats.tx_errors++;
+                /*
+		 * There is a certain probability that this currently
+		 * works at all because if we always wake up the interface,
+		 * then upper layer will try to send the next packet
+		 * immediately. And then, the old clean_up logic in the
+		 * driver will hopefully continue to work as it used to do.
+		 *
+		 * This is rather primitive right know, we better should
+		 * clean internal queues here, in particular for multilink and
+		 * ppp, and reset HL driver's channel, too.   --HE
+		 *
+		 * actually, this may not matter at all, because ISDN hardware
+		 * should not see transmitter hangs at all IMO
+		 * changed KERN_DEBUG to KERN_WARNING to find out if this is 
+		 * ever called   --KG
+		 */
+	}
+	ndev->trans_start = jiffies;
+	netif_wake_queue(ndev);
+}
+
+/*
+ * Try sending a packet.
+ * If this interface isn't connected to a ISDN-Channel, find a free channel,
+ * and start dialing.
+ */
+static int
+isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+#ifdef CONFIG_ISDN_X25
+	struct concap_proto * cprot = lp -> netdev -> cprot;
+/* At this point hard_start_xmit() passes control to the encapsulation
+   protocol (if present).
+   For X.25 auto-dialing is completly bypassed because:
+   - It does not conform with the semantics of a reliable datalink
+     service as needed by X.25 PLP.
+   - I don't want that the interface starts dialing when the network layer
+     sends a message which requests to disconnect the lapb link (or if it
+     sends any other message not resulting in data transmission).
+   Instead, dialing will be initiated by the encapsulation protocol entity
+   when a dl_establish request is received from the upper layer.
+*/
+	if (cprot && cprot -> pops) {
+		int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
+
+		if (ret)
+			netif_stop_queue(ndev);
+		return ret;
+	} else
+#endif
+	/* auto-dialing xmit function */
+	{
+#ifdef ISDN_DEBUG_NET_DUMP
+		u_char *buf;
+#endif
+		isdn_net_adjust_hdr(skb, ndev);
+#ifdef ISDN_DEBUG_NET_DUMP
+		buf = skb->data;
+		isdn_dumppkt("S:", buf, skb->len, 40);
+#endif
+
+		if (!(lp->flags & ISDN_NET_CONNECTED)) {
+			int chi;
+			/* only do autodial if allowed by config */
+			if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
+				isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
+				dev_kfree_skb(skb);
+				return 0;
+			}
+			if (lp->phone[1]) {
+				ulong flags;
+
+				if(lp->dialwait_timer <= 0)
+					if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
+						lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
+
+				if(lp->dialwait_timer > 0) {
+					if(time_before(jiffies, lp->dialwait_timer)) {
+						isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
+						dev_kfree_skb(skb);
+						return 0;
+					} else
+						lp->dialwait_timer = 0;
+				}
+				/* Grab a free ISDN-Channel */
+				spin_lock_irqsave(&dev->lock, flags);
+				if (((chi =
+				     isdn_get_free_channel(
+					 		ISDN_USAGE_NET,
+							lp->l2_proto,
+							lp->l3_proto,
+							lp->pre_device,
+						 	lp->pre_channel,
+							lp->msn)
+							) < 0) &&
+					((chi =
+				     isdn_get_free_channel(
+					 		ISDN_USAGE_NET,
+							lp->l2_proto,
+							lp->l3_proto,
+							lp->pre_device,
+							lp->pre_channel^1,
+							lp->msn)
+							) < 0)) {
+					spin_unlock_irqrestore(&dev->lock, flags);
+					isdn_net_unreachable(ndev, skb,
+							   "No channel");
+					dev_kfree_skb(skb);
+					return 0;
+				}
+				/* Log packet, which triggered dialing */
+				if (dev->net_verbose)
+					isdn_net_log_skb(skb, lp);
+				lp->dialstate = 1;
+				/* Connect interface with channel */
+				isdn_net_bind_channel(lp, chi);
+#ifdef CONFIG_ISDN_PPP
+				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+					/* no 'first_skb' handling for syncPPP */
+					if (isdn_ppp_bind(lp) < 0) {
+						dev_kfree_skb(skb);
+						isdn_net_unbind_channel(lp);
+						spin_unlock_irqrestore(&dev->lock, flags);
+						return 0;	/* STN (skb to nirvana) ;) */
+					}
+#ifdef CONFIG_IPPP_FILTER
+					if (isdn_ppp_autodial_filter(skb, lp)) {
+						isdn_ppp_free(lp);
+						isdn_net_unbind_channel(lp);
+						spin_unlock_irqrestore(&dev->lock, flags);
+						isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
+						dev_kfree_skb(skb);
+						return 0;
+					}
+#endif
+					spin_unlock_irqrestore(&dev->lock, flags);
+					isdn_net_dial();	/* Initiate dialing */
+					netif_stop_queue(ndev);
+					return 1;	/* let upper layer requeue skb packet */
+				}
+#endif
+				/* Initiate dialing */
+				spin_unlock_irqrestore(&dev->lock, flags);
+				isdn_net_dial();
+				isdn_net_device_stop_queue(lp);
+				return 1;
+			} else {
+				isdn_net_unreachable(ndev, skb,
+						     "No phone number");
+				dev_kfree_skb(skb);
+				return 0;
+			}
+		} else {
+			/* Device is connected to an ISDN channel */ 
+			ndev->trans_start = jiffies;
+			if (!lp->dialstate) {
+				/* ISDN connection is established, try sending */
+				int ret;
+				ret = (isdn_net_xmit(ndev, skb));
+				if(ret) netif_stop_queue(ndev);
+				return ret;
+			} else
+				netif_stop_queue(ndev);
+		}
+	}
+	return 1;
+}
+
+/*
+ * Shutdown a net-interface.
+ */
 static int
-isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
-		   unsigned short type, void *daddr, void *saddr, 
-		   unsigned plen)
+isdn_net_close(struct net_device *dev)
+{
+	struct net_device *p;
+#ifdef CONFIG_ISDN_X25
+	struct concap_proto * cprot =
+		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+	/* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
+#endif
+
+#ifdef CONFIG_ISDN_X25
+	if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
+#endif
+	netif_stop_queue(dev);
+	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
+		/* If this interface has slaves, stop them also */
+		while (p) {
+#ifdef CONFIG_ISDN_X25
+			cprot = ( (isdn_net_local *) p->priv )
+				-> netdev -> cprot;
+			if( cprot && cprot -> pops )
+				cprot -> pops -> close( cprot );
+#endif
+			isdn_net_hangup(p);
+			p = (((isdn_net_local *) p->priv)->slave);
+		}
+	}
+	isdn_net_hangup(dev);
+	isdn_unlock_drivers();
+	return 0;
+}
+
+/*
+ * Get statistics
+ */
+static struct net_device_stats *
+isdn_net_get_stats(struct net_device *dev)
+{
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	return &lp->stats;
+}
+
+/*      This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
+ *      instead of dev->hard_header_len off. This is done because the
+ *      lowlevel-driver has already pulled off its stuff when we get
+ *      here and this routine only gets called with p_encap == ETHER.
+ *      Determine the packet's protocol ID. The rule here is that we
+ *      assume 802.3 if the type field is short enough to be a length.
+ *      This is normal practice and works for any 'now in use' protocol.
+ */
+
+static unsigned short
+isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb->mac.raw = skb->data;
+	skb_pull(skb, ETH_HLEN);
+	eth = skb->mac.ethernet;
+
+	if (*eth->h_dest & 1) {
+		if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	}
+	/*
+	 *      This ALLMULTI check should be redundant by 1.4
+	 *      so don't forget to remove it.
+	 */
+
+	else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
+		if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	if (ntohs(eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+	/*
+	 *      This is a magic hack to spot IPX packets. Older Novell breaks
+	 *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
+	 *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+	 *      won't work for fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *) rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+	/*
+	 *      Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
+}
+
+
+/* 
+ * CISCO HDLC keepalive specific stuff
+ */
+static struct sk_buff*
+isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
 {
-	put_u16(skb_push(skb, 2), 0x0103);
-	return 2;
+	unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(hl + len, GFP_ATOMIC);
+	if (!skb) {
+		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
+		return 0;
+	}
+	skb_reserve(skb, hl);
+	return skb;
+}
+
+/* cisco hdlck device private ioctls */
+int
+isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	unsigned long len = 0;
+	unsigned long expires = 0;
+	int tmp = 0;
+	int period = lp->cisco_keepalive_period;
+	char debserint = lp->cisco_debserint;
+	int rc = 0;
+
+	if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
+		return -EINVAL;
+
+	switch (cmd) {
+		/* get/set keepalive period */
+		case SIOCGKEEPPERIOD:
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(int *)&lp->cisco_keepalive_period, len))
+				rc = -EFAULT;
+			break;
+		case SIOCSKEEPPERIOD:
+			tmp = lp->cisco_keepalive_period;
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_from_user((int *)&period,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((period > 0) && (period <= 32767))
+				lp->cisco_keepalive_period = period;
+			else
+				rc = -EINVAL;
+			if (!rc && (tmp != lp->cisco_keepalive_period)) {
+				expires = (unsigned long)(jiffies +
+					lp->cisco_keepalive_period * HZ);
+				mod_timer(&lp->cisco_timer, expires);
+				printk(KERN_INFO "%s: Keepalive period set "
+					"to %d seconds.\n",
+					lp->name, lp->cisco_keepalive_period);
+			}
+			break;
+
+		/* get/set debugging */
+		case SIOCGDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(char *)&lp->cisco_debserint, len))
+				rc = -EFAULT;
+			break;
+		case SIOCSDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_from_user((char *)&debserint,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((debserint >= 0) && (debserint <= 64))
+				lp->cisco_debserint = debserint;
+			else
+				rc = -EINVAL;
+			break;
+
+		default:
+			rc = -EINVAL;
+			break;
+	}
+	return (rc);
 }
 
+/* called via cisco_timer.function */
 static void
-isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev, 
-		    struct sk_buff *skb)
+isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
 {
-	skb_pull(skb, 2);
-	isdn_netif_rx(idev, skb, htons(ETH_P_IP));
+	isdn_net_local *lp = (isdn_net_local *) data;
+	struct sk_buff *skb;
+	unsigned char *p;
+	unsigned long last_cisco_myseq = lp->cisco_myseq;
+	int myseq_diff = 0;
+
+	if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		return;
+	}
+	lp->cisco_myseq++;
+
+	myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
+	if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
+		/* line up -> down */
+		lp->cisco_line_state = 0;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to down\n", lp->name);
+		/* should stop routing higher-level data accross */
+	} else if ((!lp->cisco_line_state) &&
+		(myseq_diff >= 0) && (myseq_diff <= 2)) {
+		/* line down -> up */
+		lp->cisco_line_state = 1;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to up\n", lp->name);
+		/* restart routing higher-level data accross */
+	}
+
+	if (lp->cisco_debserint)
+		printk (KERN_DEBUG "%s: HDLC "
+			"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
+			lp->name, last_cisco_myseq, lp->cisco_mineseen,
+			((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
+			lp->cisco_yourseq,
+			((lp->cisco_line_state) ? "line up" : "line down"));
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp keepalive */
+	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
+	p += put_u32(p, lp->cisco_myseq);
+	p += put_u32(p, lp->cisco_yourseq);
+	p += put_u16(p, 0xffff); // reliablity, always 0xffff
+
+	isdn_net_write_super(lp, skb);
+
+	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+	
+	add_timer(&lp->cisco_timer);
 }
 
-struct isdn_netif_ops isdn_uihdlc_ops = {
-	.hard_start_xmit     = isdn_net_start_xmit,
-	.hard_header         = isdn_uihdlc_header,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_HDLC,
-	.addr_len            = 2,
-	.receive             = isdn_uihdlc_receive,
-};
+static void
+isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
 
-// ISDN_NET_ENCAP_RAWIP
-// RAW-IP without MAC-Header
-// ======================================================================
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp request */
+	p += put_u32(p, CISCO_SLARP_REQUEST);
+	p += put_u32(p, 0); // address
+	p += put_u32(p, 0); // netmask
+	p += put_u16(p, 0); // unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void 
+isdn_net_ciscohdlck_connected(isdn_net_local *lp)
+{
+	lp->cisco_myseq = 0;
+	lp->cisco_mineseen = 0;
+	lp->cisco_yourseq = 0;
+	lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
+	lp->cisco_last_slarp_in = 0;
+	lp->cisco_line_state = 0;
+	lp->cisco_debserint = 0;
+
+	/* send slarp request because interface/seq.no.s reset */
+	isdn_net_ciscohdlck_slarp_send_request(lp);
+
+	init_timer(&lp->cisco_timer);
+	lp->cisco_timer.data = (unsigned long) lp;
+	lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
+	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+	add_timer(&lp->cisco_timer);
+}
+
+static void 
+isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
+{
+	del_timer(&lp->cisco_timer);
+}
 
 static void
-isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev, 
-		   struct sk_buff *skb)
+isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
 {
-	idev->huptimer = 0;
-	skb->protocol = htons(ETH_P_IP);
+	struct sk_buff *skb;
+	unsigned char *p;
+	struct in_device *in_dev = NULL;
+	u32 addr = 0;		/* local ipv4 address */
+	u32 mask = 0;		/* local netmask */
+
+	if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+		/* take primary(first) address of interface */
+		struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa != NULL) {
+			addr = ifa->ifa_local;
+			mask = ifa->ifa_mask;
+		}
+	}
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp reply, send own ip/netmask; if values are nonsense remote
+	 * should think we are unable to provide it with an address via SLARP */
+	p += put_u32(p, CISCO_SLARP_REPLY);
+	p += put_u32(p, addr);	// address
+	p += put_u32(p, mask);	// netmask
+	p += put_u16(p, 0);	// unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+{
+	unsigned char *p;
+	int period;
+	u32 code;
+	u32 my_seq, addr;
+	u32 your_seq, mask;
+	u32 local;
+	u16 unused;
+
+	if (skb->len < 14)
+		return;
+
+	p = skb->data;
+	p += get_u32(p, &code);
+	
+	switch (code) {
+	case CISCO_SLARP_REQUEST:
+		lp->cisco_yourseq = 0;
+		isdn_net_ciscohdlck_slarp_send_reply(lp);
+		break;
+	case CISCO_SLARP_REPLY:
+		addr = ntohl(*(u32 *)p);
+		mask = ntohl(*(u32 *)(p+4));
+		if (mask != 0xfffffffc)
+			goto slarp_reply_out;
+		if ((addr & 3) == 0 || (addr & 3) == 3)
+			goto slarp_reply_out;
+		local = addr ^ 3;
+		printk(KERN_INFO "%s: got slarp reply: "
+			"remote ip: %d.%d.%d.%d, "
+			"local ip: %d.%d.%d.%d "
+			"mask: %d.%d.%d.%d\n",
+		       lp->name,
+		       HIPQUAD(addr),
+		       HIPQUAD(local),
+		       HIPQUAD(mask));
+		break;
+  slarp_reply_out:
+		 printk(KERN_INFO "%s: got invalid slarp "
+				 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
+				 "- ignored\n", lp->name,
+				 HIPQUAD(addr), HIPQUAD(mask));
+		break;
+	case CISCO_SLARP_KEEPALIVE:
+		period = (int)((jiffies - lp->cisco_last_slarp_in
+				+ HZ/2 - 1) / HZ);
+		if (lp->cisco_debserint &&
+				(period != lp->cisco_keepalive_period) &&
+				lp->cisco_last_slarp_in) {
+			printk(KERN_DEBUG "%s: Keepalive period mismatch - "
+				"is %d but should be %d.\n",
+				lp->name, period, lp->cisco_keepalive_period);
+		}
+		lp->cisco_last_slarp_in = jiffies;
+		p += get_u32(p, &my_seq);
+		p += get_u32(p, &your_seq);
+		p += get_u16(p, &unused);
+		lp->cisco_yourseq = my_seq;
+		lp->cisco_mineseen = your_seq;
+		break;
+	}
+}
+
+static void
+isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
+{
+	unsigned char *p;
+ 	u8 addr;
+ 	u8 ctrl;
+ 	u16 type;
+	
+	if (skb->len < 4)
+		goto out_free;
+
+	p = skb->data;
+	p += get_u8 (p, &addr);
+	p += get_u8 (p, &ctrl);
+	p += get_u16(p, &type);
+	skb_pull(skb, 4);
+	
+	if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
+		printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
+		       lp->name, addr);
+		goto out_free;
+	}
+	if (ctrl != CISCO_CTRL) {
+		printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
+		       lp->name, ctrl);
+		goto out_free;
+	}
+
+	switch (type) {
+	case CISCO_TYPE_SLARP:
+		isdn_net_ciscohdlck_slarp_in(lp, skb);
+		goto out_free;
+	case CISCO_TYPE_CDP:
+		if (lp->cisco_debserint)
+			printk(KERN_DEBUG "%s: Received CDP packet. use "
+				"\"no cdp enable\" on cisco.\n", lp->name);
+		goto out_free;
+	default:
+		/* no special cisco protocol */
+		skb->protocol = htons(type);
+		netif_rx(skb);
+		return;
+	}
+
+ out_free:
+	kfree_skb(skb);
+}
+
+/*
+ * Got a packet from ISDN-Channel.
+ */
+static void
+isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
+{
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *olp = lp;	/* original 'lp' */
+#ifdef CONFIG_ISDN_X25
+	struct concap_proto *cprot = lp -> netdev -> cprot;
+#endif
+	lp->transcount += skb->len;
+
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes += skb->len;
+	if (lp->master) {
+		/* Bundling: If device is a slave-device, deliver to master, also
+		 * handle master's statistics and hangup-timeout
+		 */
+		ndev = lp->master;
+		lp = (isdn_net_local *) ndev->priv;
+		lp->stats.rx_packets++;
+		lp->stats.rx_bytes += skb->len;
+	}
+	skb->dev = ndev;
+	skb->pkt_type = PACKET_HOST;
+	skb->mac.raw = skb->data;
+#ifdef ISDN_DEBUG_NET_DUMP
+	isdn_dumppkt("R:", skb->data, skb->len, 40);
+#endif
+	switch (lp->p_encap) {
+		case ISDN_NET_ENCAP_ETHER:
+			/* Ethernet over ISDN */
+			olp->huptimer = 0;
+			lp->huptimer = 0;
+			skb->protocol = isdn_net_type_trans(skb, ndev);
+			break;
+		case ISDN_NET_ENCAP_UIHDLC:
+			/* HDLC with UI-frame (for ispa with -h1 option) */
+			olp->huptimer = 0;
+			lp->huptimer = 0;
+			skb_pull(skb, 2);
+			/* Fall through */
+		case ISDN_NET_ENCAP_RAWIP:
+			/* RAW-IP without MAC-Header */
+			olp->huptimer = 0;
+			lp->huptimer = 0;
+			skb->protocol = htons(ETH_P_IP);
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLCK:
+			isdn_net_ciscohdlck_receive(lp, skb);
+			return;
+		case ISDN_NET_ENCAP_CISCOHDLC:
+			/* CISCO-HDLC IP with type field and  fake I-frame-header */
+			skb_pull(skb, 2);
+			/* Fall through */
+		case ISDN_NET_ENCAP_IPTYP:
+			/* IP with type field */
+			olp->huptimer = 0;
+			lp->huptimer = 0;
+			skb->protocol = *(unsigned short *) &(skb->data[0]);
+			skb_pull(skb, 2);
+			if (*(unsigned short *) skb->data == 0xFFFF)
+				skb->protocol = htons(ETH_P_802_3);
+			break;
+#ifdef CONFIG_ISDN_PPP
+		case ISDN_NET_ENCAP_SYNCPPP:
+			/* huptimer is done in isdn_ppp_push_higher */
+			isdn_ppp_receive(lp->netdev, olp, skb);
+			return;
+#endif
+
+		default:
+#ifdef CONFIG_ISDN_X25
+		  /* try if there are generic sync_device receiver routines */
+			if(cprot) if(cprot -> pops)
+				if( cprot -> pops -> data_ind){
+					cprot -> pops -> data_ind(cprot,skb);
+					return;
+				};
+#endif /* CONFIG_ISDN_X25 */
+			printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
+			       lp->name);
+			kfree_skb(skb);
+			return;
+	}
+
 	netif_rx(skb);
+	return;
 }
 
-struct isdn_netif_ops isdn_rawip_ops = {
-	.hard_start_xmit     = isdn_net_start_xmit,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_PPP,
-	.receive             = isdn_rawip_receive,
-};
+/*
+ * A packet arrived via ISDN. Search interface-chain for a corresponding
+ * interface. If found, deliver packet to receiver-function and return 1,
+ * else return 0.
+ */
+int
+isdn_net_rcv_skb(int idx, struct sk_buff *skb)
+{
+	isdn_net_dev *p = dev->rx_netdev[idx];
+
+	if (p) {
+		isdn_net_local *lp = p->local;
+		if ((lp->flags & ISDN_NET_CONNECTED) &&
+		    (!lp->dialstate)) {
+			isdn_net_receive(&p->dev, skb);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int
+my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+	      void *daddr, void *saddr, unsigned len)
+{
+	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	/*
+	 * Set the protocol type. For a packet of type ETH_P_802_3 we
+	 * put the length here instead. It is up to the 802.2 layer to
+	 * carry protocol information.
+	 */
+
+	if (type != ETH_P_802_3)
+		eth->h_proto = htons(type);
+	else
+		eth->h_proto = htons(len);
+
+	/*
+	 * Set the source hardware address.
+	 */
+	if (saddr)
+		memcpy(eth->h_source, saddr, dev->addr_len);
+	else
+		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+
+	/*
+	 * Anyway, the loopback-device should never use this function...
+	 */
+
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+		memset(eth->h_dest, 0, dev->addr_len);
+		return ETH_HLEN /*(dev->hard_header_len)*/;
+	}
+	if (daddr) {
+		memcpy(eth->h_dest, daddr, dev->addr_len);
+		return ETH_HLEN /*dev->hard_header_len*/;
+	}
+	return -ETH_HLEN /*dev->hard_header_len*/;
+}
+
+/*
+ *  build an header
+ *  depends on encaps that is being used.
+ */
+
+static int
+isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+		void *daddr, void *saddr, unsigned plen)
+{
+	isdn_net_local *lp = dev->priv;
+	unsigned char *p;
+	ushort len = 0;
+
+	switch (lp->p_encap) {
+		case ISDN_NET_ENCAP_ETHER:
+			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+			break;
+#ifdef CONFIG_ISDN_PPP
+		case ISDN_NET_ENCAP_SYNCPPP:
+			/* stick on a fake header to keep fragmentation code happy. */
+			len = IPPP_MAX_HEADER;
+			skb_push(skb,len);
+			break;
+#endif
+		case ISDN_NET_ENCAP_RAWIP:
+			printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
+			len = 0;
+			break;
+		case ISDN_NET_ENCAP_IPTYP:
+			/* ethernet type field */
+			*((ushort *) skb_push(skb, 2)) = htons(type);
+			len = 2;
+			break;
+		case ISDN_NET_ENCAP_UIHDLC:
+			/* HDLC with UI-Frames (for ispa with -h1 option) */
+			*((ushort *) skb_push(skb, 2)) = htons(0x0103);
+			len = 2;
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLC:
+		case ISDN_NET_ENCAP_CISCOHDLCK:
+			p = skb_push(skb, 4);
+			p += put_u8 (p, CISCO_ADDR_UNICAST);
+			p += put_u8 (p, CISCO_CTRL);
+			p += put_u16(p, type);
+			len = 4;
+			break;
+#ifdef CONFIG_ISDN_X25
+		default:
+		  /* try if there are generic concap protocol routines */
+			if( lp-> netdev -> cprot ){
+				printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
+				len = 0;
+				break;
+			}
+			break;
+#endif /* CONFIG_ISDN_X25 */
+	}
+	return len;
+}
+
+/* We don't need to send arp, because we have point-to-point connections. */
+static int
+isdn_net_rebuild_header(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	isdn_net_local *lp = dev->priv;
+	int ret = 0;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+		struct ethhdr *eth = (struct ethhdr *) skb->data;
+
+		/*
+		 *      Only ARP/IP is currently supported
+		 */
+
+		if (eth->h_proto != htons(ETH_P_IP)) {
+			printk(KERN_WARNING
+			       "isdn_net: %s don't know how to resolve type %d addresses?\n",
+			       dev->name, (int) eth->h_proto);
+			memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+			return 0;
+		}
+		/*
+		 *      Try to get ARP to resolve the header.
+		 */
+#ifdef CONFIG_INET
+		ret = arp_find(eth->h_dest, skb);
+#endif
+	}
+	return ret;
+}
 
-// ISDN_NET_ENCAP_ETHER
-// Ethernet over ISDN
-// ======================================================================
+/*
+ * Interface-setup. (just after registering a new interface)
+ */
+static int
+isdn_net_init(struct net_device *ndev)
+{
+	ushort max_hlhdr_len = 0;
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	int drvidx, i;
+
+	ether_setup(ndev);
+	lp->org_hhc = ndev->hard_header_cache;
+	lp->org_hcu = ndev->header_cache_update;
+
+	/* Setup the generic properties */
+
+	ndev->hard_header = NULL;
+	ndev->hard_header_cache = NULL;
+	ndev->header_cache_update = NULL;
+	ndev->mtu = 1500;
+	ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
+	ndev->type = ARPHRD_ETHER;
+	ndev->addr_len = ETH_ALEN;
+
+	/* for clients with MPPP maybe higher values better */
+	ndev->tx_queue_len = 30;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		ndev->broadcast[i] = 0xff;
+
+	/* The ISDN-specific entries in the device structure. */
+	ndev->open = &isdn_net_open;
+	ndev->hard_start_xmit = &isdn_net_start_xmit;
+
+	/*
+	 *  up till binding we ask the protocol layer to reserve as much
+	 *  as we might need for HL layer
+	 */
+
+	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
+		if (dev->drv[drvidx])
+			if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
+				max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
+
+	ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
+	ndev->stop = &isdn_net_close;
+	ndev->get_stats = &isdn_net_get_stats;
+	ndev->rebuild_header = &isdn_net_rebuild_header;
+	ndev->do_ioctl = NULL;
+	return 0;
+}
+
+static void
+isdn_net_swapbind(int drvidx)
+{
+	isdn_net_dev *p;
+
+#ifdef ISDN_DEBUG_NET_ICALL
+	printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
+#endif
+	p = dev->netdev;
+	while (p) {
+		if (p->local->pre_device == drvidx)
+			switch (p->local->pre_channel) {
+				case 0:
+					p->local->pre_channel = 1;
+					break;
+				case 1:
+					p->local->pre_channel = 0;
+					break;
+			}
+		p = (isdn_net_dev *) p->next;
+	}
+}
 
 static void
-isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev, 
-		   struct sk_buff *skb)
+isdn_net_swap_usage(int i1, int i2)
+{
+	int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
+	int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
+
+#ifdef ISDN_DEBUG_NET_ICALL
+	printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
+#endif
+	dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
+	dev->usage[i1] |= u2;
+	dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
+	dev->usage[i2] |= u1;
+	isdn_info_update();
+}
+
+/*
+ * An incoming call-request has arrived.
+ * Search the interface-chain for an appropriate interface.
+ * If found, connect the interface to the ISDN-channel and initiate
+ * D- and B-Channel-setup. If secure-flag is set, accept only
+ * configured phone-numbers. If callback-flag is set, initiate
+ * callback-dialing.
+ *
+ * Return-Value: 0 = No appropriate interface for this call.
+ *               1 = Call accepted
+ *               2 = Reject call, wait cbdelay, then call back
+ *               3 = Reject call
+ *               4 = Wait cbdelay, then call back
+ *               5 = No appropriate interface for this call,
+ *                   would eventually match if CID was longer.
+ */
+
+int
+isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
 {
-	isdn_netif_rx(idev, skb, eth_type_trans(skb, &lp->dev));
+	char *eaz;
+	int si1;
+	int si2;
+	int ematch;
+	int wret;
+	int swapped;
+	int sidx = 0;
+	u_long flags;
+	isdn_net_dev *p;
+	isdn_net_phone *n;
+	char nr[32];
+	char *my_eaz;
+
+	/* Search name in netdev-chain */
+	if (!setup->phone[0]) {
+		nr[0] = '0';
+		nr[1] = '\0';
+		printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
+	} else
+		strcpy(nr, setup->phone);
+	si1 = (int) setup->si1;
+	si2 = (int) setup->si2;
+	if (!setup->eazmsn[0]) {
+		printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
+		eaz = "0";
+	} else
+		eaz = setup->eazmsn;
+	if (dev->net_verbose > 1)
+		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
+	/* Accept DATA and VOICE calls at this stage
+	 * local eaz is checked later for allowed call types
+	 */
+	if ((si1 != 7) && (si1 != 1)) {
+		if (dev->net_verbose > 1)
+			printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
+		return 0;
+	}
+	n = (isdn_net_phone *) 0;
+	p = dev->netdev;
+	ematch = wret = swapped = 0;
+#ifdef ISDN_DEBUG_NET_ICALL
+	printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
+		dev->usage[idx]);
+#endif
+	while (p) {
+		int matchret;
+		isdn_net_local *lp = p->local;
+
+		/* If last check has triggered as binding-swap, revert it */
+		switch (swapped) {
+			case 2:
+				isdn_net_swap_usage(idx, sidx);
+				/* fall through */
+			case 1:
+				isdn_net_swapbind(di);
+				break;
+		}
+		swapped = 0;
+                /* check acceptable call types for DOV */
+                my_eaz = isdn_map_eaz2msn(lp->msn, di);
+                if (si1 == 1) { /* it's a DOV call, check if we allow it */
+                        if (*my_eaz == 'v' || *my_eaz == 'V' ||
+			    *my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                        else
+                                my_eaz = 0; /* force non match */
+                } else { /* it's a DATA call, check if we allow it */
+                        if (*my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                }
+                if (my_eaz)
+                        matchret = isdn_msncmp(eaz, my_eaz);
+                else
+                        matchret = 1;
+                if (!matchret)
+                        ematch = 1;
+
+		/* Remember if more numbers eventually can match */
+		if (matchret > wret)
+			wret = matchret;
+#ifdef ISDN_DEBUG_NET_ICALL
+		printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
+		       lp->name, lp->msn, lp->flags, lp->dialstate);
+#endif
+		if ((!matchret) &&                                        /* EAZ is matching   */
+		    (((!(lp->flags & ISDN_NET_CONNECTED)) &&              /* but not connected */
+		      (USG_NONE(dev->usage[idx]))) ||                     /* and ch. unused or */
+		     ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing        */
+		       (!(lp->flags & ISDN_NET_CALLBACK)))                /* but no callback   */
+		     )))
+			 {
+#ifdef ISDN_DEBUG_NET_ICALL
+			printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
+			       lp->pre_device, lp->pre_channel);
+#endif
+			if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
+				if ((lp->pre_channel != ch) ||
+				    (lp->pre_device != di)) {
+					/* Here we got a problem:
+					 * If using an ICN-Card, an incoming call is always signaled on
+					 * on the first channel of the card, if both channels are
+					 * down. However this channel may be bound exclusive. If the
+					 * second channel is free, this call should be accepted.
+					 * The solution is horribly but it runs, so what:
+					 * We exchange the exclusive bindings of the two channels, the
+					 * corresponding variables in the interface-structs.
+					 */
+					if (ch == 0) {
+						sidx = isdn_dc2minor(di, 1);
+#ifdef ISDN_DEBUG_NET_ICALL
+						printk(KERN_DEBUG "n_fi: ch is 0\n");
+#endif
+						if (USG_NONE(dev->usage[sidx])) {
+							/* Second Channel is free, now see if it is bound
+							 * exclusive too. */
+							if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
+#ifdef ISDN_DEBUG_NET_ICALL
+								printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
+#endif
+								/* Yes, swap bindings only, if the original
+								 * binding is bound to channel 1 of this driver */
+								if ((lp->pre_device == di) &&
+								    (lp->pre_channel == 1)) {
+									isdn_net_swapbind(di);
+									swapped = 1;
+								} else {
+									/* ... else iterate next device */
+									p = (isdn_net_dev *) p->next;
+									continue;
+								}
+							} else {
+#ifdef ISDN_DEBUG_NET_ICALL
+								printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
+#endif
+								/* No, swap always and swap excl-usage also */
+								isdn_net_swap_usage(idx, sidx);
+								isdn_net_swapbind(di);
+								swapped = 2;
+							}
+							/* Now check for exclusive binding again */
+#ifdef ISDN_DEBUG_NET_ICALL
+							printk(KERN_DEBUG "n_fi: final check\n");
+#endif
+							if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
+							    ((lp->pre_channel != ch) ||
+							     (lp->pre_device != di))) {
+#ifdef ISDN_DEBUG_NET_ICALL
+								printk(KERN_DEBUG "n_fi: final check failed\n");
+#endif
+								p = (isdn_net_dev *) p->next;
+								continue;
+							}
+						}
+					} else {
+						/* We are already on the second channel, so nothing to do */
+#ifdef ISDN_DEBUG_NET_ICALL
+						printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
+#endif
+					}
+				}
+			}
+#ifdef ISDN_DEBUG_NET_ICALL
+			printk(KERN_DEBUG "n_fi: match2\n");
+#endif
+			n = lp->phone[0];
+			if (lp->flags & ISDN_NET_SECURE) {
+				while (n) {
+					if (!isdn_msncmp(nr, n->num))
+						break;
+					n = (isdn_net_phone *) n->next;
+				}
+			}
+			if (n || (!(lp->flags & ISDN_NET_SECURE))) {
+#ifdef ISDN_DEBUG_NET_ICALL
+				printk(KERN_DEBUG "n_fi: match3\n");
+#endif
+				/* matching interface found */
+
+				/*
+				 * Is the state STOPPED?
+				 * If so, no dialin is allowed,
+				 * so reject actively.
+				 * */
+				if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+					printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
+					       lp->name);
+					return 3;
+				}
+				/*
+				 * Is the interface up?
+				 * If not, reject the call actively.
+				 */
+				if (!isdn_net_device_started(p)) {
+					printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
+					       lp->name);
+					return 3;
+				}
+				/* Interface is up, now see if it's a slave. If so, see if
+				 * it's master and parent slave is online. If not, reject the call.
+				 */
+				if (lp->master) {
+					isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
+					printk(KERN_DEBUG "ICALLslv: %s\n", lp->name);
+					printk(KERN_DEBUG "master=%s\n", mlp->name);
+					if (mlp->flags & ISDN_NET_CONNECTED) {
+						printk(KERN_DEBUG "master online\n");
+						/* Master is online, find parent-slave (master if first slave) */
+						while (mlp->slave) {
+							if ((isdn_net_local *) mlp->slave->priv == lp)
+								break;
+							mlp = (isdn_net_local *) mlp->slave->priv;
+						}
+					} else
+						printk(KERN_DEBUG "master offline\n");
+					/* Found parent, if it's offline iterate next device */
+					printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
+					if (!(mlp->flags & ISDN_NET_CONNECTED)) {
+						p = (isdn_net_dev *) p->next;
+						continue;
+					}
+				} 
+				if (lp->flags & ISDN_NET_CALLBACK) {
+					int chi;
+					/*
+					 * Is the state MANUAL?
+					 * If so, no callback can be made,
+					 * so reject actively.
+					 * */
+					if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+						printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
+						       lp->name);
+						return 3;
+					}
+					printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
+					       lp->name, nr, eaz);
+					if (lp->phone[1]) {
+						/* Grab a free ISDN-Channel */
+						spin_lock_irqsave(&dev->lock, flags);
+						if ((chi = 
+							isdn_get_free_channel(
+								ISDN_USAGE_NET,
+								lp->l2_proto,
+								lp->l3_proto,
+							  	lp->pre_device,
+						 		lp->pre_channel,
+						 		lp->msn)
+								) < 0) {
+
+							printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
+							spin_unlock_irqrestore(&dev->lock, flags);
+							return 0;
+						}
+						/* Setup dialstate. */
+						lp->dtimer = 0;
+						lp->dialstate = 11;
+						/* Connect interface with channel */
+						isdn_net_bind_channel(lp, chi);
+#ifdef CONFIG_ISDN_PPP
+						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+							if (isdn_ppp_bind(lp) < 0) {
+								spin_unlock_irqrestore(&dev->lock, flags);
+								isdn_net_unbind_channel(lp);
+								return 0;
+							}
+#endif
+						spin_unlock_irqrestore(&dev->lock, flags);
+						/* Initiate dialing by returning 2 or 4 */
+						return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
+					} else
+						printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
+					return 0;
+				} else {
+					printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
+					       eaz);
+					/* if this interface is dialing, it does it probably on a different
+					   device, so free this device */
+					if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
+#ifdef CONFIG_ISDN_PPP
+						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+							isdn_ppp_free(lp);
+#endif
+						isdn_net_lp_disconnected(lp);
+						isdn_free_channel(lp->isdn_device, lp->isdn_channel,
+							 ISDN_USAGE_NET);
+					}
+					spin_lock_irqsave(&dev->lock, flags);
+					dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
+					dev->usage[idx] |= ISDN_USAGE_NET;
+					strcpy(dev->num[idx], nr);
+					isdn_info_update();
+					dev->st_netdev[idx] = lp->netdev;
+					lp->isdn_device = di;
+					lp->isdn_channel = ch;
+					lp->ppp_slot = -1;
+					lp->flags |= ISDN_NET_CONNECTED;
+					lp->dialstate = 7;
+					lp->dtimer = 0;
+					lp->outgoing = 0;
+					lp->huptimer = 0;
+					lp->hupflags |= ISDN_WAITCHARGE;
+					lp->hupflags &= ~ISDN_HAVECHARGE;
+#ifdef CONFIG_ISDN_PPP
+					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+						if (isdn_ppp_bind(lp) < 0) {
+							isdn_net_unbind_channel(lp);
+							spin_unlock_irqrestore(&dev->lock, flags);
+							return 0;
+						}
+					}
+#endif
+					spin_unlock_irqrestore(&dev->lock, flags);
+					return 1;
+				}
+			}
+		}
+		p = (isdn_net_dev *) p->next;
+	}
+	/* If none of configured EAZ/MSN matched and not verbose, be silent */
+	if (!ematch || dev->net_verbose)
+		printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
+	return (wret == 2)?5:0;
 }
 
+/*
+ * Search list of net-interfaces for an interface with given name.
+ */
+isdn_net_dev *
+isdn_net_findif(char *name)
+{
+	isdn_net_dev *p = dev->netdev;
+
+	while (p) {
+		if (!strcmp(p->local->name, name))
+			return p;
+		p = (isdn_net_dev *) p->next;
+	}
+	return (isdn_net_dev *) NULL;
+}
+
+/*
+ * Force a net-interface to dial out.
+ * This is called from the userlevel-routine below or
+ * from isdn_net_start_xmit().
+ */
+int
+isdn_net_force_dial_lp(isdn_net_local * lp)
+{
+	if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
+		int chi;
+		if (lp->phone[1]) {
+			ulong flags;
+
+			/* Grab a free ISDN-Channel */
+			spin_lock_irqsave(&dev->lock, flags);
+			if ((chi = isdn_get_free_channel(
+					ISDN_USAGE_NET,
+					lp->l2_proto,
+					lp->l3_proto,
+					lp->pre_device,
+					lp->pre_channel,
+					lp->msn)) < 0) {
+				printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				return -EAGAIN;
+			}
+			lp->dialstate = 1;
+			/* Connect interface with channel */
+			isdn_net_bind_channel(lp, chi);
+#ifdef CONFIG_ISDN_PPP
+			if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+				if (isdn_ppp_bind(lp) < 0) {
+					isdn_net_unbind_channel(lp);
+					spin_unlock_irqrestore(&dev->lock, flags);
+					return -EAGAIN;
+				}
+#endif
+			/* Initiate dialing */
+			spin_unlock_irqrestore(&dev->lock, flags);
+			isdn_net_dial();
+			return 0;
+		} else
+			return -EINVAL;
+	} else
+		return -EBUSY;
+}
+
+/*
+ * This is called from certain upper protocol layers (multilink ppp
+ * and x25iface encapsulation module) that want to initiate dialing
+ * themselves.
+ */
+int
+isdn_net_dial_req(isdn_net_local * lp)
+{
+	/* is there a better error code? */
+	if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
+
+	return isdn_net_force_dial_lp(lp);
+}
+
+/*
+ * Force a net-interface to dial out.
+ * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
+ */
+int
+isdn_net_force_dial(char *name)
+{
+	isdn_net_dev *p = isdn_net_findif(name);
+
+	if (!p)
+		return -ENODEV;
+	return (isdn_net_force_dial_lp(p->local));
+}
+
+/*
+ * Allocate a new network-interface and initialize its data structures.
+ */
+char *
+isdn_net_new(char *name, struct net_device *master)
+{
+	isdn_net_dev *netdev;
+
+	/* Avoid creating an existing interface */
+	if (isdn_net_findif(name)) {
+		printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
+		return NULL;
+	}
+	if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
+		printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
+		return NULL;
+	}
+	memset(netdev, 0, sizeof(isdn_net_dev));
+	if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
+		printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+		kfree(netdev);
+		return NULL;
+	}
+	memset(netdev->local, 0, sizeof(isdn_net_local));
+	if (name == NULL)
+		strcpy(netdev->local->name, "         ");
+	else
+		strcpy(netdev->local->name, name);
+	strcpy(netdev->dev.name, netdev->local->name);
+	netdev->dev.priv = netdev->local;
+	netdev->dev.init = isdn_net_init;
+	netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
+	if (master) {
+		/* Device shall be a slave */
+		struct net_device *p = (((isdn_net_local *) master->priv)->slave);
+		struct net_device *q = master;
+
+		netdev->local->master = master;
+		/* Put device at end of slave-chain */
+		while (p) {
+			q = p;
+			p = (((isdn_net_local *) p->priv)->slave);
+		}
+		((isdn_net_local *) q->priv)->slave = &(netdev->dev);
+	} else {
+		/* Device shall be a master */
+		/*
+		 * Watchdog timer (currently) for master only.
+		 */
+		netdev->dev.tx_timeout = isdn_net_tx_timeout;
+		netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
+		if (register_netdev(&netdev->dev) != 0) {
+			printk(KERN_WARNING "isdn_net: Could not register net-device\n");
+			kfree(netdev->local);
+			kfree(netdev);
+			return NULL;
+		}
+	}
+	netdev->local->magic = ISDN_NET_MAGIC;
+
+	netdev->queue = netdev->local;
+	spin_lock_init(&netdev->queue_lock);
+
+	netdev->local->last = netdev->local;
+	netdev->local->netdev = netdev;
+	netdev->local->next = netdev->local;
+
+	INIT_WORK(&netdev->local->tqueue, (void *)(void *) isdn_net_softint, netdev->local);
+	spin_lock_init(&netdev->local->xmit_lock);
+
+	netdev->local->isdn_device = -1;
+	netdev->local->isdn_channel = -1;
+	netdev->local->pre_device = -1;
+	netdev->local->pre_channel = -1;
+	netdev->local->exclusive = -1;
+	netdev->local->ppp_slot = -1;
+	netdev->local->pppbind = -1;
+	skb_queue_head_init(&netdev->local->super_tx_queue);
+	netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
+	netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
+	netdev->local->triggercps = 6000;
+	netdev->local->slavedelay = 10 * HZ;
+	netdev->local->hupflags = ISDN_INHUP;	/* Do hangup even on incoming calls */
+	netdev->local->onhtime = 10;	/* Default hangup-time for saving costs
+	   of those who forget configuring this */
+	netdev->local->dialmax = 1;
+	netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;	/* Hangup before Callback, manual dial */
+	netdev->local->cbdelay = 25;	/* Wait 5 secs before Callback */
+	netdev->local->dialtimeout = -1;  /* Infinite Dial-Timeout */
+	netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+	netdev->local->dialstarted = 0;   /* Jiffies of last dial-start */
+	netdev->local->dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
+
+	/* Put into to netdev-chain */
+	netdev->next = (void *) dev->netdev;
+	dev->netdev = netdev;
+	return netdev->dev.name;
+}
+
+char *
+isdn_net_newslave(char *parm)
+{
+	char *p = strchr(parm, ',');
+	isdn_net_dev *n;
+	char newname[10];
+
+	if (p) {
+		/* Slave-Name MUST not be empty */
+		if (!strlen(p + 1))
+			return NULL;
+		strcpy(newname, p + 1);
+		*p = 0;
+		/* Master must already exist */
+		if (!(n = isdn_net_findif(parm)))
+			return NULL;
+		/* Master must be a real interface, not a slave */
+		if (n->local->master)
+			return NULL;
+		/* Master must not be started yet */
+		if (isdn_net_device_started(n)) 
+			return NULL;
+		return (isdn_net_new(newname, &(n->dev)));
+	}
+	return NULL;
+}
+
+/*
+ * Set interface-parameters.
+ * Always set all parameters, so the user-level application is responsible
+ * for not overwriting existing setups. It has to get the current
+ * setup first, if only selected parameters are to be changed.
+ */
+int
+isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
+{
+	isdn_net_dev *p = isdn_net_findif(cfg->name);
+	ulong features;
+	int i;
+	int drvidx;
+	int chidx;
+	char drvid[25];
+
+	if (p) {
+		isdn_net_local *lp = p->local;
+
+		/* See if any registered driver supports the features we want */
+		features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
+			((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
+		for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+			if (dev->drv[i])
+				if ((dev->drv[i]->interface->features & features) == features)
+					break;
+		if (i == ISDN_MAX_DRIVERS) {
+			printk(KERN_WARNING "isdn_net: No driver with selected features\n");
+			return -ENODEV;
+		}
+		if (lp->p_encap != cfg->p_encap){
+#ifdef CONFIG_ISDN_X25
+			struct concap_proto * cprot = p -> cprot;
+#endif
+			if (isdn_net_device_started(p)) {
+				printk(KERN_WARNING "%s: cannot change encap when if is up\n",
+				       lp->name);
+				return -EBUSY;
+			}
+#ifdef CONFIG_ISDN_X25
+			if( cprot && cprot -> pops )
+				cprot -> pops -> proto_del ( cprot );
+			p -> cprot = NULL;
+			lp -> dops = NULL;
+			/* ... ,  prepare for configuration of new one ... */
+			switch ( cfg -> p_encap ){
+			case ISDN_NET_ENCAP_X25IFACE:
+				lp -> dops = &isdn_concap_reliable_dl_dops;
+			}
+			/* ... and allocate new one ... */
+			p -> cprot = isdn_concap_new( cfg -> p_encap );
+			/* p -> cprot == NULL now if p_encap is not supported
+			   by means of the concap_proto mechanism */
+			/* the protocol is not configured yet; this will
+			   happen later when isdn_net_reset() is called */
+#endif
+		}
+		switch ( cfg->p_encap ) {
+		case ISDN_NET_ENCAP_SYNCPPP:
+#ifndef CONFIG_ISDN_PPP
+			printk(KERN_WARNING "%s: SyncPPP support not configured\n",
+			       lp->name);
+			return -EINVAL;
+#else
+			p->dev.type = ARPHRD_PPP;	/* change ARP type */
+			p->dev.addr_len = 0;
+			p->dev.do_ioctl = isdn_ppp_dev_ioctl;
+#endif
+			break;
+		case ISDN_NET_ENCAP_X25IFACE:
+#ifndef CONFIG_ISDN_X25
+			printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
+			       p->local->name);
+			return -EINVAL;
+#else
+			p->dev.type = ARPHRD_X25;	/* change ARP type */
+			p->dev.addr_len = 0;
+#endif
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLCK:
+			p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
+			break;
+		default:
+			if( cfg->p_encap >= 0 &&
+			    cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
+				break;
+			printk(KERN_WARNING
+			       "%s: encapsulation protocol %d not supported\n",
+			       p->local->name, cfg->p_encap);
+			return -EINVAL;
+		}
+		if (strlen(cfg->drvid)) {
+			/* A bind has been requested ... */
+			char *c,
+			*e;
+
+			drvidx = -1;
+			chidx = -1;
+			strcpy(drvid, cfg->drvid);
+			if ((c = strchr(drvid, ','))) {
+				/* The channel-number is appended to the driver-Id with a comma */
+				chidx = (int) simple_strtoul(c + 1, &e, 10);
+				if (e == c)
+					chidx = -1;
+				*c = '\0';
+			}
+			for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+				/* Lookup driver-Id in array */
+				if (!(strcmp(dev->drvid[i], drvid))) {
+					drvidx = i;
+					break;
+				}
+			if ((drvidx == -1) || (chidx == -1))
+				/* Either driver-Id or channel-number invalid */
+				return -ENODEV;
+		} else {
+			/* Parameters are valid, so get them */
+			drvidx = lp->pre_device;
+			chidx = lp->pre_channel;
+		}
+		if (cfg->exclusive > 0) {
+			unsigned long flags;
+
+			/* If binding is exclusive, try to grab the channel */
+			spin_lock_irqsave(&dev->lock, flags);
+			if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+				lp->l2_proto, lp->l3_proto, drvidx,
+				chidx, lp->msn)) < 0) {
+				/* Grab failed, because desired channel is in use */
+				lp->exclusive = -1;
+				spin_unlock_irqrestore(&dev->lock, flags);
+				return -EBUSY;
+			}
+			/* All went ok, so update isdninfo */
+			dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
+			isdn_info_update();
+			spin_unlock_irqrestore(&dev->lock, flags);
+			lp->exclusive = i;
+		} else {
+			/* Non-exclusive binding or unbind. */
+			lp->exclusive = -1;
+			if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
+				isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
+				isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
+				drvidx = -1;
+				chidx = -1;
+			}
+		}
+		strcpy(lp->msn, cfg->eaz);
+		lp->pre_device = drvidx;
+		lp->pre_channel = chidx;
+		lp->onhtime = cfg->onhtime;
+		lp->charge = cfg->charge;
+		lp->l2_proto = cfg->l2_proto;
+		lp->l3_proto = cfg->l3_proto;
+		lp->cbdelay = cfg->cbdelay;
+		lp->dialmax = cfg->dialmax;
+		lp->triggercps = cfg->triggercps;
+		lp->slavedelay = cfg->slavedelay * HZ;
+		lp->pppbind = cfg->pppbind;
+		lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
+		lp->dialwait = cfg->dialwait * HZ;
+		if (cfg->secure)
+			lp->flags |= ISDN_NET_SECURE;
+		else
+			lp->flags &= ~ISDN_NET_SECURE;
+		if (cfg->cbhup)
+			lp->flags |= ISDN_NET_CBHUP;
+		else
+			lp->flags &= ~ISDN_NET_CBHUP;
+		switch (cfg->callback) {
+			case 0:
+				lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+				break;
+			case 1:
+				lp->flags |= ISDN_NET_CALLBACK;
+				lp->flags &= ~ISDN_NET_CBOUT;
+				break;
+			case 2:
+				lp->flags |= ISDN_NET_CBOUT;
+				lp->flags &= ~ISDN_NET_CALLBACK;
+				break;
+		}
+		lp->flags &= ~ISDN_NET_DIALMODE_MASK;	/* first all bits off */
+		if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
+			/* old isdnctrl version, where only 0 or 1 is given */
+			printk(KERN_WARNING
+			     "Old isdnctrl version detected! Please update.\n");
+			lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
+		}
+		else {
+			lp->flags |= cfg->dialmode;  /* turn on selected bits */
+		}
+		if (cfg->chargehup)
+			lp->hupflags |= ISDN_CHARGEHUP;
+		else
+			lp->hupflags &= ~ISDN_CHARGEHUP;
+		if (cfg->ihup)
+			lp->hupflags |= ISDN_INHUP;
+		else
+			lp->hupflags &= ~ISDN_INHUP;
+		if (cfg->chargeint > 10) {
+			lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+			lp->chargeint = cfg->chargeint * HZ;
+		}
+		if (cfg->p_encap != lp->p_encap) {
+			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
+				p->dev.hard_header = NULL;
+				p->dev.hard_header_cache = NULL;
+				p->dev.header_cache_update = NULL;
+				p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
+			} else {
+				p->dev.hard_header = isdn_net_header;
+				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
+					p->dev.hard_header_cache = lp->org_hhc;
+					p->dev.header_cache_update = lp->org_hcu;
+					p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
+				} else {
+					p->dev.hard_header_cache = NULL;
+					p->dev.header_cache_update = NULL;
+					p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
+				}
+			}
+		}
+		lp->p_encap = cfg->p_encap;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Perform get-interface-parameters.ioctl
+ */
+int
+isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
+{
+	isdn_net_dev *p = isdn_net_findif(cfg->name);
+
+	if (p) {
+		isdn_net_local *lp = p->local;
+
+		strcpy(cfg->eaz, lp->msn);
+		cfg->exclusive = lp->exclusive;
+		if (lp->pre_device >= 0) {
+			sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
+				lp->pre_channel);
+		} else
+			cfg->drvid[0] = '\0';
+		cfg->onhtime = lp->onhtime;
+		cfg->charge = lp->charge;
+		cfg->l2_proto = lp->l2_proto;
+		cfg->l3_proto = lp->l3_proto;
+		cfg->p_encap = lp->p_encap;
+		cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
+		cfg->callback = 0;
+		if (lp->flags & ISDN_NET_CALLBACK)
+			cfg->callback = 1;
+		if (lp->flags & ISDN_NET_CBOUT)
+			cfg->callback = 2;
+		cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+		cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
+		cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
+		cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
+		cfg->cbdelay = lp->cbdelay;
+		cfg->dialmax = lp->dialmax;
+		cfg->triggercps = lp->triggercps;
+		cfg->slavedelay = lp->slavedelay / HZ;
+		cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
+		    (lp->chargeint / HZ) : 0;
+		cfg->pppbind = lp->pppbind;
+		cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
+		cfg->dialwait = lp->dialwait / HZ;
+		if (lp->slave)
+			strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
+		else
+			cfg->slave[0] = '\0';
+		if (lp->master)
+			strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
+		else
+			cfg->master[0] = '\0';
+		return 0;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Add a phone-number to an interface.
+ */
+int
+isdn_net_addphone(isdn_net_ioctl_phone * phone)
+{
+	isdn_net_dev *p = isdn_net_findif(phone->name);
+	isdn_net_phone *n;
+
+	if (p) {
+		if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
+			return -ENOMEM;
+		strcpy(n->num, phone->phone);
+		n->next = p->local->phone[phone->outgoing & 1];
+		p->local->phone[phone->outgoing & 1] = n;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Copy a string of all phone-numbers of an interface to user space.
+ * This might sleep and must be called with the isdn semaphore down.
+ */
+int
+isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
+{
+	isdn_net_dev *p = isdn_net_findif(phone->name);
+	int inout = phone->outgoing & 1;
+	int more = 0;
+	int count = 0;
+	isdn_net_phone *n;
+
+	if (!p)
+		return -ENODEV;
+	inout &= 1;
+	for (n = p->local->phone[inout]; n; n = n->next) {
+		if (more) {
+			put_user(' ', phones++);
+			count++;
+		}
+		if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
+			return -EFAULT;
+		}
+		phones += strlen(n->num);
+		count += strlen(n->num);
+		more = 1;
+	}
+	put_user(0, phones);
+	count++;
+	return count;
+}
+
+/*
+ * Copy a string containing the peer's phone number of a connected interface
+ * to user space.
+ */
+int
+isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
+{
+	isdn_net_dev *p = isdn_net_findif(phone->name);
+	int ch, dv, idx;
+
+	if (!p) return -ENODEV;
+	/*
+	 * Theoretical race: while this executes, the remote number might
+	 * become invalid (hang up) or change (new connection), resulting
+         * in (partially) wrong number copied to user. This race
+	 * currently ignored.
+	 */
+	ch = p->local->isdn_channel;
+	dv = p->local->isdn_device;
+	if(ch<0 && dv<0) return -ENOTCONN;
+	idx = isdn_dc2minor(dv, ch);
+	if (idx<0) return -ENODEV;
+	/* for pre-bound channels, we need this extra check */
+	if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
+	strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
+	phone->outgoing=USG_OUTGOING(dev->usage[idx]);
+	if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
+	return 0;
+}
+/*
+ * Delete a phone-number from an interface.
+ */
+int
+isdn_net_delphone(isdn_net_ioctl_phone * phone)
+{
+	isdn_net_dev *p = isdn_net_findif(phone->name);
+	int inout = phone->outgoing & 1;
+	isdn_net_phone *n;
+	isdn_net_phone *m;
+
+	if (p) {
+		n = p->local->phone[inout];
+		m = NULL;
+		while (n) {
+			if (!strcmp(n->num, phone->phone)) {
+				if (p->local->dial == n)
+					p->local->dial = n->next;
+				if (m)
+					m->next = n->next;
+				else
+					p->local->phone[inout] = n->next;
+				kfree(n);
+				return 0;
+			}
+			m = n;
+			n = (isdn_net_phone *) n->next;
+		}
+		return -EINVAL;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Delete all phone-numbers of an interface.
+ */
 static int
-isdn_ether_open(isdn_net_local *lp)
+isdn_net_rmallphone(isdn_net_dev * p)
 {
-	struct net_device *dev = &lp->dev;
-	struct in_device *in_dev;
+	isdn_net_phone *n;
+	isdn_net_phone *m;
 	int i;
 
-	/* Fill in the MAC-level header ... */
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = 0xfc;
-	in_dev = dev->ip_ptr;
-	if (in_dev) {
-		/* any address will do - we take the first */
-		struct in_ifaddr *ifa = in_dev->ifa_list;
-		if (ifa)
-			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+	for (i = 0; i < 2; i++) {
+		n = p->local->phone[i];
+		while (n) {
+			m = n->next;
+			kfree(n);
+			n = m;
+		}
+		p->local->phone[i] = NULL;
 	}
+	p->local->dial = NULL;
 	return 0;
 }
 
+/*
+ * Force a hangup of a network-interface.
+ */
+int
+isdn_net_force_hangup(char *name)
+{
+	isdn_net_dev *p = isdn_net_findif(name);
+	struct net_device *q;
+
+	if (p) {
+		if (p->local->isdn_device < 0)
+			return 1;
+		q = p->local->slave;
+		/* If this interface has slaves, do a hangup for them also. */
+		while (q) {
+			isdn_net_hangup(q);
+			q = (((isdn_net_local *) q->priv)->slave);
+		}
+		isdn_net_hangup(&p->dev);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Helper-function for isdn_net_rm: Do the real work.
+ */
 static int
-isdn_ether_init(isdn_net_local *lp)
+isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
 {
-	struct net_device *dev = &lp->dev;
+	u_long flags;
 
-	ether_setup(dev);
-	dev->tx_queue_len = 10;
-	dev->hard_header_len += isdn_hard_header_len();
+	if (isdn_net_device_started(p)) {
+		return -EBUSY;
+	}
+#ifdef CONFIG_ISDN_X25
+	if( p -> cprot && p -> cprot -> pops )
+		p -> cprot -> pops -> proto_del ( p -> cprot );
+#endif
+	/* Free all phone-entries */
+	isdn_net_rmallphone(p);
+	/* If interface is bound exclusive, free channel-usage */
+	if (p->local->exclusive != -1)
+		isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
+	if (p->local->master) {
+		/* It's a slave-device, so update master's slave-pointer if necessary */
+		if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+			((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
+	} else {
+		/* Unregister only if it's a master-device */
+		p->dev.hard_header_cache = p->local->org_hhc;
+		p->dev.header_cache_update = p->local->org_hcu;
+		unregister_netdev(&p->dev);
+	}
+	/* Unlink device from chain */
+	spin_lock_irqsave(&dev->lock, flags);
+	if (q)
+		q->next = p->next;
+	else
+		dev->netdev = p->next;
+	if (p->local->slave) {
+		/* If this interface has a slave, remove it also */
+		char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
+		isdn_net_dev *n = dev->netdev;
+		q = NULL;
+		while (n) {
+			if (!strcmp(n->local->name, slavename)) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				isdn_net_realrm(n, q);
+				spin_lock_irqsave(&dev->lock, flags);
+				break;
+			}
+			q = n;
+			n = (isdn_net_dev *) n->next;
+		}
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+	/* If no more net-devices remain, disable auto-hangup timer */
+	if (dev->netdev == NULL)
+		isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
+	kfree(p->local);
+	kfree(p);
 
 	return 0;
 }
 
-struct isdn_netif_ops isdn_ether_ops = {
-	.hard_start_xmit     = isdn_net_start_xmit,
-	.receive             = isdn_ether_receive,
-	.init                = isdn_ether_init,
-	.open                = isdn_ether_open,
-};
+/*
+ * Remove a single network-interface.
+ */
+int
+isdn_net_rm(char *name)
+{
+	u_long flags;
+	isdn_net_dev *p;
+	isdn_net_dev *q;
+
+	/* Search name in netdev-chain */
+	spin_lock_irqsave(&dev->lock, flags);
+	p = dev->netdev;
+	q = NULL;
+	while (p) {
+		if (!strcmp(p->local->name, name)) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return (isdn_net_realrm(p, q));
+		}
+		q = p;
+		p = (isdn_net_dev *) p->next;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+	/* If no more net-devices remain, disable auto-hangup timer */
+	if (dev->netdev == NULL)
+		isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
+	return -ENODEV;
+}
+
+/*
+ * Remove all network-interfaces
+ */
+int
+isdn_net_rmall(void)
+{
+	u_long flags;
+	int ret;
+
+	/* Walk through netdev-chain */
+	spin_lock_irqsave(&dev->lock, flags);
+	while (dev->netdev) {
+		if (!dev->netdev->local->master) {
+			/* Remove master-devices only, slaves get removed with their master */
+			spin_unlock_irqrestore(&dev->lock, flags);
+			if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
+				return ret;
+			}
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+	dev->netdev = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
--- diff/drivers/isdn/i4l/isdn_net.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_net.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,15 +1,189 @@
-/* Linux ISDN subsystem, network related functions
+/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem, network related functions (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
+ * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
+ * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+			      /* Definitions for hupflags:                */
+#define ISDN_WAITCHARGE  1      /* did not get a charge info yet            */
+#define ISDN_HAVECHARGE  2      /* We know a charge info                    */
+#define ISDN_CHARGEHUP   4      /* We want to use the charge mechanism      */
+#define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
+#define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
+
+/*
+ * Definitions for Cisco-HDLC header.
+ */
+
+#define CISCO_ADDR_UNICAST    0x0f
+#define CISCO_ADDR_BROADCAST  0x8f
+#define CISCO_CTRL            0x00
+#define CISCO_TYPE_CDP        0x2000
+#define CISCO_TYPE_SLARP      0x8035
+#define CISCO_SLARP_REQUEST   0
+#define CISCO_SLARP_REPLY     1
+#define CISCO_SLARP_KEEPALIVE 2
+
+extern char *isdn_net_new(char *, struct net_device *);
+extern char *isdn_net_newslave(char *);
+extern int isdn_net_rm(char *);
+extern int isdn_net_rmall(void);
+extern int isdn_net_stat_callback(int, isdn_ctrl *);
+extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_addphone(isdn_net_ioctl_phone *);
+extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
+extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
+extern int isdn_net_delphone(isdn_net_ioctl_phone *);
+extern int isdn_net_find_icall(int, int, int, setup_parm *);
+extern void isdn_net_hangup(struct net_device *);
+extern void isdn_net_dial(void);
+extern void isdn_net_autohup(void);
+extern int isdn_net_force_hangup(char *);
+extern int isdn_net_force_dial(char *);
+extern isdn_net_dev *isdn_net_findif(char *);
+extern int isdn_net_rcv_skb(int, struct sk_buff *);
+extern int isdn_net_dial_req(isdn_net_local *);
+extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
+extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
+
+#define ISDN_NET_MAX_QUEUE_LENGTH 2
+
+/*
+ * is this particular channel busy?
+ */
+static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
+{
+	if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
+		return 0;
+	else 
+		return 1;
+}
+
+/*
+ * For the given net device, this will get a non-busy channel out of the
+ * corresponding bundle. The returned channel is locked.
+ */
+static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
+{
+	unsigned long flags;
+	isdn_net_local *lp;
+
+	spin_lock_irqsave(&nd->queue_lock, flags);
+	lp = nd->queue;         /* get lp on top of queue */
+	spin_lock_bh(&nd->queue->xmit_lock);
+	while (isdn_net_lp_busy(nd->queue)) {
+		spin_unlock_bh(&nd->queue->xmit_lock);
+		nd->queue = nd->queue->next;
+		if (nd->queue == lp) { /* not found -- should never happen */
+			lp = NULL;
+			goto errout;
+		}
+		spin_lock_bh(&nd->queue->xmit_lock);
+	}
+	lp = nd->queue;
+	nd->queue = nd->queue->next;
+errout:
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+	return lp;
+}
+
+/*
+ * add a channel to a bundle
  */
+static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
+{
+	isdn_net_local *lp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nd->queue_lock, flags);
+
+	lp = nd->queue;
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) nlp:%s(%p) last(%p)\n",
+//		lp->name, lp, nlp->name, nlp, lp->last); 
+	nlp->last = lp->last;
+	lp->last->next = nlp;
+	lp->last = nlp;
+	nlp->next = lp;
+	nd->queue = nlp;
+
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+}
+/*
+ * remove a channel from the bundle it belongs to
+ */
+static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
+{
+	isdn_net_local *master_lp = lp;
+	unsigned long flags;
+
+	if (lp->master)
+		master_lp = (isdn_net_local *) lp->master->priv;
+
+//	printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
+//		lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); 
+	spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
+	lp->last->next = lp->next;
+	lp->next->last = lp->last;
+	if (master_lp->netdev->queue == lp) {
+		master_lp->netdev->queue = lp->next;
+		if (lp->next == lp) { /* last in queue */
+			master_lp->netdev->queue = master_lp->netdev->local;
+		}
+	}
+	lp->next = lp->last = lp;	/* (re)set own pointers */
+//	printk(KERN_DEBUG __FUNCTION__": mndq(%p)\n",
+//		master_lp->netdev->queue); 
+	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+static inline int
+put_u8(unsigned char *p, u8 x)
+{
+	*p = x;
+	return 1;
+}
+
+static inline int
+put_u16(unsigned char *p, u16 x)
+{
+	*((u16 *)p) = htons(x);
+	return 2;
+}
+
+static inline int
+put_u32(unsigned char *p, u32 x)
+{
+	*((u32 *)p) = htonl(x);
+	return 4;
+}
+
+static inline int
+get_u8(unsigned char *p, u8 *x)
+{
+	*x = *p;
+	return 1;
+}
+
+static inline int
+get_u16(unsigned char *p, u16 *x)
+{
+	*x = ntohs(*((u16 *)p));
+	return 2;
+}
+
+static inline int
+get_u32(unsigned char *p, u32 *x)
+{
+	*x = ntohl(*((u32 *)p));
+	return 4;
+}
+
 
-extern struct isdn_netif_ops isdn_iptyp_ops;
-extern struct isdn_netif_ops isdn_uihdlc_ops;
-extern struct isdn_netif_ops isdn_rawip_ops;
-extern struct isdn_netif_ops isdn_ether_ops;
--- diff/drivers/isdn/i4l/isdn_ppp.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_ppp.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,803 +1,843 @@
-/* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
  *
- * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
+ * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+ *
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
-#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/isdn.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
-#include <linux/if_arp.h>
+#ifdef CONFIG_IPPP_FILTER
+#include <linux/filter.h>
+#endif
 
 #include "isdn_common.h"
-#include "isdn_net_lib.h"
 #include "isdn_ppp.h"
-#include "isdn_ppp_ccp.h"
-#include "isdn_ppp_vj.h"
-#include "isdn_ppp_mp.h"
+#include "isdn_net.h"
 
-/* ====================================================================== */
+#ifndef PPP_IPX
+#define PPP_IPX 0x002b
+#endif
 
-#define IPPP_MAX_RQ_LEN 8 /* max #frames queued for ipppd to read */
+/* Prototypes */
+static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
+static int isdn_ppp_closewait(int slot);
+static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
+				 struct sk_buff *skb, int proto);
+static int isdn_ppp_if_get_unit(char *namebuf);
+static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+				struct ippp_struct *,struct ippp_struct *,int *proto);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+				struct sk_buff *skb,int proto);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type);
+static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+	 struct sk_buff *skb);
 
-static int
-isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *);
+/* New CCP stuff */
+static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
+static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
+				    unsigned char code, unsigned char id,
+				    unsigned char *data, int len);
+static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
+static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
+					  unsigned char id);
+static void isdn_ppp_ccp_timer_callback(unsigned long closure);
+static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
+						      unsigned char id);
+static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
+				     struct isdn_ppp_resetparams *rp);
+static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
+					unsigned char id);
 
-/* ====================================================================== */
-/* IPPPD handling                                                         */
-/* ====================================================================== */
-
-/* We use reference counting for struct ipppd. It is alloced on
- * open() on /dev/ipppX and saved into file->private, making for one
- * reference. release() will release this reference, after all other
- * references are gone, the destructor frees it.
- *
- * Another reference is taken by isdn_ppp_bind() and freed by
- * isdn_ppp_unbind(). The callbacks from isdn_net_lib.c happen only
- * between isdn_ppp_bind() and isdn_ppp_unbind(), i.e. access to 
- * idev->ipppd is safe without further locking.
- */
 
-#undef IPPPD_DEBUG
-
-#ifdef IPPPD_DEBUG
-#define ipppd_debug(i, fmt, arg...) \
-        printk(KERN_DEBUG "ipppd %p minor %d state %#x %s: " fmt "\n", (i), \
-               (i)->minor, (i)->state, __FUNCTION__ , ## arg)
-#else
-#define ipppd_debug(...) do { } while (0)
-#endif
 
-/* ipppd::flags */
-enum {
-	IPPPD_FL_HUP    = 0x01,
-	IPPPD_FL_WAKEUP = 0x02,
-};
-
-/* ipppd::state */
-enum {
-	IPPPD_ST_OPEN,
-	IPPPD_ST_ASSIGNED,
-	IPPPD_ST_CONNECTED,
-};
-
-struct ipppd {
-	struct list_head ipppds;
-	int state;
-	int flags;
-	struct sk_buff_head rq;
-	wait_queue_head_t wq;
-	struct isdn_net_dev_s *idev;
-	int unit;
-	int minor;
-	unsigned long debug;
-	atomic_t refcnt;
-};
+#ifdef CONFIG_ISDN_MPP
+static ippp_bundle * isdn_ppp_bundle_arr = NULL;
+ 
+static int isdn_ppp_mp_bundle_array_init(void);
+static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );
+static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 
+							struct sk_buff *skb);
+static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
+
+static int isdn_ppp_bundle(struct ippp_struct *, int unit);
+#endif	/* CONFIG_ISDN_MPP */
+  
+char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
 
-/* ====================================================================== */
+static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
-static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED;
-static LIST_HEAD(ipppds);
+static struct isdn_ppp_compressor *ipc_head = NULL;
 
+/*
+ * frame log (debug)
+ */
 static void
-ipppd_destroy(struct ipppd *ipppd)
+isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
 {
-	HERE;
+	int cnt,
+	 j,
+	 i;
+	char buf[80];
 
-	skb_queue_purge(&ipppd->rq);
-	kfree(ipppd);
-}
+	if (len < maxlen)
+		maxlen = len;
 
-static inline struct ipppd *
-ipppd_get(struct ipppd *ipppd)
-{
-	atomic_inc(&ipppd->refcnt);
-	printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt));
-	return ipppd;
+	for (i = 0, cnt = 0; cnt < maxlen; i++) {
+		for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
+			sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
+		printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
+	}
 }
 
-static inline void 
-ipppd_put(struct ipppd *ipppd)
+/*
+ * unbind isdn_net_local <=> ippp-device
+ * note: it can happen, that we hangup/free the master before the slaves
+ *       in this case we bind another lp to the master device
+ */
+int
+isdn_ppp_free(isdn_net_local * lp)
 {
-	printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt));
-
-	if (atomic_dec_and_test(&ipppd->refcnt))
-		ipppd_destroy(ipppd);
-}
-
-/* ====================================================================== */
-/* char dev ops                                                           */
-
-/* --- open ------------------------------------------------------------- */
+	struct ippp_struct *is;
 
-static int
-ipppd_open(struct inode *ino, struct file *file)
-{
-	unsigned long flags;
-	unsigned int minor = iminor(ino) - ISDN_MINOR_PPP;
-	struct ipppd *ipppd;
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+			__FUNCTION__, lp->ppp_slot);
+		return 0;
+	}
 
-	ipppd = kmalloc(sizeof(*ipppd), GFP_KERNEL);
-	if (!ipppd)
-		return -ENOMEM;
+#ifdef CONFIG_ISDN_MPP
+	spin_lock(&lp->netdev->pb->lock);
+#endif
+	isdn_net_rm_from_bundle(lp);
+#ifdef CONFIG_ISDN_MPP
+	if (lp->netdev->pb->ref_ct == 1)	/* last link in queue? */
+		isdn_ppp_mp_cleanup(lp);
+
+	lp->netdev->pb->ref_ct--;
+	spin_unlock(&lp->netdev->pb->lock);
+#endif /* CONFIG_ISDN_MPP */
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
+			__FUNCTION__, lp->ppp_slot);
+		return 0;
+	}
+	is = ippp_table[lp->ppp_slot];
+	if ((is->state & IPPP_CONNECT))
+		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
+	else if (is->state & IPPP_ASSIGNED)
+		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGNED' state */
 
-	memset(ipppd, 0, sizeof(*ipppd));
-	atomic_set(&ipppd->refcnt, 0);
-	
-	/* file->private_data holds a reference */
-	file->private_data = ipppd_get(ipppd);
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
 
-	ipppd->unit = -1;          /* set by isdn_ppp_bind */
-	ipppd->minor = minor;
-	ipppd->state = IPPPD_ST_OPEN;
-	init_waitqueue_head(&ipppd->wq);
-	skb_queue_head_init(&ipppd->rq);
-
-	spin_lock_irqsave(&ipppds_lock, flags);
-	list_add(&ipppd->ipppds, &ipppds);
-	spin_unlock_irqrestore(&ipppds_lock, flags);
-	
-	ipppd_debug(ipppd, "minor %d", minor);
+	is->lp = NULL;          /* link is down .. set lp to NULL */
+	lp->ppp_slot = -1;      /* is this OK ?? */
 
 	return 0;
 }
 
-/* --- release  --------------------------------------------------------- */
-
-static int
-ipppd_release(struct inode *ino, struct file *file)
+/*
+ * bind isdn_net_local <=> ippp-device
+ *
+ * This function is allways called with holding dev->lock so
+ * no additional lock is needed
+ */
+int
+isdn_ppp_bind(isdn_net_local * lp)
 {
-	unsigned long flags;
-	struct ipppd *ipppd = file->private_data;
-
-	ipppd_debug(ipppd, "");
+	int i;
+	int unit = 0;
+	struct ippp_struct *is;
+	int retval;
 
-	if (ipppd->state == IPPPD_ST_CONNECTED)
-		isdn_net_hangup(ipppd->idev);
+	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */
+		isdn_net_dev *net_dev = dev->netdev;
+		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
+		memset(exclusive, 0, ISDN_MAX_CHANNELS);
+		while (net_dev) {	/* step through net devices to find exclusive minors */
+			isdn_net_local *lp = net_dev->local;
+			if (lp->pppbind >= 0)
+				exclusive[lp->pppbind] = 1;
+			net_dev = net_dev->next;
+		}
+		/*
+		 * search a free device / slot
+		 */
+		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) {	/* OPEN, but not connected! */
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+			if (ippp_table[i]->minor == lp->pppbind &&
+			    (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
+				break;
+		}
+	}
 
-	spin_lock_irqsave(&ipppds_lock, flags);
-	list_del(&ipppd->ipppds);
-	spin_unlock_irqrestore(&ipppds_lock, flags);
+	if (i >= ISDN_MAX_CHANNELS) {
+		printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
+		retval = -1;
+		goto out;
+	}
+	unit = isdn_ppp_if_get_unit(lp->name);	/* get unit number from interface name .. ugly! */
+	if (unit < 0) {
+		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
+		retval = -1;
+		goto out;
+	}
+	
+	lp->ppp_slot = i;
+	is = ippp_table[i];
+	is->lp = lp;
+	is->unit = unit;
+	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */
+#ifdef CONFIG_ISDN_MPP
+	retval = isdn_ppp_mp_init(lp, NULL);
+	if (retval < 0)
+		goto out;
+#endif /* CONFIG_ISDN_MPP */
 
-	ipppd_put(ipppd);
+	retval = lp->ppp_slot;
 
-	return 0;
+ out:
+	return retval;
 }
 
-/* --- read ------------------------------------------------------------- */
+/*
+ * kick the ipppd on the device
+ * (wakes up daemon after B-channel connect)
+ */
 
-/* read() is always non blocking */
-static ssize_t
-ipppd_read(struct file *file, char *buf, size_t count, loff_t *off)
+void
+isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 {
-	struct ipppd *is;
-	struct sk_buff *skb;
-	int retval;
+	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+			__FUNCTION__, lp->ppp_slot);
+		return;
+	}
+	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
+	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+}
 
-	if (off != &file->f_pos)
-		return -ESPIPE;
-	
-	is = file->private_data;
+/*
+ * there was a hangup on the netdevice
+ * force wakeup of the ippp device
+ * go into 'device waits for release' state
+ */
+static int
+isdn_ppp_closewait(int slot)
+{
+	struct ippp_struct *is;
 
-	skb = skb_dequeue(&is->rq);
-	if (!skb) {
-		retval = -EAGAIN;
-		goto out;
-	}
-	if (skb->len > count) {
-		retval = -EMSGSIZE;
-		goto out_free;
-	}
-	if (copy_to_user(buf, skb->data, skb->len)) {
-		retval = -EFAULT;
-		goto out_free;
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: slot(%d) out of range\n",
+			__FUNCTION__, slot);
+		return 0;
 	}
-	retval = skb->len;
-
- out_free:
-	dev_kfree_skb(skb);
- out:
-	return retval;
+	is = ippp_table[slot];
+	if (is->state)
+		wake_up_interruptible(&is->wq);
+	is->state = IPPP_CLOSEWAIT;
+	return 1;
 }
 
-/* --- write ------------------------------------------------------------ */
+/*
+ * isdn_ppp_find_slot / isdn_ppp_free_slot
+ */
 
-/* write() is always non blocking */
-static ssize_t
-ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
-{
-	isdn_net_dev *idev;
-	struct inl_ppp *inl_ppp;
-	struct ind_ppp *ind_ppp;
-	struct ipppd *ipppd;
-	struct sk_buff *skb;
-	char *p;
-	int retval;
-	u16 proto;
+static int
+isdn_ppp_get_slot(void)
+{
+	int i;
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		if (!ippp_table[i]->state)
+			return i;
+	}
+	return -1;
+}
 
-	if (off != &file->f_pos)
-		return -ESPIPE;
+/*
+ * isdn_ppp_open
+ */
 
-	ipppd = file->private_data;
-	ipppd_debug(ipppd, "count = %d", count);
+int
+isdn_ppp_open(int min, struct file *file)
+{
+	int slot;
+	struct ippp_struct *is;
 
-	if (ipppd->state != IPPPD_ST_CONNECTED) {
-		retval = -ENOTCONN;
-		goto out;
-	}
+	if (min < 0 || min > ISDN_MAX_CHANNELS)
+		return -ENODEV;
 
-	idev = ipppd->idev;
-	if (!idev) {
-		isdn_BUG();
-		retval = -ENODEV;
-		goto out;
-	}
-	ind_ppp = idev->ind_priv;
-	inl_ppp = idev->mlp->inl_priv;
-	/* Daemon needs to send at least full header, AC + proto */
-	if (count < 4) {
-		retval = -EMSGSIZE;
-		goto out;
-	}
-	skb = isdn_ppp_dev_alloc_skb(idev, count, GFP_KERNEL);
-	if (!skb) {
-		retval = -ENOMEM;
-		goto out;
+	slot = isdn_ppp_get_slot();
+	if (slot < 0) {
+		return -EBUSY;
 	}
-	p = skb_put(skb, count);
-	if (copy_from_user(p, buf, count)) {
-		kfree_skb(skb);
-		retval = -EFAULT;
-		goto out;
-	}
-	/* Don't reset huptimer for LCP packets. (Echo requests). */
-	proto = PPP_PROTOCOL(p);
-	if (proto != PPP_LCP)
-		idev->huptimer = 0;
+	is = file->private_data = ippp_table[slot];
 	
-	/* Keeps CCP/compression states in sync */
-	switch (proto) {
-	case PPP_CCP:
-		ippp_ccp_send_ccp(inl_ppp->ccp, skb);
-		break;
-	case PPP_CCPFRAG:
-		ippp_ccp_send_ccp(ind_ppp->ccp, skb);
-		break;
-	}
-	/* FIXME: Somewhere we need protection against the
-	 * queue growing too large */
-	isdn_net_write_super(idev, skb);
+	printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
+	       slot, min, is->state);
 
-	retval = count;
-	
- out:
-	return retval;
-}
+	/* compression stuff */
+	is->link_compressor   = is->compressor = NULL;
+	is->link_decompressor = is->decompressor = NULL;
+	is->link_comp_stat    = is->comp_stat = NULL;
+	is->link_decomp_stat  = is->decomp_stat = NULL;
+	is->compflags = 0;
+
+	is->reset = isdn_ppp_ccp_reset_alloc(is);
+
+	is->lp = NULL;
+	is->mp_seqno = 0;       /* MP sequence number */
+	is->pppcfg = 0;         /* ppp configuration */
+	is->mpppcfg = 0;        /* mppp configuration */
+	is->last_link_seqno = -1;	/* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
+	is->unit = -1;          /* set, when we have our interface */
+	is->mru = 1524;         /* MRU, default 1524 */
+	is->maxcid = 16;        /* VJ: maxcid */
+	is->tk = current;
+	init_waitqueue_head(&is->wq);
+	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
+	is->last = is->rq;
+	is->minor = min;
+#ifdef CONFIG_ISDN_PPP_VJ
+	/*
+	 * VJ header compression init
+	 */
+	is->slcomp = slhc_init(16, 16);	/* not necessary for 2. link in bundle */
+#endif
+#ifdef CONFIG_IPPP_FILTER
+	is->pass_filter.filter = NULL;
+	is->active_filter.filter = NULL;
+#endif
+	is->state = IPPP_OPEN;
 
-/* --- poll ------------------------------------------------------------- */
+	return 0;
+}
 
-static unsigned int
-ipppd_poll(struct file *file, poll_table * wait)
+/*
+ * release ippp device
+ */
+void
+isdn_ppp_release(int min, struct file *file)
 {
-	unsigned int mask;
-	struct ipppd *is;
+	int i;
+	struct ippp_struct *is;
 
+	if (min < 0 || min >= ISDN_MAX_CHANNELS)
+		return;
 	is = file->private_data;
 
-	ipppd_debug(is, "");
+	if (!is) {
+		printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__);
+		return;
+	}
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
 
-	/* just registers wait_queue hook. This doesn't really wait. */
-	poll_wait(file, &is->wq, wait);
+	if (is->lp) {           /* a lp address says: this link is still up */
+		isdn_net_dev *p = is->lp->netdev;
 
-	if (is->flags & IPPPD_FL_HUP) {
-		mask = POLLHUP;
-		goto out;
+		if (!p) {
+			printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__);
+			return;
+		}
+		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
+		/*
+		 * isdn_net_hangup() calls isdn_ppp_free()
+		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
+		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
+		 */
+		isdn_net_hangup(&p->dev);
 	}
-	/* we're always ready to send .. */
-	mask = POLLOUT | POLLWRNORM;
+	for (i = 0; i < NUM_RCV_BUFFS; i++) {
+		if (is->rq[i].buf) {
+			kfree(is->rq[i].buf);
+			is->rq[i].buf = NULL;
+		}
+	}
+	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
+	is->last = is->rq;
 
-	/*
-	 * if IPPP_FL_WAKEUP is set we return even if we have nothing to read
-	 */
-	if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) {
-		is->flags &= ~IPPPD_FL_WAKEUP;
-		mask |= POLLIN | POLLRDNORM;
+#ifdef CONFIG_ISDN_PPP_VJ
+/* TODO: if this was the previous master: link the slcomp to the new master */
+	slhc_free(is->slcomp);
+	is->slcomp = NULL;
+#endif
+#ifdef CONFIG_IPPP_FILTER
+	if (is->pass_filter.filter) {
+		kfree(is->pass_filter.filter);
+		is->pass_filter.filter = NULL;
+	}
+	if (is->active_filter.filter) {
+		kfree(is->active_filter.filter);
+		is->active_filter.filter = NULL;
 	}
+#endif
 
- out:
-	return mask;
-}
+/* TODO: if this was the previous master: link the stuff to the new master */
+	if(is->comp_stat)
+		is->compressor->free(is->comp_stat);
+	if(is->link_comp_stat)
+		is->link_compressor->free(is->link_comp_stat);
+	if(is->link_decomp_stat)
+		is->link_decompressor->free(is->link_decomp_stat);
+	if(is->decomp_stat)
+		is->decompressor->free(is->decomp_stat);
+        is->compressor   = is->link_compressor   = NULL;
+        is->decompressor = is->link_decompressor = NULL;
+	is->comp_stat    = is->link_comp_stat    = NULL;
+        is->decomp_stat  = is->link_decomp_stat  = NULL;
+
+	/* Clean up if necessary */
+	if(is->reset)
+		isdn_ppp_ccp_reset_free(is);
 
-/* --- ioctl ------------------------------------------------------------ */
+	/* this slot is ready for new connections */
+	is->state = 0;
+}
 
-/* get_arg .. ioctl helper */
+/*
+ * get_arg .. ioctl helper
+ */
 static int
-get_arg(unsigned long arg, void *val, int len)
+get_arg(void *b, void *val, int len)
 {
-	if (copy_from_user((void *) val, (void *) arg, len))
+	if (len <= 0)
+		len = sizeof(void *);
+	if (copy_from_user((void *) val, b, len))
 		return -EFAULT;
 	return 0;
 }
 
-/* set arg .. ioctl helper */
+/*
+ * set arg .. ioctl helper
+ */
 static int
-set_arg(unsigned long arg, void *val,int len)
+set_arg(void *b, void *val,int len)
 {
-	if (copy_to_user((void *) arg, (void *) val, len))
+	if(len <= 0)
+		len = sizeof(void *);
+	if (copy_to_user(b, (void *) val, len))
 		return -EFAULT;
 	return 0;
 }
 
-static int
-ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
-	    unsigned long arg)
+/*
+ * ippp device ioctl
+ */
+int
+isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	isdn_net_dev *idev;
-	struct ind_ppp *ind_ppp = NULL;
-	struct inl_ppp *inl_ppp = NULL;
 	unsigned long val;
-	int r;
-	struct ipppd *is;
+	int r,i,j;
+	struct ippp_struct *is;
+	isdn_net_local *lp;
 	struct isdn_ppp_comp_data data;
-	unsigned int cfg;
 
-	is = file->private_data;
-
-	ipppd_debug(is, "cmd %#x", cmd);
-
-	// FIXME that needs locking?
-	idev = is->idev;
-	if (idev) {
-		ind_ppp = idev->ind_priv;
-		inl_ppp = idev->mlp->inl_priv;
-	}
-	switch (cmd) {
-	case PPPIOCGUNIT:	/* get ppp/isdn unit number */
-		r = set_arg(arg, &is->unit, sizeof(is->unit));
-		break;
-	case PPPIOCGDEBUG:
-		r = set_arg(arg, &is->debug, sizeof(is->debug));
-		break;
-	case PPPIOCSDEBUG:
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
-			break;
-		is->debug = val;
-		if (idev) {
-			ind_ppp->debug = val;
-			inl_ppp->debug = val;
-		}
-		break;
-	case PPPIOCGCOMPRESSORS:
-	{
-		unsigned long protos[8];
-		ippp_ccp_get_compressors(protos);
-		r = set_arg(arg, protos, sizeof(protos));
-		break;
-	}
-	default:
-		r = -ENOTTY;
-		break;
-	}
+	is = (struct ippp_struct *) file->private_data;
+	lp = is->lp;
 
-	if (r != -ENOTTY)
-		goto out;
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
 
-	if (!idev) {
-		r = -ENODEV;
-		goto out;
-	}
+	if (!(is->state & IPPP_OPEN))
+		return -EINVAL;
 
 	switch (cmd) {
-	case PPPIOCBUNDLE:
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
+		case PPPIOCBUNDLE:
+#ifdef CONFIG_ISDN_MPP
+			if (!(is->state & IPPP_CONNECT))
+				return -EINVAL;
+			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
+				return r;
+			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
+			       (int) min, (int) is->unit, (int) val);
+			return isdn_ppp_bundle(is, val);
+#else
+			return -1;
+#endif
 			break;
-
-		r = ippp_mp_bundle(idev, val);
-		break;
-	case PPPIOCGIFNAME:
-		r = set_arg(arg, idev->name, strlen(idev->name)+1);
-		break;
-	case PPPIOCGMPFLAGS:	/* get configuration flags */
-		r = set_arg(arg, &inl_ppp->mp_cfg, sizeof(inl_ppp->mp_cfg));
-		break;
-	case PPPIOCSMPFLAGS:	/* set configuration flags */
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
+		case PPPIOCGUNIT:	/* get ppp/isdn unit number */
+			if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) )))
+				return r;
 			break;
-		inl_ppp->mp_cfg = val;
-		break;
-	case PPPIOCGFLAGS:	/* get configuration flags */
-		cfg = ind_ppp->pppcfg | ippp_ccp_get_flags(ind_ppp->ccp);
-		r = set_arg(arg, &cfg, sizeof(cfg));
-		break;
-	case PPPIOCSFLAGS:	/* set configuration flags */
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
+		case PPPIOCGIFNAME:
+			if(!lp)
+				return -EINVAL;
+			if ((r = set_arg((void *) arg, lp->name, strlen(lp->name))))
+				return r;
 			break;
-		if ((val & SC_ENABLE_IP) && !(ind_ppp->pppcfg & SC_ENABLE_IP)) {
-			ind_ppp->pppcfg = val;
-			/* OK .. we are ready to send buffers */
-			isdn_net_online(idev);
+		case PPPIOCGMPFLAGS:	/* get configuration flags */
+			if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) )))
+				return r;
 			break;
-		}
-		ind_ppp->pppcfg = val;
-		break;
-	case PPPIOCGIDLE:	/* get idle time information */
-	{
-		struct ppp_idle pidle;
-		pidle.xmit_idle = pidle.recv_idle = idev->huptimer;
-		r = set_arg(arg, &pidle,sizeof(pidle));
-		break;
-	}
-	case PPPIOCSMRU:	/* set receive unit size for PPP */
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
+		case PPPIOCSMPFLAGS:	/* set configuration flags */
+			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
+				return r;
+			is->mpppcfg = val;
 			break;
-		r = ippp_ccp_set_mru(ind_ppp->ccp, val);
-		break;
-	case PPPIOCSMPMRU:
-		break;
-	case PPPIOCSMPMTU:
-		break;
-	case PPPIOCSMAXCID:	/* set the maximum compression slot id */
-		r = get_arg(arg, &val, sizeof(val));
-		if (r)
+		case PPPIOCGFLAGS:	/* get configuration flags */
+			if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) )))
+				return r;
 			break;
-		r = ippp_vj_set_maxcid(idev, val);
-		break;
-	case PPPIOCSCOMPRESSOR:
-		r = get_arg(arg, &data, sizeof(data));
-		if (r)
+		case PPPIOCSFLAGS:	/* set configuration flags */
+			if ((r = get_arg((void *) arg, &val, sizeof(val) ))) {
+				return r;
+			}
+			if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
+				if (lp) {
+					/* OK .. we are ready to send buffers */
+					is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
+					netif_wake_queue(&lp->netdev->dev);
+					break;
+				}
+			}
+			is->pppcfg = val;
 			break;
-		r = isdn_ppp_set_compressor(idev, &data);
-		break;
-	case PPPIOCGCALLINFO:
-	{
-		isdn_net_local *mlp;
-		struct isdn_net_phone *phone;
-		struct pppcallinfo pci;
-		int i;
-		memset(&pci, 0, sizeof(pci));
-
-		mlp = idev->mlp;
-		strlcpy(pci.local_num, mlp->msn, sizeof(pci.local_num));
-		i = 0;
-		list_for_each_entry(phone, &mlp->phone[1], list) {
-			if (i++ == idev->dial) {
-				strlcpy(pci.remote_num,phone->num,sizeof(pci.remote_num));
-				break;
+		case PPPIOCGIDLE:	/* get idle time information */
+			if (lp) {
+				struct ppp_idle pidle;
+				pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
+				if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle))))
+					 return r;
 			}
-		}
-		pci.charge_units = idev->charge;
-		if (idev->outgoing)
-			pci.calltype = CALLTYPE_OUTGOING;
-		else
-			pci.calltype = CALLTYPE_INCOMING;
-		if (mlp->flags & ISDN_NET_CALLBACK)
-			pci.calltype |= CALLTYPE_CALLBACK;
-		r = set_arg(arg, &pci, sizeof(pci));
-		break;
-	}
-	default:
-		r = -ENOTTY;
-		break;
-	}
- out:
-	return r;
-}
-
-/* --- fops ------------------------------------------------------------- */
-
-struct file_operations isdn_ppp_fops =
-{
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= ipppd_read,
-	.write		= ipppd_write,
-	.poll		= ipppd_poll,
-	.ioctl		= ipppd_ioctl,
-	.open		= ipppd_open,
-	.release	= ipppd_release,
-};
-
-/* --- ipppd_queue_read ------------------------------------------------- */
-
-/* Queue packets for ipppd to read(). */
-
-static int
-ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
-{
-	struct sk_buff *skb;
-	unsigned char *p;
-	int retval;
-
-	if (is->state != IPPPD_ST_CONNECTED) {
-		printk(KERN_DEBUG "ippp: device not connected.\n");
-		retval = -ENOTCONN;
-		goto out;
-	}
-	if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) {
-		printk(KERN_WARNING "ippp: Queue is full\n");
-		retval = -EBUSY;
-		goto out;
-	}
-	skb = dev_alloc_skb(len + 4);
-	if (!skb) {
-		printk(KERN_WARNING "ippp: Can't alloc buf\n");
-		retval = -ENOMEM;
-		goto out;
-	}
-	p = skb_put(skb, 4);
-	p += put_u8(p, PPP_ALLSTATIONS);
-	p += put_u8(p, PPP_UI);
-	p += put_u16(p, proto);
-	memcpy(skb_put(skb, len), buf, len);
-
-	skb_queue_tail(&is->rq, skb);
-	wake_up(&is->wq);
-
-	retval = len;
- out:
-	return retval;
-}
-
-/* ====================================================================== */
-/* interface to isdn_net_lib                                            */
-/* ====================================================================== */
-
-
-/* Prototypes */
-static int
-isdn_ppp_if_get_unit(char *namebuf);
-
-static void
-isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto);
-
-static struct sk_buff *
-isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask);
-
-/* New CCP stuff */
-static void
-isdn_ppp_dev_kick_up(void *priv);
-
-/*
- * frame log (debug)
- */
-void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
-{
-	int cnt,
-	 j,
-	 i;
-	char buf[80];
-
-	if (len < maxlen)
-		maxlen = len;
-
-	for (i = 0, cnt = 0; cnt < maxlen; i++) {
-		for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
-			sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
-		printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
+			break;
+		case PPPIOCSMRU:	/* set receive unit size for PPP */
+			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
+				return r;
+			is->mru = val;
+			break;
+		case PPPIOCSMPMRU:
+			break;
+		case PPPIOCSMPMTU:
+			break;
+		case PPPIOCSMAXCID:	/* set the maximum compression slot id */
+			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
+				return r;
+			val++;
+			if (is->maxcid != val) {
+#ifdef CONFIG_ISDN_PPP_VJ
+				struct slcompress *sltmp;
+#endif
+				if (is->debug & 0x1)
+					printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
+				is->maxcid = val;
+#ifdef CONFIG_ISDN_PPP_VJ
+				sltmp = slhc_init(16, val);
+				if (!sltmp) {
+					printk(KERN_ERR "ippp, can't realloc slhc struct\n");
+					return -ENOMEM;
+				}
+				if (is->slcomp)
+					slhc_free(is->slcomp);
+				is->slcomp = sltmp;
+#endif
+			}
+			break;
+		case PPPIOCGDEBUG:
+			if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) )))
+				return r;
+			break;
+		case PPPIOCSDEBUG:
+			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
+				return r;
+			is->debug = val;
+			break;
+		case PPPIOCGCOMPRESSORS:
+			{
+				unsigned long protos[8] = {0,};
+				struct isdn_ppp_compressor *ipc = ipc_head;
+				while(ipc) {
+					j = ipc->num / (sizeof(long)*8);
+					i = ipc->num % (sizeof(long)*8);
+					if(j < 8)
+						protos[j] |= (0x1<<i);
+					ipc = ipc->next;
+				}
+				if ((r = set_arg((void *) arg,protos,8*sizeof(long) )))
+					return r;
+			}
+			break;
+		case PPPIOCSCOMPRESSOR:
+			if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data))))
+				return r;
+			return isdn_ppp_set_compressor(is, &data);
+		case PPPIOCGCALLINFO:
+			{
+				struct pppcallinfo pci;
+				memset((char *) &pci,0,sizeof(struct pppcallinfo));
+				if(lp)
+				{
+					strncpy(pci.local_num,lp->msn,63);
+					if(lp->dial) {
+						strncpy(pci.remote_num,lp->dial->num,63);
+					}
+					pci.charge_units = lp->charge;
+					if(lp->outgoing)
+						pci.calltype = CALLTYPE_OUTGOING;
+					else
+						pci.calltype = CALLTYPE_INCOMING;
+					if(lp->flags & ISDN_NET_CALLBACK)
+						pci.calltype |= CALLTYPE_CALLBACK;
+				}
+				return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
+			}
+#ifdef CONFIG_IPPP_FILTER
+		case PPPIOCSPASS:
+		case PPPIOCSACTIVE:
+			{
+				struct sock_fprog uprog, *filtp;
+				struct sock_filter *code = NULL;
+				int len, err;
+
+				if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
+					return -EFAULT;
+				if (uprog.len > 0 && uprog.len < 65536) {
+					len = uprog.len * sizeof(struct sock_filter);
+					code = kmalloc(len, GFP_KERNEL);
+					if (code == NULL)
+						return -ENOMEM;
+					if (copy_from_user(code, uprog.filter, len)) {
+						kfree(code);
+						return -EFAULT;
+					}
+					err = sk_chk_filter(code, uprog.len);
+					if (err) {
+						kfree(code);
+						return err;
+					}
+				}
+				filtp = (cmd == PPPIOCSPASS) ? &is->pass_filter : &is->active_filter;
+				if (filtp->filter)
+					kfree(filtp->filter);
+				filtp->filter = code;
+				filtp->len = uprog.len;
+				break;
+			}
+#endif /* CONFIG_IPPP_FILTER */
+		default:
+			break;
 	}
+	return 0;
 }
 
-void
-ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto)
+unsigned int
+isdn_ppp_poll(struct file *file, poll_table * wait)
 {
-	if (skb_headroom(skb) < 2) {
-		isdn_BUG();
-		return;
-	}
-	if ((ind_ppp->pppcfg & SC_COMP_PROT) && proto <= 0xff)
-		put_u8(skb_push(skb, 1), proto);
-	else
-		put_u16(skb_push(skb, 2), proto);
+	u_int mask;
+	struct ippp_buf_queue *bf, *bl;
+	u_long flags;
+	struct ippp_struct *is;
 
-}
+	is = file->private_data;
 
-static void
-ippp_push_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb)
-{
-	unsigned char *p;
+	if (is->debug & 0x2)
+		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
+				MINOR(file->f_dentry->d_inode->i_rdev));
 
-	if (skb_headroom(skb) < 2) {
-		isdn_BUG();
-		return;
+	/* just registers wait_queue hook. This doesn't really wait. */
+	poll_wait(file, &is->wq, wait);
+
+	if (!(is->state & IPPP_OPEN)) {
+		if(is->state == IPPP_CLOSEWAIT)
+			return POLLHUP;
+		printk(KERN_DEBUG "isdn_ppp: device not open\n");
+		return POLLERR;
 	}
-	if (ind_ppp->pppcfg & SC_COMP_AC)
-		return;
+	/* we're always ready to send .. */
+	mask = POLLOUT | POLLWRNORM;
 
-	p = skb_push(skb, 2);	
-	p += put_u8(p, PPP_ALLSTATIONS);
-	p += put_u8(p, PPP_UI);
+	spin_lock_irqsave(&is->buflock, flags);
+	bl = is->last;
+	bf = is->first;
+	/*
+	 * if IPPP_NOBLOCK is set we return even if we have nothing to read
+	 */
+	if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
+		is->state &= ~IPPP_NOBLOCK;
+		mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irqrestore(&is->buflock, flags);
+	return mask;
 }
 
 /*
- * unbind isdn_net_local <=> ippp-device
- * note: it can happen, that we hangup/free the master before the slaves
- *       in this case we bind another lp to the master device
+ *  fill up isdn_ppp_read() queue ..
  */
-static void
-isdn_ppp_unbind(isdn_net_dev *idev)
-{
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct ipppd *is = ind_ppp->ipppd;
-	
-	if (!is) {
-		isdn_BUG();
-		return;
-	}
-	ipppd_debug(is, "");
-
-	if (is->state != IPPPD_ST_ASSIGNED)
-		isdn_BUG();
 
-	is->state = IPPPD_ST_OPEN;
-
-	/* is->idev will be invalid shortly */
-	ippp_ccp_free(ind_ppp->ccp);
-
-	is->idev = NULL;
-	/* lose the reference we took on isdn_ppp_bind */
-	ipppd_put(is); 
-	ind_ppp->ipppd = NULL;
+static int
+isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
+{
+	struct ippp_buf_queue *bf, *bl;
+	u_long flags;
+	u_char *nbuf;
+	struct ippp_struct *is;
 
-	kfree(ind_ppp);
-	idev->ind_priv = NULL;
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
+		return 0;
+	}
+	is = ippp_table[slot];
 
-	return;
+	if (!(is->state & IPPP_CONNECT)) {
+		printk(KERN_DEBUG "ippp: device not activated.\n");
+		return 0;
+	}
+	nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
+	if (!nbuf) {
+		printk(KERN_WARNING "ippp: Can't alloc buf\n");
+		return 0;
+	}
+	nbuf[0] = PPP_ALLSTATIONS;
+	nbuf[1] = PPP_UI;
+	nbuf[2] = proto >> 8;
+	nbuf[3] = proto & 0xff;
+	memcpy(nbuf + 4, buf, len);
+
+	spin_lock_irqsave(&is->buflock, flags);
+	bf = is->first;
+	bl = is->last;
+
+	if (bf == bl) {
+		printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
+		bf = bf->next;
+		kfree(bf->buf);
+		is->first = bf;
+	}
+	bl->buf = (char *) nbuf;
+	bl->len = len + 4;
+
+	is->last = bl->next;
+	spin_unlock_irqrestore(&is->buflock, flags);
+	wake_up_interruptible(&is->wq);
+	return len;
 }
 
 /*
- * bind isdn_net_local <=> ippp-device
+ * read() .. non-blocking: ipppd calls it only after select()
+ *           reports, that there is data
  */
+
 int
-isdn_ppp_bind(isdn_net_dev *idev)
+isdn_ppp_read(int min, struct file *file, char *buf, int count)
 {
-	struct ind_ppp *ind_ppp;
-	int unit = 0;
-	unsigned long flags;
-	int retval = 0;
-	struct ipppd *ipppd;
-
-	if (idev->ind_priv) {
-		isdn_BUG();
-		return -EIO;
-	}
-	ind_ppp = kmalloc(sizeof(struct ind_ppp), GFP_KERNEL);
-	if (!ind_ppp)
-		return -ENOMEM;
-
-	spin_lock_irqsave(&ipppds_lock, flags);
-	if (idev->pppbind < 0) {  /* device not bound to ippp device ? */
-		struct list_head *l;
-		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
-		memset(exclusive, 0, ISDN_MAX_CHANNELS);
-		/* step through net devices to find exclusive minors */
-		list_for_each(l, &isdn_net_devs) {
-			isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-			if (p->pppbind >= 0 && p->pppbind < ISDN_MAX_CHANNELS)
-				exclusive[p->pppbind] = 1;
-		}
-		/*
-		 * search a free device / slot
-		 */
-		list_for_each_entry(ipppd, &ipppds, ipppds) {
-			if (!ipppd)
-				continue;
-			if (ipppd->state != IPPPD_ST_OPEN)
-				continue;
-			if (!exclusive[ipppd->minor])
-				goto found;
-		}
-	} else {
-		list_for_each_entry(ipppd, &ipppds, ipppds) {
-			if (!ipppd)
-				continue;
-			if (ipppd->state != IPPPD_ST_OPEN)
-				continue;
-			if (ipppd->minor == idev->pppbind)
-				goto found;
-		}
-	}
+	struct ippp_struct *is;
+	struct ippp_buf_queue *b;
+	int r;
+	u_long flags;
+	u_char *save_buf;
 
-	printk(KERN_INFO "isdn_ppp_bind: no ipppd\n");
-	retval = -ESRCH;
-	goto err;
+	is = file->private_data;
 
- found:
-	unit = isdn_ppp_if_get_unit(idev->name);	/* get unit number from interface name .. ugly! */
-	if (unit < 0) {
-		printk(KERN_INFO "isdn_ppp_bind: invalid interface name %s.\n", idev->name);
-		retval = -ENODEV;
-		goto err;
-	}
-	
-	ipppd->unit = unit;
-	ipppd->state = IPPPD_ST_ASSIGNED;
-	ipppd->idev = idev;
-	/* we hold a reference until isdn_ppp_unbind() */
-	ipppd_get(ipppd);
-	spin_unlock_irqrestore(&ipppds_lock, flags);
-
-	idev->ind_priv = ind_ppp;
-	ind_ppp->pppcfg = 0;         /* config flags */
-	ind_ppp->ipppd = ipppd;
-	ind_ppp->ccp = ippp_ccp_alloc();
-	if (!ind_ppp->ccp) {
-		retval = -ENOMEM;
-		goto out;
-	}
-	ind_ppp->ccp->proto       = PPP_COMPFRAG;
-	ind_ppp->ccp->priv        = idev;
-	ind_ppp->ccp->alloc_skb   = isdn_ppp_dev_alloc_skb;
-	ind_ppp->ccp->xmit        = isdn_ppp_dev_xmit;
-	ind_ppp->ccp->kick_up     = isdn_ppp_dev_kick_up;
+	if (!(is->state & IPPP_OPEN))
+		return 0;
 
-	retval = ippp_mp_bind(idev);
-	if (retval)
-		goto out;
-	
-	return 0;
+	if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
+		return r;
 
- out:
-	ipppd->state = IPPPD_ST_OPEN;
-	ipppd_put(ipppd);
-	ind_ppp->ipppd = NULL;
-	kfree(ind_ppp);
-	idev->ind_priv = NULL;
-	return retval;
+	spin_lock_irqsave(&is->buflock, flags);
+	b = is->first->next;
+	save_buf = b->buf;
+	if (!save_buf) {
+		spin_unlock_irqrestore(&is->buflock, flags);
+		return -EAGAIN;
+	}
+	if (b->len < count)
+		count = b->len;
+	b->buf = NULL;
+	is->first = b;
+
+	spin_unlock_irqrestore(&is->buflock, flags);
+	copy_to_user(buf, save_buf, count);
+	kfree(save_buf);
 
- err:
-	spin_unlock_irqrestore(&ipppds_lock, flags);
-	kfree(ind_ppp);
-	return retval;
+	return count;
 }
 
 /*
- * kick the ipppd on the device
- * (wakes up daemon after B-channel connect)
+ * ipppd wanna write a packet to the card .. non-blocking
  */
 
-static void
-isdn_ppp_connected(isdn_net_dev *idev)
+int
+isdn_ppp_write(int min, struct file *file, const char *buf, int count)
 {
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct ipppd *ipppd = ind_ppp->ipppd;
+	isdn_net_local *lp;
+	struct ippp_struct *is;
+	int proto;
+	unsigned char protobuf[4];
 
-	ipppd_debug(ipppd, "");
+	is = file->private_data;
 
-	ipppd->state  = IPPPD_ST_CONNECTED;
-	ipppd->flags |= IPPPD_FL_WAKEUP;
-	wake_up(&ipppd->wq);
-}
+	if (!(is->state & IPPP_CONNECT))
+		return 0;
 
-static void
-isdn_ppp_disconnected(isdn_net_dev *idev)
-{
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct ipppd *ipppd = ind_ppp->ipppd;
+	lp = is->lp;
 
-	ipppd_debug(ipppd, "");
+	/* -> push it directly to the lowlevel interface */
 
-	if (ind_ppp->pppcfg & SC_ENABLE_IP)
-		isdn_net_offline(idev);
+	if (!lp)
+		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
+	else {
+		/*
+		 * Don't reset huptimer for
+		 * LCP packets. (Echo requests).
+		 */
+		if (copy_from_user(protobuf, buf, 4))
+			return -EFAULT;
+		proto = PPP_PROTOCOL(protobuf);
+		if (proto != PPP_LCP)
+			lp->huptimer = 0;
+
+		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
+			return 0;
+
+		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
+			lp->dialstate == 0 &&
+		    (lp->flags & ISDN_NET_CONNECTED)) {
+			unsigned short hl;
+			struct sk_buff *skb;
+			/*
+			 * we need to reserve enought space in front of
+			 * sk_buff. old call to dev_alloc_skb only reserved
+			 * 16 bytes, now we are looking what the driver want
+			 */
+			hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+			skb = alloc_skb(hl+count, GFP_ATOMIC);
+			if (!skb) {
+				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
+				return count;
+			}
+			skb_reserve(skb, hl);
+			if (copy_from_user(skb_put(skb, count), buf, count))
+			{
+				kfree_skb(skb);
+				return -EFAULT;
+			}
+			if (is->debug & 0x40) {
+				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
+				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+			}
 
-	if (ipppd->state != IPPPD_ST_CONNECTED)
-		isdn_BUG();
-	
-	ipppd->state  = IPPPD_ST_ASSIGNED;
-	ipppd->flags |= IPPPD_FL_HUP;
-	wake_up(&ipppd->wq);
+			isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
 
-	ippp_mp_disconnected(idev);
+			isdn_net_write_super(lp, skb);
+		}
+	}
+	return count;
 }
 
 /*
@@ -807,44 +847,76 @@
 int
 isdn_ppp_init(void)
 {
+	int i,
+	 j;
+	 
+#ifdef CONFIG_ISDN_MPP
+	if( isdn_ppp_mp_bundle_array_init() < 0 )
+		return -ENOMEM;
+#endif /* CONFIG_ISDN_MPP */
+
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		if (!(ippp_table[i] = (struct ippp_struct *)
+		      kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+			printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
+			for (j = 0; j < i; j++)
+				kfree(ippp_table[j]);
+			return -1;
+		}
+		memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
+		spin_lock_init(&ippp_table[i]->buflock);
+		ippp_table[i]->state = 0;
+		ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
+		ippp_table[i]->last = ippp_table[i]->rq;
+
+		for (j = 0; j < NUM_RCV_BUFFS; j++) {
+			ippp_table[i]->rq[j].buf = NULL;
+			ippp_table[i]->rq[j].last = ippp_table[i]->rq +
+			    (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
+			ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
+		}
+	}
 	return 0;
 }
 
 void
 isdn_ppp_cleanup(void)
 {
+	int i;
+
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		kfree(ippp_table[i]);
+
+#ifdef CONFIG_ISDN_MPP
+	if (isdn_ppp_bundle_arr)
+		kfree(isdn_ppp_bundle_arr);
+#endif /* CONFIG_ISDN_MPP */
+
 }
 
 /*
  * check for address/control field and skip if allowed
  * retval != 0 -> discard packet silently
  */
-static int
-isdn_ppp_skip_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb) 
+static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) 
 {
-	u8 val;
-
 	if (skb->len < 1)
-		return -EINVAL;
-
-	get_u8(skb->data, &val);
-	if (val != PPP_ALLSTATIONS) {
-		/* if AC compression was not negotiated, but no AC present,
-		   discard packet */
-		if (ind_ppp->pppcfg & SC_REJ_COMP_AC)
-			return -EINVAL;
+		return -1;
 
-		return 0;
-	}
-	if (skb->len < 2)
-		return -EINVAL;
+	if (skb->data[0] == 0xff) {
+		if (skb->len < 2)
+			return -1;
 
-	get_u8(skb->data + 1, &val);
-	if (val != PPP_UI)
-		return -EINVAL;
+		if (skb->data[1] != 0x03)
+			return -1;
 
-	/* skip address/control (AC) field */
-	skb_pull(skb, 2);
+		// skip address/control (AC) field
+		skb_pull(skb, 2);
+	} else { 
+		if (is->pppcfg & SC_REJ_COMP_AC)
+			// if AC compression was not negotiated, but used, discard packet
+			return -1;
+	}
 	return 0;
 }
 
@@ -852,127 +924,262 @@
  * get the PPP protocol header and pull skb
  * retval < 0 -> discard packet silently
  */
-int
-isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto) 
+static int isdn_ppp_strip_proto(struct sk_buff *skb) 
 {
-	u8 val;
-
+	int proto;
+	
 	if (skb->len < 1)
-		return -EINVAL;
+		return -1;
 
-	get_u8(skb->data, &val);
-	if (val & 0x1) {
-		/* protocol field is compressed */
-		*proto = val;
+	if (skb->data[0] & 0x1) {
+		// protocol field is compressed
+		proto = skb->data[0];
 		skb_pull(skb, 1);
 	} else {
 		if (skb->len < 2)
-			return -EINVAL;
-		get_u16(skb->data, proto);
+			return -1;
+		proto = ((int) skb->data[0] << 8) + skb->data[1];
 		skb_pull(skb, 2);
 	}
-	return 0;
+	return proto;
 }
 
+
 /*
  * handler for incoming packets on a syncPPP interface
  */
-static void
-isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb)
+void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
 {
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct ipppd *is = ind_ppp->ipppd;
-	u16 proto;
-
-	if (!is) 
-		goto err;
-
-	if (is->debug & 0x4) {
-		printk(KERN_DEBUG "ippp_receive: is:%p lp:%p unit:%d len:%d\n",
-		       is, lp, is->unit, skb->len);
-		isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,-1);
+	struct ippp_struct *is;
+	int slot;
+	int proto;
+
+	if (net_dev->local->master)
+		BUG(); // we're called with the master device always
+
+	slot = lp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
+		kfree_skb(skb);
+		return;
 	}
+	is = ippp_table[slot];
 
- 	if (isdn_ppp_skip_ac(ind_ppp, skb) < 0)
-		goto err;
-
-  	if (isdn_ppp_strip_proto(skb, &proto))
-		goto err;
-
-	ippp_mp_receive(idev, skb, proto);
-	return;
-
- err:
-	lp->stats.rx_dropped++;
-	kfree_skb(skb);
+	if (is->debug & 0x4) {
+		printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
+		       (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
+		isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+	}
+
+ 	if (isdn_ppp_skip_ac(is, skb) < 0) {
+ 		kfree_skb(skb);
+ 		return;
+ 	}
+  	proto = isdn_ppp_strip_proto(skb);
+ 	if (proto < 0) {
+ 		kfree_skb(skb);
+ 		return;
+ 	}
+  
+#ifdef CONFIG_ISDN_MPP
+ 	if (is->compflags & SC_LINK_DECOMP_ON) {
+ 		skb = isdn_ppp_decompress(skb, is, NULL, &proto);
+ 		if (!skb) // decompression error
+ 			return;
+ 	}
+	
+ 	if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
+  		if (proto == PPP_MP) {
+  			isdn_ppp_mp_receive(net_dev, lp, skb);
+ 			return;
+ 		}
+ 	} 
+#endif
+ 	isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
 /*
+ * we receive a reassembled frame, MPPP has been taken care of before.
  * address/control and protocol have been stripped from the skb
+ * note: net_dev has to be master net_dev
  */
-void
-ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+static void
+isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
 {
-	isdn_net_local *lp = idev->mlp;
-	struct inl_ppp *inl_ppp = lp->inl_priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
- 	struct ipppd *is = ind_ppp->ipppd;
+	struct net_device *dev = &net_dev->dev;
+ 	struct ippp_struct *is, *mis;
+	isdn_net_local *mlp = NULL;
+	int slot;
+
+	slot = lp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
+		goto drop_packet;
+	}
+	is = ippp_table[slot];
+ 	
+ 	if (lp->master) { // FIXME?
+		mlp = (isdn_net_local *) lp->master->priv;
+ 		slot = mlp->ppp_slot;
+ 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
+ 				lp->ppp_slot);
+			goto drop_packet;
+ 		}
+ 	}
+ 	mis = ippp_table[slot];
 
 	if (is->debug & 0x10) {
 		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
-		isdn_ppp_frame_log("rpush", skb->data, skb->len, 256, is->unit, -1);
+		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
 	}
-	/* all packets need to be passed through the compressor */
-	skb = ippp_ccp_decompress(inl_ppp->ccp, skb, &proto);
-	if (!skb) /* decompression error */
-		goto error;
-
+	if (mis->compflags & SC_DECOMP_ON) {
+		skb = isdn_ppp_decompress(skb, is, mis, &proto);
+		if (!skb) // decompression error
+  			return;
+  	}
 	switch (proto) {
 		case PPP_IPX:  /* untested */
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: IPX\n");
-			isdn_netif_rx(idev, skb, htons(ETH_P_IPX));
+			skb->protocol = htons(ETH_P_IPX);
 			break;
 		case PPP_IP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: IP\n");
-			isdn_netif_rx(idev, skb, htons(ETH_P_IP));
+			skb->protocol = htons(ETH_P_IP);
 			break;
 		case PPP_COMP:
 		case PPP_COMPFRAG:
 			printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
-			goto drop;
+			goto drop_packet;
+#ifdef CONFIG_ISDN_PPP_VJ
 		case PPP_VJC_UNCOMP:
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+			if (net_dev->local->ppp_slot < 0) {
+				printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
+					__FUNCTION__, net_dev->local->ppp_slot);
+				goto drop_packet;
+			}
+			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
+				goto drop_packet;
+			}
+			skb->protocol = htons(ETH_P_IP);
+			break;
 		case PPP_VJC_COMP:
-			ippp_vj_decompress(idev, skb, proto);
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+			{
+				struct sk_buff *skb_old = skb;
+				int pkt_len;
+				skb = dev_alloc_skb(skb_old->len + 128);
+
+				if (!skb) {
+					printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+					skb = skb_old;
+					goto drop_packet;
+				}
+				skb_put(skb, skb_old->len + 128);
+				memcpy(skb->data, skb_old->data, skb_old->len);
+				if (net_dev->local->ppp_slot < 0) {
+					printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
+						__FUNCTION__, net_dev->local->ppp_slot);
+					goto drop_packet;
+				}
+				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
+						skb->data, skb_old->len);
+				kfree_skb(skb_old);
+				if (pkt_len < 0)
+					goto drop_packet;
+
+				skb_trim(skb, pkt_len);
+				skb->protocol = htons(ETH_P_IP);
+			}
 			break;
-		case PPP_CCPFRAG:
-			ippp_ccp_receive_ccp(ind_ppp->ccp, skb);
-			goto ccp;
+#endif
 		case PPP_CCP:
-			ippp_ccp_receive_ccp(inl_ppp->ccp, skb);
-	ccp:
+		case PPP_CCPFRAG:
+			isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
 			/* Dont pop up ResetReq/Ack stuff to the daemon any
 			   longer - the job is done already */
 			if(skb->data[0] == CCP_RESETREQ ||
 			   skb->data[0] == CCP_RESETACK)
-				goto free;
+				break;
 			/* fall through */
 		default:
-			// FIXME use skb directly
-			ipppd_queue_read(is, proto, skb->data, skb->len);
-			goto free;
+			isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
+			kfree_skb(skb);
+			return;
+	}
+
+#ifdef CONFIG_IPPP_FILTER
+	/* check if the packet passes the pass and active filters
+	 * the filter instructions are constructed assuming
+	 * a four-byte PPP header on each packet (which is still present) */
+	skb_push(skb, 4);
+	skb->data[0] = 0;	/* indicate inbound */
+
+	if (is->pass_filter.filter
+	    && sk_run_filter(skb, is->pass_filter.filter,
+	                    is->pass_filter.len) == 0) {
+		if (is->debug & 0x2)
+			printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
+		kfree_skb(skb);
+		return;
 	}
+	if (!(is->active_filter.filter
+	      && sk_run_filter(skb, is->active_filter.filter,
+	                       is->active_filter.len) == 0)) {
+		if (is->debug & 0x2)
+			printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
+		lp->huptimer = 0;
+		if (mlp)
+			mlp->huptimer = 0;
+	}
+	skb_pull(skb, 4);
+#else /* CONFIG_IPPP_FILTER */
+	lp->huptimer = 0;
+	if (mlp)
+		mlp->huptimer = 0;
+#endif /* CONFIG_IPPP_FILTER */
+	skb->dev = dev;
+	skb->mac.raw = skb->data;
+	netif_rx(skb);
+	/* net_dev->local->stats.rx_packets++; done in isdn_net.c */
 	return;
 
- drop:
-	lp->stats.rx_dropped++;
- free:
+ drop_packet:
+	net_dev->local->stats.rx_dropped++;
 	kfree_skb(skb);
-	return;
+}
+
+/*
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the skb
+ * and allocs a new SKB if necessary
+ */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
+{
+	struct sk_buff *skb = *skb_p;
+
+	if(skb_headroom(skb) < len) {
+		struct sk_buff *nskb = skb_realloc_headroom(skb, len);
 
- error:
-	lp->stats.rx_dropped++;
+		if (!nskb) {
+			printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
+			dev_kfree_skb(skb);
+			return NULL;
+		}
+		printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+		dev_kfree_skb(skb);
+		*skb_p = nskb;
+		return skb_push(nskb, len);
+	}
+	return skb_push(skb,len);
 }
 
 /*
@@ -983,99 +1190,773 @@
  * skb isn't allowed!!
  */
 
-static int
-isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+int
+isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	isdn_net_local *lp,*mlp;
+	isdn_net_dev *nd;
+	unsigned int proto = PPP_IP;     /* 0x21 */
+	struct ippp_struct *ipt,*ipts;
+	int slot, retval = 0;
+
+	mlp = (isdn_net_local *) (netdev->priv);
+	nd = mlp->netdev;       /* get master lp */
+
+	slot = mlp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			mlp->ppp_slot);
+		kfree_skb(skb);
+		goto out;
+	}
+	ipts = ippp_table[slot];
+
+	if (!(ipts->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
+		if (ipts->debug & 0x1)
+			printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
+		retval = 1;
+		goto out;
+	}
+
+	switch (ntohs(skb->protocol)) {
+		case ETH_P_IP:
+			proto = PPP_IP;
+			break;
+		case ETH_P_IPX:
+			proto = PPP_IPX;	/* untested */
+			break;
+		default:
+			printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", 
+			       skb->protocol);
+			dev_kfree_skb(skb);
+			goto out;
+	}
+
+	lp = isdn_net_get_locked_lp(nd);
+	if (!lp) {
+		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
+		retval = 1;
+		goto out;
+	}
+	/* we have our lp locked from now on */
+
+	slot = lp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
+		kfree_skb(skb);
+		goto unlock;
+	}
+	ipt = ippp_table[slot];
+
+	/*
+	 * after this line .. requeueing in the device queue is no longer allowed!!!
+	 */
+
+	/* Pull off the fake header we stuck on earlier to keep
+	 * the fragmentation code happy.
+	 */
+	skb_pull(skb,IPPP_MAX_HEADER);
+
+#ifdef CONFIG_IPPP_FILTER
+	/* check if we should pass this packet
+	 * the filter instructions are constructed assuming
+	 * a four-byte PPP header on each packet */
+	skb_push(skb, 4);
+	skb->data[0] = 1;	/* indicate outbound */
+	*(u_int16_t *)(skb->data + 2) = htons(proto);
+
+	if (ipt->pass_filter.filter 
+	    && sk_run_filter(skb, ipt->pass_filter.filter,
+		             ipt->pass_filter.len) == 0) {
+		if (ipt->debug & 0x4)
+			printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
+		kfree_skb(skb);
+		goto unlock;
+	}
+	if (!(ipt->active_filter.filter
+	      && sk_run_filter(skb, ipt->active_filter.filter,
+		               ipt->active_filter.len) == 0)) {
+		if (ipt->debug & 0x4)
+			printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
+		lp->huptimer = 0;
+	}
+	skb_pull(skb, 4);
+#else /* CONFIG_IPPP_FILTER */
+	lp->huptimer = 0;
+#endif /* CONFIG_IPPP_FILTER */
+
+	if (ipt->debug & 0x4)
+		printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
+        if (ipts->debug & 0x40)
+                isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot);
+
+#ifdef CONFIG_ISDN_PPP_VJ
+	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes, but check this again */
+		struct sk_buff *new_skb;
+	        unsigned short hl;
+		/*
+		 * we need to reserve enought space in front of
+		 * sk_buff. old call to dev_alloc_skb only reserved
+		 * 16 bytes, now we are looking what the driver want.
+		 */
+		hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
+		/* 
+		 * Note: hl might still be insufficient because the method
+		 * above does not account for a possibible MPPP slave channel
+		 * which had larger HL header space requirements than the
+		 * master.
+		 */
+		new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC);
+		if (new_skb) {
+			u_char *buf;
+			int pktlen;
+
+			skb_reserve(new_skb, hl);
+			new_skb->dev = skb->dev;
+			skb_put(new_skb, skb->len);
+			buf = skb->data;
+
+			pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
+				 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
+
+			if (buf != skb->data) {	
+				if (new_skb->data != buf)
+					printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
+				dev_kfree_skb(skb);
+				skb = new_skb;
+			} else {
+				dev_kfree_skb(new_skb);
+			}
+
+			skb_trim(skb, pktlen);
+			if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) {	/* cslip? style -> PPP */
+				proto = PPP_VJC_COMP;
+				skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
+			} else {
+				if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+					proto = PPP_VJC_UNCOMP;
+				skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
+			}
+		}
+	}
+#endif
+
+	/*
+	 * normal (single link) or bundle compression
+	 */
+	if(ipts->compflags & SC_COMP_ON) {
+		/* We send compressed only if both down- und upstream
+		   compression is negotiated, that means, CCP is up */
+		if(ipts->compflags & SC_DECOMP_ON) {
+			skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+		} else {
+			printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
+		}
+	}
+
+	if (ipt->debug & 0x24)
+		printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
+
+#ifdef CONFIG_ISDN_MPP
+	if (ipt->mpppcfg & SC_MP_PROT) {
+		/* we get mp_seqno from static isdn_net_local */
+		long mp_seqno = ipts->mp_seqno;
+		ipts->mp_seqno++;
+		if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
+			unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+			if(!data)
+				goto unlock;
+			mp_seqno &= 0xfff;
+			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf);	/* (B)egin & (E)ndbit .. */
+			data[1] = mp_seqno & 0xff;
+			data[2] = proto;	/* PID compression */
+		} else {
+			unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+			if(!data)
+				goto unlock;
+			data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
+			data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
+			data[2] = (mp_seqno >> 8) & 0xff;
+			data[3] = (mp_seqno >> 0) & 0xff;
+			data[4] = proto;	/* PID compression */
+		}
+		proto = PPP_MP; /* MP Protocol, 0x003d */
+	}
+#endif
+
+	/*
+	 * 'link in bundle' compression  ...
+	 */
+	if(ipt->compflags & SC_LINK_COMP_ON)
+		skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
+	if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
+		unsigned char *data = isdn_ppp_skb_push(&skb,1);
+		if(!data)
+			goto unlock;
+		data[0] = proto & 0xff;
+	}
+	else {
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			goto unlock;
+		data[0] = (proto >> 8) & 0xff;
+		data[1] = proto & 0xff;
+	}
+	if(!(ipt->pppcfg & SC_COMP_AC)) {
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			goto unlock;
+		data[0] = 0xff;    /* All Stations */
+		data[1] = 0x03;    /* Unnumbered information */
+	}
+
+	/* tx-stats are now updated via BSENT-callback */
+
+	if (ipts->debug & 0x40) {
+		printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
+		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
+	}
+	
+	isdn_net_writebuf_skb(lp, skb);
+
+ unlock:
+	spin_unlock_bh(&lp->xmit_lock);
+ out:
+	return retval;
+}
+
+#ifdef CONFIG_IPPP_FILTER
+/*
+ * check if this packet may trigger auto-dial.
+ */
+
+int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
+{
+	struct ippp_struct *is = ippp_table[lp->ppp_slot];
+	u_int16_t proto;
+	int drop = 0;
+
+	switch (ntohs(skb->protocol)) {
+	case ETH_P_IP:
+		proto = PPP_IP;
+		break;
+	case ETH_P_IPX:
+		proto = PPP_IPX;
+		break;
+	default:
+		printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
+		       skb->protocol);
+		return 1;
+	}
+
+	/* the filter instructions are constructed assuming
+	 * a four-byte PPP header on each packet. we have to
+	 * temporarily remove part of the fake header stuck on
+	 * earlier.
+	 */
+	skb_pull(skb, IPPP_MAX_HEADER - 4);
+	skb->data[0] = 1;	/* indicate outbound */
+	*(u_int16_t *)(skb->data + 2) = htons(proto);
+	
+	drop |= is->pass_filter.filter
+	        && sk_run_filter(skb, is->pass_filter.filter,
+	                         is->pass_filter.len) == 0;
+	drop |= is->active_filter.filter
+	        && sk_run_filter(skb, is->active_filter.filter,
+	                         is->active_filter.len) == 0;
+	
+	skb_push(skb, IPPP_MAX_HEADER - 4);
+	return drop;
+}
+#endif
+#ifdef CONFIG_ISDN_MPP
+
+/* this is _not_ rfc1990 header, but something we convert both short and long
+ * headers to for convinience's sake:
+ * 	byte 0 is flags as in rfc1990
+ *	bytes 1...4 is 24-bit seqence number converted to host byte order 
+ */
+#define MP_HEADER_LEN	5
+
+#define MP_LONGSEQ_MASK		0x00ffffff
+#define MP_SHORTSEQ_MASK	0x00000fff
+#define MP_LONGSEQ_MAX		MP_LONGSEQ_MASK
+#define MP_SHORTSEQ_MAX		MP_SHORTSEQ_MASK
+#define MP_LONGSEQ_MAXBIT	((MP_LONGSEQ_MASK+1)>>1)
+#define MP_SHORTSEQ_MAXBIT	((MP_SHORTSEQ_MASK+1)>>1)
+
+/* sequence-wrap safe comparisions (for long sequence)*/ 
+#define MP_LT(a,b)	((a-b)&MP_LONGSEQ_MAXBIT)
+#define MP_LE(a,b) 	!((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GT(a,b) 	((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GE(a,b)	!((a-b)&MP_LONGSEQ_MAXBIT)
+
+#define MP_SEQ(f)	((*(u32*)(f->data+1)))
+#define MP_FLAGS(f)	(f->data[0])
+
+static int isdn_ppp_mp_bundle_array_init(void)
+{
+	int i;
+	int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
+	if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz, 
+							GFP_KERNEL)) == NULL )
+		return -ENOMEM;
+	memset(isdn_ppp_bundle_arr, 0, sz);
+	for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
+		spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
+	return 0;
+}
+
+static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
 {
-	isdn_net_local *mlp = ndev->priv;
-	struct inl_ppp *inl_ppp = mlp->inl_priv;
-	struct ind_ppp *ind_ppp;
-	isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online);
-	u16 proto = PPP_IP;     /* 0x21 */
-	struct ipppd *ipppd;
+	int i;
+	for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
+		if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
+			return (isdn_ppp_bundle_arr + i);
+	return NULL;
+}
+
+static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
+{
+	struct ippp_struct * is;
+
+	if (lp->ppp_slot < 0) {
+		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+			__FUNCTION__, lp->ppp_slot);
+		return(-EINVAL);
+	}
+
+	is = ippp_table[lp->ppp_slot];
+	if (add_to) {
+		if( lp->netdev->pb )
+			lp->netdev->pb->ref_ct--;
+		lp->netdev->pb = add_to;
+	} else {		/* first link in a bundle */
+		is->mp_seqno = 0;
+		if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
+			return -ENOMEM;
+		lp->next = lp->last = lp;	/* nobody else in a queue */
+		lp->netdev->pb->frags = NULL;
+		lp->netdev->pb->frames = 0;
+		lp->netdev->pb->seq = LONG_MAX;
+	}
+	lp->netdev->pb->ref_ct++;
+	
+	is->last_link_seqno = 0;
+	return 0;
+}
 
-	ndev->trans_start = jiffies;
+static u32 isdn_ppp_mp_get_seq( int short_seq, 
+					struct sk_buff * skb, u32 last_seq );
+static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+			struct sk_buff * from, struct sk_buff * to );
+static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+				struct sk_buff * from, struct sk_buff * to );
+static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
+static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
+
+static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 
+							struct sk_buff *skb)
+{
+	struct ippp_struct *is;
+	isdn_net_local * lpq;
+	ippp_bundle * mp;
+	isdn_mppp_stats * stats;
+	struct sk_buff * newfrag, * frag, * start, *nextf;
+	u32 newseq, minseq, thisseq;
+	unsigned long flags;
+	int slot;
 
-	if (list_empty(&mlp->online))
-		return isdn_net_autodial(skb, ndev);
+	spin_lock_irqsave(&net_dev->pb->lock, flags);
+    	mp = net_dev->pb;
+        stats = &mp->stats;
+	slot = lp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
+			__FUNCTION__, lp->ppp_slot);
+		stats->frame_drops++;
+		dev_kfree_skb(skb);
+		spin_unlock_irqrestore(&mp->lock, flags);
+		return;
+	}
+	is = ippp_table[slot];
+    	if( ++mp->frames > stats->max_queue_len )
+		stats->max_queue_len = mp->frames;
+	
+	if (is->debug & 0x8)
+		isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
 
-	switch (ntohs(skb->protocol)) {
-		case ETH_P_IP:
-			proto = PPP_IP;
-			break;
-		case ETH_P_IPX:
-			proto = PPP_IPX;	/* untested */
+	newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, 
+						skb, is->last_link_seqno);
+
+
+	/* if this packet seq # is less than last already processed one,
+	 * toss it right away, but check for sequence start case first 
+	 */
+	if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
+		mp->seq = newseq;	/* the first packet: required for
+					 * rfc1990 non-compliant clients --
+					 * prevents constant packet toss */
+	} else if( MP_LT(newseq, mp->seq) ) {
+		stats->frame_drops++;
+		isdn_ppp_mp_free_skb(mp, skb);
+		spin_unlock_irqrestore(&mp->lock, flags);
+		return;
+	}
+	
+	/* find the minimum received sequence number over all links */
+	is->last_link_seqno = minseq = newseq;
+	for (lpq = net_dev->queue;;) {
+		slot = lpq->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
+				__FUNCTION__, lpq->ppp_slot);
+		} else {
+			u32 lls = ippp_table[slot]->last_link_seqno;
+			if (MP_LT(lls, minseq))
+				minseq = lls;
+		}
+		if ((lpq = lpq->next) == net_dev->queue)
 			break;
-		default:
-			printk(KERN_INFO "isdn_ppp: skipped unsupported protocol: %#x.\n", 
-			       skb->protocol);
-			goto drop;
 	}
+	if (MP_LT(minseq, mp->seq))
+		minseq = mp->seq;	/* can't go beyond already processed
+					 * packets */
+	newfrag = skb;
+
+  	/* if this new fragment is before the first one, then enqueue it now. */
+  	if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
+		newfrag->next = frag;
+    		mp->frags = frag = newfrag;
+    		newfrag = NULL;
+  	}
+
+  	start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
+				MP_SEQ(frag) == mp->seq ? frag : NULL;
+
+	/* 
+	 * main fragment traversing loop
+	 *
+	 * try to accomplish several tasks:
+	 * - insert new fragment into the proper sequence slot (once that's done
+	 *   newfrag will be set to NULL)
+	 * - reassemble any complete fragment sequence (non-null 'start'
+	 *   indicates there is a continguous sequence present)
+	 * - discard any incomplete sequences that are below minseq -- due
+	 *   to the fact that sender always increment sequence number, if there
+	 *   is an incomplete sequence below minseq, no new fragments would
+	 *   come to complete such sequence and it should be discarded
+	 *
+	 * loop completes when we accomplished the following tasks:
+	 * - new fragment is inserted in the proper sequence ('newfrag' is 
+	 *   set to NULL)
+	 * - we hit a gap in the sequence, so no reassembly/processing is 
+	 *   possible ('start' would be set to NULL)
+	 *
+	 * algorightm for this code is derived from code in the book
+	 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
+	 */
+  	while (start != NULL || newfrag != NULL) {
+
+    		thisseq = MP_SEQ(frag);
+    		nextf = frag->next;
+
+    		/* drop any duplicate fragments */
+    		if (newfrag != NULL && thisseq == newseq) {
+      			isdn_ppp_mp_free_skb(mp, newfrag);
+      			newfrag = NULL;
+    		}
+
+    		/* insert new fragment before next element if possible. */
+    		if (newfrag != NULL && (nextf == NULL || 
+						MP_LT(newseq, MP_SEQ(nextf)))) {
+      			newfrag->next = nextf;
+      			frag->next = nextf = newfrag;
+      			newfrag = NULL;
+    		}
+
+    		if (start != NULL) {
+	    		/* check for misplaced start */
+      			if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
+				printk(KERN_WARNING"isdn_mppp(seq %d): new "
+				      "BEGIN flag with no prior END", thisseq);
+				stats->seqerrs++;
+				stats->frame_drops++;
+				start = isdn_ppp_mp_discard(mp, start,frag);
+				nextf = frag->next;
+      			}
+    		} else if (MP_LE(thisseq, minseq)) {		
+      			if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
+				start = frag;
+      			else {
+				if (MP_FLAGS(frag) & MP_END_FRAG)
+	  				stats->frame_drops++;
+				if( mp->frags == frag )
+					mp->frags = nextf;	
+				isdn_ppp_mp_free_skb(mp, frag);
+				frag = nextf;
+				continue;
+      			}
+		}
+		
+		/* if start is non-null and we have end fragment, then
+		 * we have full reassembly sequence -- reassemble 
+		 * and process packet now
+		 */
+    		if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
+      			minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
+      			/* Reassemble the packet then dispatch it */
+			isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
+      
+      			start = NULL;
+      			frag = NULL;
+
+      			mp->frags = nextf;
+    		}
+
+		/* check if need to update start pointer: if we just
+		 * reassembled the packet and sequence is contiguous
+		 * then next fragment should be the start of new reassembly
+		 * if sequence is contiguous, but we haven't reassembled yet,
+		 * keep going.
+		 * if sequence is not contiguous, either clear everyting
+		 * below low watermark and set start to the next frag or
+		 * clear start ptr.
+		 */ 
+    		if (nextf != NULL && 
+		    ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
+      			/* if we just reassembled and the next one is here, 
+			 * then start another reassembly. */
+
+      			if (frag == NULL) {
+				if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
+	  				start = nextf;
+				else
+				{
+	  				printk(KERN_WARNING"isdn_mppp(seq %d):"
+						" END flag with no following "
+						"BEGIN", thisseq);
+					stats->seqerrs++;
+				}
+			}
 
-	idev = isdn_net_get_xmit_dev(mlp);
-	if (!idev) {
-		printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name);
-		goto stop;
+    		} else {
+			if ( nextf != NULL && frag != NULL &&
+						MP_LT(thisseq, minseq)) {
+				/* we've got a break in the sequence
+				 * and we not at the end yet
+				 * and we did not just reassembled
+				 *(if we did, there wouldn't be anything before)
+				 * and we below the low watermark 
+			 	 * discard all the frames below low watermark 
+				 * and start over */
+				stats->frame_drops++;
+				mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
+			}
+			/* break in the sequence, no reassembly */
+      			start = NULL;
+    		}
+	  			
+    		frag = nextf;
+  	}	/* while -- main loop */
+	
+  	if (mp->frags == NULL)
+    		mp->frags = frag;
+		
+	/* rather straighforward way to deal with (not very) possible 
+	 * queue overflow */
+	if (mp->frames > MP_MAX_QUEUE_LEN) {
+		stats->overflows++;
+		while (mp->frames > MP_MAX_QUEUE_LEN) {
+			frag = mp->frags->next;
+			isdn_ppp_mp_free_skb(mp, mp->frags);
+			mp->frags = frag;
+		}
 	}
-	ind_ppp = idev->ind_priv;
-	if (!(ind_ppp->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
-		isdn_BUG();
-		goto stop;
+	spin_unlock_irqrestore(&mp->lock, flags);
+}
+
+static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
+{
+	struct sk_buff * frag = lp->netdev->pb->frags;
+	struct sk_buff * nextfrag;
+    	while( frag ) {
+		nextfrag = frag->next;
+		isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
+		frag = nextfrag;
 	}
-	ipppd = ind_ppp->ipppd;
-	idev->huptimer = 0;
+	lp->netdev->pb->frags = NULL;
+}
 
-        if (ipppd->debug & 0x40)
-                isdn_ppp_frame_log("xmit0", skb->data, skb->len, 256, ipppd->unit, -1);
+static u32 isdn_ppp_mp_get_seq( int short_seq, 
+					struct sk_buff * skb, u32 last_seq )
+{
+	u32 seq;
+	int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
+   
+   	if( !short_seq )
+	{
+		seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;
+		skb_push(skb,1);
+	}
+	else
+	{
+		/* convert 12-bit short seq number to 24-bit long one 
+	 	*/
+		seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;
+	
+		/* check for seqence wrap */
+		if( !(seq &  MP_SHORTSEQ_MAXBIT) && 
+		     (last_seq &  MP_SHORTSEQ_MAXBIT) && 
+		     (unsigned long)last_seq <= MP_LONGSEQ_MAX )
+			seq |= (last_seq + MP_SHORTSEQ_MAX+1) & 
+					(~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
+		else
+			seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
+		
+		skb_push(skb, 3);	/* put converted seqence back in skb */
+	}
+	*(u32*)(skb->data+1) = seq; 	/* put seqence back in _host_ byte
+					 * order */
+	skb->data[0] = flags;	        /* restore flags */
+	return seq;
+}
+
+struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+			struct sk_buff * from, struct sk_buff * to )
+{
+	if( from )
+		while (from != to) {
+	  		struct sk_buff * next = from->next;
+			isdn_ppp_mp_free_skb(mp, from);
+	  		from = next;
+		}
+	return from;
+}
 
-	/* after this line,requeueing is no longer allowed! */
-	skb = ippp_vj_compress(idev, skb, &proto);
+void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+				struct sk_buff * from, struct sk_buff * to )
+{
+	ippp_bundle * mp = net_dev->pb;
+	int proto;
+	struct sk_buff * skb;
+	unsigned int tot_len;
 
-	/* normal (single link) or bundle compression */
-	skb = ippp_ccp_compress(inl_ppp->ccp, skb, &proto);
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+			__FUNCTION__, lp->ppp_slot);
+		return;
+	}
+	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
+		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
+					"len %d\n", MP_SEQ(from), from->len );
+		skb = from;
+		skb_pull(skb, MP_HEADER_LEN);
+		mp->frames--;	
+	} else {
+		struct sk_buff * frag;
+		int n;
 
-	if (ipppd->debug & 0x40)
-                isdn_ppp_frame_log("xmit1", skb->data, skb->len, 32, ipppd->unit, -1);
+		for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
+			tot_len += frag->len - MP_HEADER_LEN;
 
-	ippp_push_proto(ind_ppp, skb, proto);
-	ippp_mp_xmit(idev, skb);
-	return 0;
+		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
+				"to %d, len %d\n", MP_SEQ(from), 
+				(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
+		if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
+			printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
+					"of size %d\n", tot_len);
+			isdn_ppp_mp_discard(mp, from, to);
+			return;
+		}
 
- drop:
-	kfree_skb(skb);
-	mlp->stats.tx_dropped++;
-	return 0;
+		while( from != to ) {
+			unsigned int len = from->len - MP_HEADER_LEN;
 
- stop:
-	netif_stop_queue(ndev);
-	return 1;
+			memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
+			frag = from->next;
+			isdn_ppp_mp_free_skb(mp, from);
+			from = frag; 
+		}
+	}
+   	proto = isdn_ppp_strip_proto(skb);
+	isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
-void
-ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb)
+static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
+{
+	dev_kfree_skb(skb);
+	mp->frames--;
+}
+
+static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb )
 {
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct ipppd *ipppd = ind_ppp->ipppd;
+	printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", 
+		slot, (int) skb->len, 
+		(int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
+		(int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
+}
 
-	ippp_push_ac(ind_ppp, skb);
+static int
+isdn_ppp_bundle(struct ippp_struct *is, int unit)
+{
+	char ifn[IFNAMSIZ + 1];
+	isdn_net_dev *p;
+	isdn_net_local *lp, *nlp;
+	int rc;
+	unsigned long flags;
 
-	if (ipppd->debug & 0x40) {
-		isdn_ppp_frame_log("xmit3", skb->data, skb->len, 32, ipppd->unit, -1);
+	sprintf(ifn, "ippp%d", unit);
+	p = isdn_net_findif(ifn);
+	if (!p) {
+		printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
+		return -EINVAL;
 	}
-	
-	isdn_net_writebuf_skb(idev, skb);
-}
 
+    	spin_lock_irqsave(&p->pb->lock, flags);
+
+	nlp = is->lp;
+	lp = p->queue;
+	if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
+		lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
+		printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
+			nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? 
+			nlp->ppp_slot : lp->ppp_slot );
+		rc = -EINVAL;
+		goto out;
+ 	}
+
+	isdn_net_add_to_bundle(p, nlp);
+
+	ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
+
+	/* maybe also SC_CCP stuff */
+	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
+		(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
+	ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
+		(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
+	rc = isdn_ppp_mp_init(nlp, p->pb);
+out:
+	spin_unlock_irqrestore(&p->pb->lock, flags);
+	return rc;
+}
+  
+#endif /* CONFIG_ISDN_MPP */
+  
 /*
  * network device ioctl handlers
  */
 
 static int
-isdn_ppp_dev_ioctl_stats(struct ifreq *ifr, struct net_device *dev)
+isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
 {
-	struct ppp_stats *res, t;
+	struct ppp_stats *res,
+	 t;
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
-	struct inl_ppp *inl_ppp = lp->inl_priv;
-	struct slcompress *slcomp;
 	int err;
 
 	res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
@@ -1095,8 +1976,8 @@
 		t.p.ppp_obytes = lp->stats.tx_bytes;
 		t.p.ppp_oerrors = lp->stats.tx_errors;
 #ifdef CONFIG_ISDN_PPP_VJ
-		slcomp = inl_ppp->slcomp;
-		if (slcomp) {
+		if (slot >= 0 && ippp_table[slot]->slcomp) {
+			struct slcompress *slcomp = ippp_table[slot]->slcomp;
 			t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
 			t.vj.vjs_compressed = slcomp->sls_o_compressed;
 			t.vj.vjs_searches = slcomp->sls_o_searches;
@@ -1125,18 +2006,20 @@
 		return -EINVAL;
 
 	switch (cmd) {
-	case SIOCGPPPVER:
-		r = (char *) ifr->ifr_ifru.ifru_data;
-		len = strlen(PPP_VERSION) + 1;
-		if (copy_to_user(r, PPP_VERSION, len))
-			error = -EFAULT;
-		break;
-	case SIOCGPPPSTATS:
-		error = isdn_ppp_dev_ioctl_stats(ifr, dev);
-		break;
-	default:
-		error = -EINVAL;
-		break;
+#define PPP_VERSION "2.3.7"
+		case SIOCGPPPVER:
+			r = (char *) ifr->ifr_ifru.ifru_data;
+			len = strlen(PPP_VERSION) + 1;
+			if (copy_to_user(r, PPP_VERSION, len))
+				error = -EFAULT;
+			break;
+
+		case SIOCGPPPSTATS:
+			error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
+			break;
+		default:
+			error = -EINVAL;
+			break;
 	}
 	return error;
 }
@@ -1167,6 +2050,76 @@
 	return unit;
 }
 
+
+int
+isdn_ppp_dial_slave(char *name)
+{
+#ifdef CONFIG_ISDN_MPP
+	isdn_net_dev *ndev;
+	isdn_net_local *lp;
+	struct net_device *sdev;
+
+	if (!(ndev = isdn_net_findif(name)))
+		return 1;
+	lp = ndev->local;
+	if (!(lp->flags & ISDN_NET_CONNECTED))
+		return 5;
+
+	sdev = lp->slave;
+	while (sdev) {
+		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
+		if (!(mlp->flags & ISDN_NET_CONNECTED))
+			break;
+		sdev = mlp->slave;
+	}
+	if (!sdev)
+		return 2;
+
+	isdn_net_dial_req((isdn_net_local *) sdev->priv);
+	return 0;
+#else
+	return -1;
+#endif
+}
+
+int
+isdn_ppp_hangup_slave(char *name)
+{
+#ifdef CONFIG_ISDN_MPP
+	isdn_net_dev *ndev;
+	isdn_net_local *lp;
+	struct net_device *sdev;
+
+	if (!(ndev = isdn_net_findif(name)))
+		return 1;
+	lp = ndev->local;
+	if (!(lp->flags & ISDN_NET_CONNECTED))
+		return 5;
+
+	sdev = lp->slave;
+	while (sdev) {
+		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
+
+		if (mlp->slave) { /* find last connected link in chain */
+			isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
+
+			if (!(nlp->flags & ISDN_NET_CONNECTED))
+				break;
+		} else if (mlp->flags & ISDN_NET_CONNECTED)
+			break;
+		
+		sdev = mlp->slave;
+	}
+	if (!sdev)
+		return 2;
+
+	isdn_net_hangup(sdev);
+	return 0;
+#else
+	return -1;
+#endif
+}
+
 /*
  * PPP compression stuff
  */
@@ -1175,172 +2128,860 @@
 /* Push an empty CCP Data Frame up to the daemon to wake it up and let it
    generate a CCP Reset-Request or tear down CCP altogether */
 
-static void isdn_ppp_dev_kick_up(void *priv)
+static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
 {
-	isdn_net_dev *idev = priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-
-	ipppd_queue_read(ind_ppp->ipppd, PPP_COMPFRAG, NULL, 0);
+	isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
 }
 
-static void isdn_ppp_lp_kick_up(void *priv)
+/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
+   but absolutely nontrivial. The most abstruse problem we are facing is
+   that the generation, reception and all the handling of timeouts and
+   resends including proper request id management should be entirely left
+   to the (de)compressor, but indeed is not covered by the current API to
+   the (de)compressor. The API is a prototype version from PPP where only
+   some (de)compressors have yet been implemented and all of them are
+   rather simple in their reset handling. Especially, their is only one
+   outstanding ResetAck at a time with all of them and ResetReq/-Acks do
+   not have parameters. For this very special case it was sufficient to
+   just return an error code from the decompressor and have a single
+   reset() entry to communicate all the necessary information between
+   the framework and the (de)compressor. Bad enough, LZS is different
+   (and any other compressor may be different, too). It has multiple
+   histories (eventually) and needs to Reset each of them independently
+   and thus uses multiple outstanding Acks and history numbers as an
+   additional parameter to Reqs/Acks.
+   All that makes it harder to port the reset state engine into the
+   kernel because it is not just the same simple one as in (i)pppd but
+   it must be able to pass additional parameters and have multiple out-
+   standing Acks. We are trying to achieve the impossible by handling
+   reset transactions independent by their id. The id MUST change when
+   the data portion changes, thus any (de)compressor who uses more than
+   one resettable state must provide and recognize individual ids for
+   each individual reset transaction. The framework itself does _only_
+   differentiate them by id, because it has no other semantics like the
+   (de)compressor might.
+   This looks like a major redesign of the interface would be nice,
+   but I don't have an idea how to do it better. */
+
+/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
+   getting that lengthy because there is no simple "send-this-frame-out"
+   function above but every wrapper does a bit different. Hope I guess
+   correct in this hack... */
+
+static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
+				    unsigned char code, unsigned char id,
+				    unsigned char *data, int len)
 {
-	isdn_net_local *lp = priv;
-	isdn_net_dev *idev;
-	struct ind_ppp *ind_ppp;
-
-	if (list_empty(&lp->online)) {
-		isdn_BUG();
+	struct sk_buff *skb;
+	unsigned char *p;
+	int hl;
+	int cnt = 0;
+	isdn_net_local *lp = is->lp;
+
+	/* Alloc large enough skb */
+	hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+	skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
+	if(!skb) {
+		printk(KERN_WARNING
+		       "ippp: CCP cannot send reset - out of memory\n");
 		return;
 	}
-	idev = list_entry(lp->online.next, isdn_net_dev, online);
-	ind_ppp = idev->ind_priv;
-	ipppd_queue_read(ind_ppp->ipppd, PPP_COMP, NULL, 0);
-}
+	skb_reserve(skb, hl);
 
-/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */
+	/* We may need to stuff an address and control field first */
+	if(!(is->pppcfg & SC_COMP_AC)) {
+		p = skb_put(skb, 2);
+		*p++ = 0xff;
+		*p++ = 0x03;
+	}
+
+	/* Stuff proto, code, id and length */
+	p = skb_put(skb, 6);
+	*p++ = (proto >> 8);
+	*p++ = (proto & 0xff);
+	*p++ = code;
+	*p++ = id;
+	cnt = 4 + len;
+	*p++ = (cnt >> 8);
+	*p++ = (cnt & 0xff);
+
+	/* Now stuff remaining bytes */
+	if(len) {
+		p = skb_put(skb, len);
+		memcpy(p, data, len);
+	}
+
+	/* skb is now ready for xmit */
+	printk(KERN_DEBUG "Sending CCP Frame:\n");
+	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+	isdn_net_write_super(lp, skb);
+}
+
+/* Allocate the reset state vector */
+static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
+{
+	struct ippp_ccp_reset *r;
+	r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
+	if(!r) {
+		printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
+		       " structure - no mem\n");
+		return NULL;
+	}
+	memset(r, 0, sizeof(struct ippp_ccp_reset));
+	printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
+	is->reset = r;
+	return r;
+}
 
-static struct sk_buff *
-__isdn_ppp_alloc_skb(isdn_net_dev *idev, int len, unsigned int gfp_mask)
+/* Destroy the reset state vector. Kill all pending timers first. */
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
 {
-	int hl = IPPP_MAX_HEADER + isdn_slot_hdrlen(idev->isdn_slot); 
-	struct sk_buff *skb;
+	unsigned int id;
 
-	skb = alloc_skb(hl + len, gfp_mask);
-	if (!skb)
-		return NULL;
+	printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
+	       is->reset);
+	for(id = 0; id < 256; id++) {
+		if(is->reset->rs[id]) {
+			isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
+		}
+	}
+	kfree(is->reset);
+	is->reset = NULL;
+}
 
-	skb_reserve(skb, hl);
-	return skb;
+/* Free a given state and clear everything up for later reallocation */
+static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
+					  unsigned char id)
+{
+	struct ippp_ccp_reset_state *rs;
+
+	if(is->reset->rs[id]) {
+		printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
+		rs = is->reset->rs[id];
+		/* Make sure the kernel will not call back later */
+		if(rs->ta)
+			del_timer(&rs->timer);
+		is->reset->rs[id] = NULL;
+		kfree(rs);
+	} else {
+		printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
+	}
 }
 
-struct sk_buff *
-isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask)
+/* The timer callback function which is called when a ResetReq has timed out,
+   aka has never been answered by a ResetAck */
+static void isdn_ppp_ccp_timer_callback(unsigned long closure)
 {
-	isdn_net_dev *idev = priv;
+	struct ippp_ccp_reset_state *rs =
+		(struct ippp_ccp_reset_state *)closure;
 
-	return __isdn_ppp_alloc_skb(idev, len, gfp_mask);
+	if(!rs) {
+		printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
+		return;
+	}
+	if(rs->ta && rs->state == CCPResetSentReq) {
+		/* We are correct here */
+		if(!rs->expra) {
+			/* Hmm, there is no Ack really expected. We can clean
+			   up the state now, it will be reallocated if the
+			   decompressor insists on another reset */
+			rs->ta = 0;
+			isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
+			return;
+		}
+		printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
+		       rs->id);
+		/* Push it again */
+		isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
+					rs->data, rs->dlen);
+		/* Restart timer */
+		rs->timer.expires = jiffies + HZ*5;
+		add_timer(&rs->timer);
+	} else {
+		printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
+		       rs->state);
+	}
 }
 
-static struct sk_buff *
-isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask)
+/* Allocate a new reset transaction state */
+static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
+						      unsigned char id)
 {
-	isdn_net_local *lp = priv;
-	isdn_net_dev *idev;
-
-	if (list_empty(&lp->online)) {
-		isdn_BUG();
+	struct ippp_ccp_reset_state *rs;
+	if(is->reset->rs[id]) {
+		printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
+		       id);
 		return NULL;
+	} else {
+		rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+		if(!rs)
+			return NULL;
+		memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
+		rs->state = CCPResetIdle;
+		rs->is = is;
+		rs->id = id;
+		rs->timer.data = (unsigned long)rs;
+		rs->timer.function = isdn_ppp_ccp_timer_callback;
+		is->reset->rs[id] = rs;
+	}
+	return rs;
+}
+
+
+/* A decompressor wants a reset with a set of parameters - do what is
+   necessary to fulfill it */
+static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
+				     struct isdn_ppp_resetparams *rp)
+{
+	struct ippp_ccp_reset_state *rs;
+
+	if(rp->valid) {
+		/* The decompressor defines parameters by itself */
+		if(rp->rsend) {
+			/* And he wants us to send a request */
+			if(!(rp->idval)) {
+				printk(KERN_ERR "ippp_ccp: decompressor must"
+				       " specify reset id\n");
+				return;
+			}
+			if(is->reset->rs[rp->id]) {
+				/* There is already a transaction in existence
+				   for this id. May be still waiting for a
+				   Ack or may be wrong. */
+				rs = is->reset->rs[rp->id];
+				if(rs->state == CCPResetSentReq && rs->ta) {
+					printk(KERN_DEBUG "ippp_ccp: reset"
+					       " trans still in progress"
+					       " for id %d\n", rp->id);
+				} else {
+					printk(KERN_WARNING "ippp_ccp: reset"
+					       " trans in wrong state %d for"
+					       " id %d\n", rs->state, rp->id);
+				}
+			} else {
+				/* Ok, this is a new transaction */
+				printk(KERN_DEBUG "ippp_ccp: new trans for id"
+				       " %d to be started\n", rp->id);
+				rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
+				if(!rs) {
+					printk(KERN_ERR "ippp_ccp: out of mem"
+					       " allocing ccp trans\n");
+					return;
+				}
+				rs->state = CCPResetSentReq;
+				rs->expra = rp->expra;
+				if(rp->dtval) {
+					rs->dlen = rp->dlen;
+					memcpy(rs->data, rp->data, rp->dlen);
+				}
+				/* HACK TODO - add link comp here */
+				isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
+							CCP_RESETREQ, rs->id,
+							rs->data, rs->dlen);
+				/* Start the timer */
+				rs->timer.expires = jiffies + 5*HZ;
+				add_timer(&rs->timer);
+				rs->ta = 1;
+			}
+		} else {
+			printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
+		}
+	} else {
+		/* The reset params are invalid. The decompressor does not
+		   care about them, so we just send the minimal requests
+		   and increase ids only when an Ack is received for a
+		   given id */
+		if(is->reset->rs[is->reset->lastid]) {
+			/* There is already a transaction in existence
+			   for this id. May be still waiting for a
+			   Ack or may be wrong. */
+			rs = is->reset->rs[is->reset->lastid];
+			if(rs->state == CCPResetSentReq && rs->ta) {
+				printk(KERN_DEBUG "ippp_ccp: reset"
+				       " trans still in progress"
+				       " for id %d\n", rp->id);
+			} else {
+				printk(KERN_WARNING "ippp_ccp: reset"
+				       " trans in wrong state %d for"
+				       " id %d\n", rs->state, rp->id);
+			}
+		} else {
+			printk(KERN_DEBUG "ippp_ccp: new trans for id"
+			       " %d to be started\n", is->reset->lastid);
+			rs = isdn_ppp_ccp_reset_alloc_state(is,
+							    is->reset->lastid);
+			if(!rs) {
+				printk(KERN_ERR "ippp_ccp: out of mem"
+				       " allocing ccp trans\n");
+				return;
+			}
+			rs->state = CCPResetSentReq;
+			/* We always expect an Ack if the decompressor doesn't
+			   know	better */
+			rs->expra = 1;
+			rs->dlen = 0;
+			/* HACK TODO - add link comp here */
+			isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
+						rs->id, NULL, 0);
+			/* Start the timer */
+			rs->timer.expires = jiffies + 5*HZ;
+			add_timer(&rs->timer);
+			rs->ta = 1;
+		}
 	}
-	idev = list_entry(lp->online.next, isdn_net_dev, online);
-	return __isdn_ppp_alloc_skb(idev, len, gfp_mask);
 }
 
-static void
-isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto)
-{
-	isdn_net_dev *idev = priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
+/* An Ack was received for this id. This means we stop the timer and clean
+   up the state prior to calling the decompressors reset routine. */
+static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
+					unsigned char id)
+{
+	struct ippp_ccp_reset_state *rs = is->reset->rs[id];
+
+	if(rs) {
+		if(rs->ta && rs->state == CCPResetSentReq) {
+			/* Great, we are correct */
+			if(!rs->expra)
+				printk(KERN_DEBUG "ippp_ccp: ResetAck received"
+				       " for id %d but not expected\n", id);
+		} else {
+			printk(KERN_INFO "ippp_ccp: ResetAck received out of"
+			       "sync for id %d\n", id);
+		}
+		if(rs->ta) {
+			rs->ta = 0;
+			del_timer(&rs->timer);
+		}
+		isdn_ppp_ccp_reset_free_state(is, id);
+	} else {
+		printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
+		       " %d\n", id);
+	}
+	/* Make sure the simple reset stuff uses a new id next time */
+	is->reset->lastid++;
+}
+
+/* 
+ * decompress packet
+ *
+ * if master = 0, we're trying to uncompress an per-link compressed packet,
+ * as opposed to an compressed reconstructed-from-MPPP packet.
+ * proto is updated to protocol field of uncompressed packet.
+ *
+ * retval: decompressed packet,
+ *         same packet if uncompressed,
+ *	   NULL if decompression error
+ */
 
-	ippp_push_proto(ind_ppp, skb, proto);
-	ippp_push_ac(ind_ppp, skb);
-	isdn_net_write_super(idev, skb);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
+	int *proto)
+{
+	void *stat = NULL;
+	struct isdn_ppp_compressor *ipc = NULL;
+	struct sk_buff *skb_out;
+	int len;
+	struct ippp_struct *ri;
+	struct isdn_ppp_resetparams rsparm;
+	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
+
+	if(!master) {
+		// per-link decompression 
+		stat = is->link_decomp_stat;
+		ipc = is->link_decompressor;
+		ri = is;
+	} else {
+		stat = master->decomp_stat;
+		ipc = master->decompressor;
+		ri = master;
+	}
+
+	if (!ipc) {
+		// no decompressor -> we can't decompress.
+		printk(KERN_DEBUG "ippp: no decompressor defined!\n");
+		return skb;
+	}
+	if (!stat) // if we have a compressor, stat has been set as well
+		BUG();
+
+	if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
+		// compressed packets are compressed by their protocol type
+
+		// Set up reset params for the decompressor
+  		memset(&rsparm, 0, sizeof(rsparm));
+  		rsparm.data = rsdata;
+  		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+  
+  		skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
+		len = ipc->decompress(stat, skb, skb_out, &rsparm);
+		kfree_skb(skb);
+		if (len <= 0) {
+			switch(len) {
+			case DECOMP_ERROR:
+				printk(KERN_INFO "ippp: decomp wants reset %s params\n",
+				       rsparm.valid ? "with" : "without");
+				
+				isdn_ppp_ccp_reset_trans(ri, &rsparm);
+				break;
+			case DECOMP_FATALERROR:
+				ri->pppcfg |= SC_DC_FERROR;
+				/* Kick ipppd to recognize the error */
+				isdn_ppp_ccp_kickup(ri);
+				break;
+			}
+			kfree_skb(skb_out);
+			return NULL;
+		}
+		*proto = isdn_ppp_strip_proto(skb_out);
+		if (*proto < 0) {
+			kfree_skb(skb_out);
+			return NULL;
+		}
+		return skb_out;
+	} else { 
+		// uncompressed packets are fed through the decompressor to
+		// update the decompressor state
+		ipc->incomp(stat, skb, *proto);
+		return skb;
+	}
 }
 
-static void
-isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb, u16 proto)
+/*
+ * compress a frame 
+ *   type=0: normal/bundle compression
+ *       =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type)
 {
-	isdn_net_local *lp = priv;
-	isdn_net_dev *idev;
-	struct ind_ppp *ind_ppp;
+    int ret;
+    int new_proto;
+    struct isdn_ppp_compressor *compressor;
+    void *stat;
+    struct sk_buff *skb_out;
+
+	/* we do not compress control protocols */
+    if(*proto < 0 || *proto > 0x3fff) {
+	    return skb_in;
+    }
+
+	if(type) { /* type=1 => Link compression */
+		return skb_in;
+	}
+	else {
+		if(!master) {
+			compressor = is->compressor;
+			stat = is->comp_stat;
+		}
+		else {
+			compressor = master->compressor;
+			stat = master->comp_stat;
+		}
+		new_proto = PPP_COMP;
+	}
 
-	if (list_empty(&lp->online)) {
-		isdn_BUG();
-		return;
+	if(!compressor) {
+		printk(KERN_ERR "isdn_ppp: No compressor set!\n");
+		return skb_in;
+	}
+	if(!stat) {
+		printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
+		return skb_in;
 	}
-	idev = list_entry(lp->online.next, isdn_net_dev, online);
-	ind_ppp = idev->ind_priv;
-	ippp_push_proto(ind_ppp, skb, proto);
-	ippp_push_ac(ind_ppp, skb);
-	isdn_net_write_super(idev, skb);
+
+	/* Allow for at least 150 % expansion (for now) */
+	skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 +
+		skb_headroom(skb_in), GFP_ATOMIC);
+	if(!skb_out)
+		return skb_in;
+	skb_reserve(skb_out, skb_headroom(skb_in));
+
+	ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+	if(!ret) {
+		dev_kfree_skb(skb_out);
+		return skb_in;
+	}
+	
+	dev_kfree_skb(skb_in);
+	*proto = new_proto;
+	return skb_out;
 }
 
-static int
-isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data)
+/*
+ * we received a CCP frame .. 
+ * not a clean solution, but we MUST handle a few cases in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+	 struct sk_buff *skb,int proto)
 {
-	struct ippp_ccp *ccp;
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
+	struct ippp_struct *is;
+	struct ippp_struct *mis;
+	int len;
+	struct isdn_ppp_resetparams rsparm;
+	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
 
-	if (data->flags & IPPP_COMP_FLAG_LINK)
-		ccp = ind_ppp->ccp;
-	else
-		ccp = inl_ppp->ccp;
+	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
+		lp->ppp_slot);
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+			__FUNCTION__, lp->ppp_slot);
+		return;
+	}
+	is = ippp_table[lp->ppp_slot];
+	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+	if(lp->master) {
+		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR "%s: slot(%d) out of range\n",
+				__FUNCTION__, slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
+		mis = is;
+
+	switch(skb->data[0]) {
+	case CCP_CONFREQ:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable compression here!\n");
+		if(proto == PPP_CCP)
+			mis->compflags &= ~SC_COMP_ON;		
+		else
+			is->compflags &= ~SC_LINK_COMP_ON;		
+		break;
+	case CCP_TERMREQ:
+	case CCP_TERMACK:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable (de)compression here!\n");
+		if(proto == PPP_CCP)
+			mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);		
+		else
+			is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);		
+		break;
+	case CCP_CONFACK:
+		/* if we RECEIVE an ackowledge we enable the decompressor */
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Enable decompression here!\n");
+		if(proto == PPP_CCP) {
+			if (!mis->decompressor)
+				break;
+			mis->compflags |= SC_DECOMP_ON;
+		} else {
+			if (!is->decompressor)
+				break;
+			is->compflags |= SC_LINK_DECOMP_ON;
+		}
+		break;
+
+	case CCP_RESETACK:
+		printk(KERN_DEBUG "Received ResetAck from peer\n");
+		len = (skb->data[2] << 8) | skb->data[3];
+		len -= 4;
+
+		if(proto == PPP_CCP) {
+			/* If a reset Ack was outstanding for this id, then
+			   clean up the state engine */
+			isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
+			if(mis->decompressor && mis->decomp_stat)
+				mis->decompressor->
+					reset(mis->decomp_stat,
+					      skb->data[0],
+					      skb->data[1],
+					      len ? &skb->data[4] : NULL,
+					      len, NULL);
+			/* TODO: This is not easy to decide here */
+			mis->compflags &= ~SC_DECOMP_DISCARD;
+		}
+		else {
+			isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
+			if(is->link_decompressor && is->link_decomp_stat)
+				is->link_decompressor->
+					reset(is->link_decomp_stat,
+					      skb->data[0],
+					      skb->data[1],
+					      len ? &skb->data[4] : NULL,
+					      len, NULL);
+			/* TODO: neither here */
+			is->compflags &= ~SC_LINK_DECOMP_DISCARD;
+		}
+		break;
 
-	return ippp_ccp_set_compressor(ccp, ind_ppp->ipppd->unit, data);
+	case CCP_RESETREQ:
+		printk(KERN_DEBUG "Received ResetReq from peer\n");
+		/* Receiving a ResetReq means we must reset our compressor */
+		/* Set up reset params for the reset entry */
+		memset(&rsparm, 0, sizeof(rsparm));
+		rsparm.data = rsdata;
+		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; 
+		/* Isolate data length */
+		len = (skb->data[2] << 8) | skb->data[3];
+		len -= 4;
+		if(proto == PPP_CCP) {
+			if(mis->compressor && mis->comp_stat)
+				mis->compressor->
+					reset(mis->comp_stat,
+					      skb->data[0],
+					      skb->data[1],
+					      len ? &skb->data[4] : NULL,
+					      len, &rsparm);
+		}
+		else {
+			if(is->link_compressor && is->link_comp_stat)
+				is->link_compressor->
+					reset(is->link_comp_stat,
+					      skb->data[0],
+					      skb->data[1],
+					      len ? &skb->data[4] : NULL,
+					      len, &rsparm);
+		}
+		/* Ack the Req as specified by rsparm */
+		if(rsparm.valid) {
+			/* Compressor reset handler decided how to answer */
+			if(rsparm.rsend) {
+				/* We should send a Frame */
+				isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
+							rsparm.idval ? rsparm.id
+							: skb->data[1],
+							rsparm.dtval ?
+							rsparm.data : NULL,
+							rsparm.dtval ?
+							rsparm.dlen : 0);
+			} else {
+				printk(KERN_DEBUG "ResetAck suppressed\n");
+			}
+		} else {
+			/* We answer with a straight reflected Ack */
+			isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
+						skb->data[1],
+						len ? &skb->data[4] : NULL,
+						len);
+		}
+		break;
+	}
 }
 
-// ISDN_NET_ENCAP_SYNCPPP
-// ======================================================================
 
-static int
-isdn_ppp_open(isdn_net_local *lp)
+/*
+ * Daemon sends a CCP frame ...
+ */
+
+/* TODO: Clean this up with new Reset semantics */
+
+/* I believe the CCP handling as-is is done wrong. Compressed frames
+ * should only be sent/received after CCP reaches UP state, which means
+ * both sides have sent CONF_ACK. Currently, we handle both directions
+ * independently, which means we may accept compressed frames too early
+ * (supposedly not a problem), but may also mean we send compressed frames
+ * too early, which may turn out to be a problem.
+ * This part of state machine should actually be handled by (i)pppd, but
+ * that's too big of a change now. --kai
+ */
+
+/* Actually, we might turn this into an advantage: deal with the RFC in
+ * the old tradition of beeing generous on what we accept, but beeing
+ * strict on what we send. Thus we should just
+ * - accept compressed frames as soon as decompression is negotiated
+ * - send compressed frames only when decomp *and* comp are negotiated
+ * - drop rx compressed frames if we cannot decomp (instead of pushing them
+ *   up to ipppd)
+ * and I tried to modify this file according to that. --abp
+ */
+
+static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
-	struct inl_ppp *inl_ppp;
+	struct ippp_struct *mis,*is;
+	int proto, slot = lp->ppp_slot;
+	unsigned char *data;
 
-	inl_ppp = kmalloc(sizeof(*inl_ppp), GFP_KERNEL);
-	if (!inl_ppp)
-		return -ENOMEM;
+	if(!skb || skb->len < 3)
+		return;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+			__FUNCTION__, slot);
+		return;
+	}	
+	is = ippp_table[slot];
+	/* Daemon may send with or without address and control field comp */
+	data = skb->data;
+	if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
+		data += 2;
+		if(skb->len < 5)
+			return;
+	}
+
+	proto = ((int)data[0]<<8)+data[1];
+	if(proto != PPP_CCP && proto != PPP_CCPFRAG)
+		return;
 
-	lp->inl_priv = inl_ppp;
+	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
+	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-	inl_ppp->slcomp = ippp_vj_alloc();
-	if (!inl_ppp->slcomp)
-		goto err;
-
-	inl_ppp->ccp = ippp_ccp_alloc();
-	if (!inl_ppp->ccp)
-		goto err_vj;
-
-	inl_ppp->ccp->proto       = PPP_COMP;
-	inl_ppp->ccp->priv        = lp;
-	inl_ppp->ccp->alloc_skb   = isdn_ppp_lp_alloc_skb;
-	inl_ppp->ccp->xmit        = isdn_ppp_lp_xmit;
-	inl_ppp->ccp->kick_up     = isdn_ppp_lp_kick_up;
+	if (lp->master) {
+		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR "%s: slot(%d) out of range\n",
+				__FUNCTION__, slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
+		mis = is;
+	if (mis != is)
+		printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
 	
-	return 0;
-
- err_vj:
-	ippp_vj_free(inl_ppp->slcomp);
- err:
-	kfree(inl_ppp);
-	lp->inl_priv = NULL;
-	return -ENOMEM;
+        switch(data[2]) {
+	case CCP_CONFREQ:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable decompression here!\n");
+		if(proto == PPP_CCP)
+			is->compflags &= ~SC_DECOMP_ON;
+		else
+			is->compflags &= ~SC_LINK_DECOMP_ON;
+		break;
+	case CCP_TERMREQ:
+	case CCP_TERMACK:
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Disable (de)compression here!\n");
+		if(proto == PPP_CCP)
+			is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);
+		else
+			is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);
+		break;
+	case CCP_CONFACK:
+		/* if we SEND an ackowledge we can/must enable the compressor */
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Enable compression here!\n");
+		if(proto == PPP_CCP) {
+			if (!is->compressor)
+				break;
+			is->compflags |= SC_COMP_ON;
+		} else {
+			if (!is->compressor)
+				break;
+			is->compflags |= SC_LINK_COMP_ON;
+		}
+		break;
+	case CCP_RESETACK:
+		/* If we send a ACK we should reset our compressor */
+		if(is->debug & 0x10)
+			printk(KERN_DEBUG "Reset decompression state here!\n");
+		printk(KERN_DEBUG "ResetAck from daemon passed by\n");
+		if(proto == PPP_CCP) {
+			/* link to master? */
+			if(is->compressor && is->comp_stat)
+				is->compressor->reset(is->comp_stat, 0, 0,
+						      NULL, 0, NULL);
+			is->compflags &= ~SC_COMP_DISCARD;	
+		}
+		else {
+			if(is->link_compressor && is->link_comp_stat)
+				is->link_compressor->reset(is->link_comp_stat,
+							   0, 0, NULL, 0, NULL);
+			is->compflags &= ~SC_LINK_COMP_DISCARD;	
+		}
+		break;
+	case CCP_RESETREQ:
+		/* Just let it pass by */
+		printk(KERN_DEBUG "ResetReq from daemon passed by\n");
+		break;
+	}
 }
 
-static void
-isdn_ppp_close(isdn_net_local *lp)
+int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
-	struct inl_ppp *inl_ppp = lp->inl_priv;
-	
-	ippp_ccp_free(inl_ppp->ccp);
-	ippp_vj_free(inl_ppp->slcomp);
+	ipc->next = ipc_head;
+	ipc->prev = NULL;
+	if(ipc_head) {
+		ipc_head->prev = ipc;
+	}
+	ipc_head = ipc;
+	return 0;
+}
 
-	kfree(inl_ppp);
-	lp->inl_priv = NULL;
+int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
+{
+	if(ipc->prev)
+		ipc->prev->next = ipc->next;
+	else
+		ipc_head = ipc->next;
+	if(ipc->next)
+		ipc->next->prev = ipc->prev;
+	ipc->prev = ipc->next = NULL;
+	return 0;
 }
 
-struct isdn_netif_ops isdn_ppp_ops = {
-	.hard_start_xmit     = isdn_ppp_start_xmit,
-	.do_ioctl            = isdn_ppp_dev_ioctl,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_PPP,
-	.receive             = isdn_ppp_receive,
-	.connected           = isdn_ppp_connected,
-	.disconnected        = isdn_ppp_disconnected,
-	.bind                = isdn_ppp_bind,
-	.unbind              = isdn_ppp_unbind,
-	.open                = isdn_ppp_open,
-	.close               = isdn_ppp_close,
-};
+static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
+{
+	struct isdn_ppp_compressor *ipc = ipc_head;
+	int ret;
+	void *stat;
+	int num = data->num;
+
+	if(is->debug & 0x10)
+		printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit,
+			(data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num);
+
+	/* If is has no valid reset state vector, we cannot allocate a
+	   decompressor. The decompressor would cause reset transactions
+	   sooner or later, and they need that vector. */
+
+	if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
+		printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
+		       " allow decompression.\n");
+		return -ENOMEM;
+	}
+
+	while(ipc) {
+		if(ipc->num == num) {
+			stat = ipc->alloc(data);
+			if(stat) {
+				ret = ipc->init(stat,data,is->unit,0);
+				if(!ret) {
+					printk(KERN_ERR "Can't init (de)compression!\n");
+					ipc->free(stat);
+					stat = NULL;
+					break;
+				}
+			}
+			else {
+				printk(KERN_ERR "Can't alloc (de)compression!\n");
+				break;
+			}
 
+                        if(data->flags & IPPP_COMP_FLAG_XMIT) {
+				if(data->flags & IPPP_COMP_FLAG_LINK) {
+					if(is->link_comp_stat)
+						is->link_compressor->free(is->link_comp_stat);
+					is->link_comp_stat = stat;
+                                	is->link_compressor = ipc;
+				}
+				else {
+					if(is->comp_stat)
+						is->compressor->free(is->comp_stat);
+					is->comp_stat = stat;
+                                	is->compressor = ipc;
+				}
+			}
+                        else {
+				if(data->flags & IPPP_COMP_FLAG_LINK) {
+					if(is->link_decomp_stat)
+						is->link_decompressor->free(is->link_decomp_stat);
+					is->link_decomp_stat = stat;
+        	                        is->link_decompressor = ipc;
+				}
+				else {
+					if(is->decomp_stat)
+						is->decompressor->free(is->decomp_stat);
+					is->decomp_stat = stat;
+        	                        is->decompressor = ipc;
+				}
+			}
+			return 0;
+		}
+		ipc = ipc->next;
+	}
+	return -EINVAL;
+}
--- diff/drivers/isdn/i4l/isdn_ppp.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ppp.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,57 +1,43 @@
-/* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
-#include "isdn_net_lib.h"
-
-extern struct file_operations isdn_ppp_fops;
-extern struct isdn_netif_ops isdn_ppp_ops;
+#include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
+#include <linux/isdn_ppp.h>	/* for isdn_ppp info */
 
-int isdn_ppp_init(void);
-void isdn_ppp_cleanup(void);
-int isdn_ppp_dial_slave(char *);
-int isdn_ppp_hangup_slave(char *);
-
-struct inl_ppp {
-	unsigned long debug;
-	struct slcompress *slcomp;
-	struct ippp_ccp *ccp;         /* CCP for this channel */
-	unsigned int mp_cfg;
-	struct sk_buff_head mp_frags; /* fragments list */
-	u32 mp_rxseq;                 /* last processed packet seq # */
-	u32 mp_txseq;                 /* current tx seq # */
-};
-
-struct ind_ppp {
-	struct ipppd *ipppd;          /* /dev/ipppX which controls us */
-	unsigned int pppcfg;
-	unsigned long debug;
-	struct ippp_ccp *ccp;         /* CCP for this channel (multilink) */
-	u32 mp_rxseq;                 /* last seq no seen on this channel */
-};
-
-void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, 
-		   int unit, int slot);
-
-int
-isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto);
-
-void
-ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto);
+extern int isdn_ppp_read(int, struct file *, char *, int);
+extern int isdn_ppp_write(int, struct file *, const char *, int);
+extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_init(void);
+extern void isdn_ppp_cleanup(void);
+extern int isdn_ppp_free(isdn_net_local *);
+extern int isdn_ppp_bind(isdn_net_local *);
+extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
+extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
+extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
+extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
+extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
+extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
+extern void isdn_ppp_release(int, struct file *);
+extern int isdn_ppp_dial_slave(char *);
+extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
+
+extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
+extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
+
+#define IPPP_OPEN	0x01
+#define IPPP_CONNECT	0x02
+#define IPPP_CLOSEWAIT	0x04
+#define IPPP_NOBLOCK	0x08
+#define IPPP_ASSIGNED	0x10
 
-void
-ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb);
-
-void
-ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto);
+#define IPPP_MAX_HEADER 10
 
-struct sk_buff *
-isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask);
 
-#define IPPP_MAX_HEADER 10
--- diff/drivers/isdn/i4l/isdn_tty.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_tty.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,20 +1,17 @@
-/* Linux ISDN subsystem, tty functions and AT-command emulator
+/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
+ *
+ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
+#undef ISDN_TTY_STAT_DEBUG
 
-#define ISDN_TTY_STAT_DEBUG
-#define ISDN_DEBUG_MODEM_HUP
-#define ISDN_DEBUG_MODEM_VOICE
-#define ISDN_DEBUG_MODEM_OPEN
-#define ISDN_DEBUG_MODEM_IOCTL
-#define ISDN_DEBUG_MODEM_ICALL
-
-#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/isdn.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
@@ -24,51 +21,33 @@
 #define VBUFX (VBUF/16)
 #endif
 
-#define RING_TIMEOUT     (5*HZ)  /* repeat RING every 5 secs */
 #define FIX_FILE_TRANSFER
 #define	DUMMY_HAYES_AT
 
 /* Prototypes */
 
-static void isdn_tty_modem_xmit(struct modem_info *info);
 static int isdn_tty_edit_at(const char *, int, modem_info *, int);
-static void isdn_tty_escape_timer(unsigned long data);
-static void isdn_tty_ring_timer(unsigned long data);
-static void isdn_tty_connect_timer(unsigned long data);
-static void isdn_tty_check_esc(struct modem_info *info, 
-			       const unsigned char *p, int count);
+static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *, int);
 static void isdn_tty_modem_reset_regs(modem_info *, int);
 static void isdn_tty_cmd_ATA(modem_info *);
 static void isdn_tty_flush_buffer(struct tty_struct *);
 static void isdn_tty_modem_result(int, modem_info *);
-static int isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c);
-static int isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb);
 #ifdef CONFIG_ISDN_AUDIO
 static int isdn_tty_countDLE(unsigned char *, int);
 #endif
 
-static int
-isdn_tty_event_callback(struct isdn_slot *slot, int pr, void *arg)
-{
-	switch (pr) {
-	case EV_DATA_IND:
-		return isdn_tty_rcv_skb(slot, arg);
-	default:
-		return isdn_tty_stat_callback(slot, arg);
-	}
-}
-
 /* Leave this unchanged unless you know what you do! */
 #define MODEM_PARANOIA_CHECK
 #define MODEM_DO_RESTART
 
-struct isdn_modem isdn_mdm;
-
 static int bit2si[8] =
 {1, 5, 7, 7, 7, 7, 7, 7};
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
+char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
+
+
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. This
  * is done to speed up tty-receiving if the receive-queue is empty.
@@ -124,166 +103,78 @@
 	return 0;
 }
 
-/*
- * isdn_slot_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- */
-static int
-isdn_tty_readbchan(struct modem_info *info, u_char * buf, u_char * fp, int len)
-{
-	int count;
-	u_int count_pull;
-	int count_put;
-	int dflag;
-	struct sk_buff *skb;
-	u_char *cp;
-
-	if (skb_queue_empty(&info->rpqueue))
-		return 0;
-
-	if (len > info->rcvcount)
-		len = info->rcvcount;
-	cp = buf;
-	count = 0;
-	while (len) {
-		if (!(skb = skb_peek(&info->rpqueue)))
-			break;
-#ifdef CONFIG_ISDN_AUDIO
-		if (ISDN_AUDIO_SKB_LOCK(skb))
-			break;
-		ISDN_AUDIO_SKB_LOCK(skb) = 1;
-		if (ISDN_AUDIO_SKB_DLECOUNT(skb) || info->DLEflag) {
-			char *p = skb->data;
-
-			dflag = 0;
-			count_pull = count_put = 0;
-			while ((count_pull < skb->len) && (len > 0)) {
-				len--;
-				if (info->DLEflag) {
-					*cp++ = DLE;
-					info->DLEflag = 0;
-				} else {
-					*cp++ = *p;
-					if (*p == DLE) {
-						info->DLEflag = 1;
-						(ISDN_AUDIO_SKB_DLECOUNT(skb))--;
-					}
-					p++;
-					count_pull++;
-				}
-				count_put++;
-			}
-			if (count_pull >= skb->len)
-				dflag = 1;
-		} else {
-#endif
-			/* No DLE's in buff, so simply copy it */
-			dflag = 1;
-			if ((int)(count_pull = skb->len) > len) {
-				count_pull = len;
-				dflag = 0;
-			}
-			count_put = count_pull;
-			memcpy(cp, skb->data, count_put);
-			cp += count_put;
-			len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
-		}
-#endif
-		count += count_put;
-		if (fp) {
-			memset(fp, 0, count_put);
-			fp += count_put;
-		}
-		if (dflag) {
-			/* We got all the data in this buff.
-			 * Now we can dequeue it.
-			 */
-			if (fp)
-				*(fp - 1) = 0xff;
-#ifdef CONFIG_ISDN_AUDIO
-			ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
-			skb = skb_dequeue(&info->rpqueue);
-			dev_kfree_skb(skb);
-		} else {
-			/* Not yet emptied this buff, so it
-			 * must stay in the queue, for further calls
-			 * but we pull off the data we got until now.
-			 */
-			skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
-			ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
-		}
-		info->rcvcount -= count_put;
-	}
-	return count;
-}
-
 /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
  * It tries getting received data from the receive queue an stuff it into
  * the tty's flip-buffer.
  */
-static void
-isdn_tty_readmodem(unsigned long data)
+void
+isdn_tty_readmodem(void)
 {
-	struct modem_info *info = (struct modem_info *) data;
+	int resched = 0;
+	int midx;
+	int i;
 	int c;
 	int r;
-	ulong flags;
 	struct tty_struct *tty;
+	modem_info *info;
 
-	if (!info->online)
-		return;
-
-	r = 0;
-#ifdef CONFIG_ISDN_AUDIO
-	isdn_audio_eval_dtmf(info);
-	if ((info->vonline & 1) && (info->emu.vpar[1]))
-		isdn_audio_eval_silence(info);
-#endif
-	if ((tty = info->tty)) {
-		if (info->mcr & UART_MCR_RTS) {
-			c = TTY_FLIPBUF_SIZE - tty->flip.count;
-			if (c > 0) {
-				save_flags(flags);
-				cli();
-				r = isdn_tty_readbchan(info,
-						       tty->flip.char_buf_ptr,
-						       tty->flip.flag_buf_ptr, c);
-				/* CISCO AsyncPPP Hack */
-				if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
-					memset(tty->flip.flag_buf_ptr, 0, r);
-				tty->flip.count += r;
-				tty->flip.flag_buf_ptr += r;
-				tty->flip.char_buf_ptr += r;
-				if (r)
-					schedule_delayed_work(&tty->flip.work, 1);
-				restore_flags(flags);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		if ((midx = dev->m_idx[i]) >= 0) {
+			info = &dev->mdm.info[midx];
+			if (info->online) {
+				r = 0;
+#ifdef CONFIG_ISDN_AUDIO
+				isdn_audio_eval_dtmf(info);
+				if ((info->vonline & 1) && (info->emu.vpar[1]))
+					isdn_audio_eval_silence(info);
+#endif
+				if ((tty = info->tty)) {
+					if (info->mcr & UART_MCR_RTS) {
+						c = TTY_FLIPBUF_SIZE - tty->flip.count;
+						if (c > 0) {
+							r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
+									   tty->flip.char_buf_ptr,
+									   tty->flip.flag_buf_ptr, c, 0);
+							/* CISCO AsyncPPP Hack */
+							if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+								memset(tty->flip.flag_buf_ptr, 0, r);
+							tty->flip.count += r;
+							tty->flip.flag_buf_ptr += r;
+							tty->flip.char_buf_ptr += r;
+							if (r)
+								schedule_delayed_work(&tty->flip.work, 1);
+						}
+					} else
+						r = 1;
+				} else
+					r = 1;
+				if (r) {
+					info->rcvsched = 0;
+					resched = 1;
+				} else
+					info->rcvsched = 1;
 			}
-		} else
-			r = 1;
-	} else
-		r = 1;
-
-	if (r) {
-		info->rcvsched = 0;
-		mod_timer(&info->read_timer, jiffies + 4);
-	} else
-		info->rcvsched = 1;
+		}
+	}
+	if (!resched)
+		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 }
 
-static int
-isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb)
+int
+isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
 {
 	ulong flags;
+	int midx;
 #ifdef CONFIG_ISDN_AUDIO
 	int ifmt;
 #endif
 	modem_info *info;
 
-	info = slot->priv;
+	if ((midx = dev->m_idx[i]) < 0) {
+		/* if midx is invalid, packet is not for tty */
+		return 0;
+	}
+	info = &dev->mdm.info[midx];
 #ifdef CONFIG_ISDN_AUDIO
 	ifmt = 1;
 	
@@ -315,12 +206,6 @@
 				skb_pull(skb, 4);
 	}
 #ifdef CONFIG_ISDN_AUDIO
-	if ((size_t)skb_headroom(skb) < sizeof(isdnaudio_header)) {
-		printk(KERN_WARNING
-		       "isdn_audio: insufficient skb_headroom, dropping\n");
-		kfree_skb(skb);
-		return 1;
-	}
 	ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
 	ISDN_AUDIO_SKB_LOCK(skb) = 0;
 	if (info->vonline & 1) {
@@ -364,53 +249,49 @@
 #endif
 #endif
 	/* Try to deliver directly via tty-flip-buf if queue is empty */
-	save_flags(flags);
-	cli();
-	if (skb_queue_empty(&info->rpqueue))
+	spin_lock_irqsave(&info->readlock, flags);
+	if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
 		if (isdn_tty_try_read(info, skb)) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&info->readlock, flags);
 			return 1;
 		}
 	/* Direct deliver failed or queue wasn't empty.
 	 * Queue up for later dequeueing via timer-irq.
 	 */
-	isdn_tty_queue_tail(info, skb, skb->len
+	__skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
+	dev->drv[di]->rcvcount[channel] +=
+		(skb->len
 #ifdef CONFIG_ISDN_AUDIO
 		 + ISDN_AUDIO_SKB_DLECOUNT(skb)
 #endif
-			    );
-	restore_flags(flags);
+			);
+	spin_unlock_irqrestore(&info->readlock, flags);
 	/* Schedule dequeuing */
-	if ((get_isdn_dev())->modempoll && info->rcvsched)
-		mod_timer(&info->read_timer, jiffies + 4);
+	if ((dev->modempoll) && (info->rcvsched))
+		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
 	return 1;
 }
 
 void
 isdn_tty_cleanup_xmit(modem_info * info)
 {
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 	skb_queue_purge(&info->xmit_queue);
 #ifdef CONFIG_ISDN_AUDIO
 	skb_queue_purge(&info->dtmf_queue);
 #endif
-	restore_flags(flags);
 }
 
 static void
 isdn_tty_tint(modem_info * info)
 {
 	struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
-	int len,
-	 slen;
+	int len, slen;
 
 	if (!skb)
 		return;
 	len = skb->len;
-	if ((slen = isdn_slot_write(info->isdn_slot, skb)) == len) {
+	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
+					   info->isdn_channel, 1, skb)) == len) {
 		struct tty_struct *tty = info->tty;
 		info->send_outstanding++;
 		info->msr &= ~UART_MSR_CTS;
@@ -573,11 +454,11 @@
 	atomic_inc(&info->xmit_lock);
 	if (!(atomic_dec_and_test(&info->xmit_lock)))
 		return;
-	if (info->isdn_slot < 0) {
+	if (info->isdn_driver < 0) {
 		info->xmit_count = 0;
 		return;
 	}
-	skb_res = isdn_slot_hdrlen(info->isdn_slot);
+	skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
 #ifdef CONFIG_ISDN_AUDIO
 	if (info->vonline & 2)
 		audio_len = buflen * voice_cf[info->emu.vpar[3]];
@@ -677,8 +558,6 @@
 {
 	if (info->ncarrier) {
 		info->nc_timer.expires = jiffies + HZ;
-		info->nc_timer.function = isdn_tty_modem_do_ncarrier;
-		info->nc_timer.data = (unsigned long) info;
 		add_timer(&info->nc_timer);
 	}
 }
@@ -721,8 +600,9 @@
 	int usg = ISDN_USAGE_MODEM;
 	int si = 7;
 	int l2 = m->mdmreg[REG_L2PROT];
-	ulong flags;
-	struct isdn_slot *slot;
+	u_long flags;
+	isdn_ctrl cmd;
+	int i;
 	int j;
 
 	for (j = 7; j >= 0; j--)
@@ -743,39 +623,58 @@
 	}
 #endif
 	m->mdmreg[REG_SI1I] = si2bit[si];
-	save_flags(flags);
-	cli();
-	slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
-	if (!slot) {
-		restore_flags(flags);
+	spin_lock_irqsave(&dev->lock, flags);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+	if (i < 0) {
+		spin_unlock_irqrestore(&dev->lock, flags);
 		isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 	} else {
-		struct dial_info dial = {
-			.l2_proto = l2,
-			.l3_proto = m->mdmreg[REG_L3PROT],
-			.si1      = si,
-			.si2      = m->mdmreg[REG_SI2],
-			.msn      = m->msn,
-			.phone    = n,
-		};
-
-		info->isdn_slot = slot;
-		slot->usage |= ISDN_USAGE_MODEM;
-		slot->priv = info;
-		slot->event_cb = isdn_tty_event_callback;
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		dev->usage[i] |= ISDN_USAGE_OUTGOING;
 		info->last_dir = 1;
-		info->last_l2 = l2;
 		strcpy(info->last_num, n);
-		restore_flags(flags);
+		isdn_info_update();
+		spin_unlock_irqrestore(&dev->lock, flags);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_CLREAZ;
+		isdn_command(&cmd);
+		strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETEAZ;
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
+		info->last_l2 = l2;
+		cmd.arg = info->isdn_channel + (l2 << 8);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
 #ifdef CONFIG_ISDN_TTY_FAX
 		if (l2 == ISDN_PROTO_L2_FAX) {
-			dial.fax = info->fax;
+			cmd.parm.fax = info->fax;
 			info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
 		}
 #endif
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		sprintf(cmd.parm.setup.phone, "%s", n);
+		sprintf(cmd.parm.setup.eazmsn, "%s",
+			isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.parm.setup.si1 = si;
+		cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
+		cmd.command = ISDN_CMD_DIAL;
 		info->dialing = 1;
-		isdn_slot_dial(info->isdn_slot, &dial);
-		mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); 
+		info->emu.carrierwait = 0;
+		strcpy(dev->num[i], n);
+		isdn_info_update();
+		isdn_command(&cmd);
+		isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
 	}
 }
 
@@ -787,15 +686,19 @@
 isdn_tty_modem_hup(modem_info * info, int local)
 {
 	isdn_ctrl cmd;
-	struct isdn_slot *slot;
+	int di, ch;
 
 	if (!info)
 		return;
 
-	slot = info->isdn_slot;
-	if (!slot)
+	di = info->isdn_driver;
+	ch = info->isdn_channel;
+	if (di < 0 || ch < 0)
 		return;
 
+	info->isdn_driver = -1;
+	info->isdn_channel = -1;
+
 #ifdef ISDN_DEBUG_MODEM_HUP
 	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 #endif
@@ -837,15 +740,21 @@
 	info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
 	info->lsr |= UART_LSR_TEMT;
 
-	if (local)
-		isdn_slot_command(slot, ISDN_CMD_HANGUP, &cmd);
+	if (local) {
+		cmd.driver = di;
+		cmd.command = ISDN_CMD_HANGUP;
+		cmd.arg = ch;
+		isdn_command(&cmd);
+	}
 
+	isdn_all_eaz(di, ch);
 	info->emu.mdmreg[REG_RINGCNT] = 0;
-	skb_queue_purge(&info->rpqueue);
-	slot->priv = NULL;
-	slot->event_cb = NULL;
-	isdn_slot_free(slot);
-	info->isdn_slot = NULL;
+	isdn_free_channel(di, ch, 0);
+
+	if (info->drv_index >= 0) {
+		dev->m_idx[info->drv_index] = -1;
+		info->drv_index = -1;
+	}
 }
 
 /*
@@ -875,10 +784,11 @@
 	printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
 #endif
 	l = strlen(id);
-	if ((info->isdn_slot >= 0)) {
+	if ((info->isdn_driver >= 0)) {
 		cmd.parm.cmsg.Length = l+18;
 		cmd.parm.cmsg.Command = CAPI_FACILITY;
 		cmd.parm.cmsg.Subcommand = CAPI_REQ;
+		cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 		cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
 		cmd.parm.cmsg.para[1] = 0;
 		cmd.parm.cmsg.para[2] = l + 3;
@@ -886,7 +796,10 @@
 		cmd.parm.cmsg.para[4] = 0;
 		cmd.parm.cmsg.para[5] = l;
 		strncpy(&cmd.parm.cmsg.para[6], id, l);
-		isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
+		cmd.command = CAPI_PUT_MESSAGE;
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		isdn_command(&cmd);
 	}
 }
 
@@ -905,7 +818,7 @@
 	int l2 = m->mdmreg[REG_L2PROT];
 	isdn_ctrl cmd;
 	ulong flags;
-	struct isdn_slot *slot;
+	int i;
 	int j;
 	int l;
 
@@ -928,28 +841,44 @@
 	}
 #endif
 	m->mdmreg[REG_SI1I] = si2bit[si];
-	save_flags(flags);
-	cli();
-	slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
-	if (!slot) {
-		restore_flags(flags);
+	spin_lock_irqsave(&dev->lock, flags);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+	if (i < 0) {
+		spin_unlock_irqrestore(&dev->lock, flags);
 		isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 	} else {
-		info->isdn_slot = slot;
-		slot->usage |= ISDN_USAGE_MODEM;
-		slot->priv = info;
-		slot->event_cb = isdn_tty_event_callback;
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		dev->usage[i] |= ISDN_USAGE_OUTGOING;
 		info->last_dir = 1;
 //		strcpy(info->last_num, n);
-		restore_flags(flags);
+		isdn_info_update();
+		spin_unlock_irqrestore(&dev->lock, flags);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_CLREAZ;
+		isdn_command(&cmd);
+		strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETEAZ;
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
 		info->last_l2 = l2;
-		cmd.arg = l2 << 8;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
-		cmd.arg = m->mdmreg[REG_L3PROT] << 8;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
+		cmd.arg = info->isdn_channel + (l2 << 8);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
 		cmd.parm.cmsg.Length = l+18;
 		cmd.parm.cmsg.Command = CAPI_FACILITY;
 		cmd.parm.cmsg.Subcommand = CAPI_REQ;
+		cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 		cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
 		cmd.parm.cmsg.para[1] = 0;
 		cmd.parm.cmsg.para[2] = l+3;
@@ -957,11 +886,12 @@
 		cmd.parm.cmsg.para[4] = 0;
 		cmd.parm.cmsg.para[5] = l;
 		strncpy(&cmd.parm.cmsg.para[6], id, l);
+		cmd.command =CAPI_PUT_MESSAGE;
 		info->dialing = 1;
 //		strcpy(dev->num[i], n);
 		isdn_info_update();
-		isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
-		mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); 
+		isdn_command(&cmd);
+		isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
 	}
 }
 
@@ -977,7 +907,7 @@
 	int l2 = m->mdmreg[REG_L2PROT];
 	isdn_ctrl cmd;
 	ulong flags;
-	struct isdn_slot *slot;
+	int i;
 	int j;
 	int l;
 
@@ -1004,45 +934,62 @@
 	}
 #endif
 	m->mdmreg[REG_SI1I] = si2bit[si];
-	save_flags(flags);
-	cli();
-	slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
-	if (!slot) {
-		restore_flags(flags);
+	spin_lock_irqsave(&dev->lock, flags);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+	if (i < 0) {
+		spin_unlock_irqrestore(&dev->lock, flags);
 		isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 	} else {
-		info->isdn_slot = slot;
-		slot->usage |= ISDN_USAGE_MODEM;
-		slot->priv = info;
-		slot->event_cb = isdn_tty_event_callback;
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		dev->usage[i] |= ISDN_USAGE_OUTGOING;
 		info->last_dir = 1;
-		restore_flags(flags);
+		isdn_info_update();
+		spin_unlock_irqrestore(&dev->lock, flags);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_CLREAZ;
+		isdn_command(&cmd);
+		strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETEAZ;
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
 		info->last_l2 = l2;
-		cmd.arg = l2 << 8;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
-		cmd.arg = m->mdmreg[REG_L3PROT] << 8;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
+		cmd.arg = info->isdn_channel + (l2 << 8);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
 		cmd.parm.cmsg.Length = l+14;
 		cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
 		cmd.parm.cmsg.Subcommand = CAPI_REQ;
+		cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 		cmd.parm.cmsg.para[0] = l+1;
 		strncpy(&cmd.parm.cmsg.para[1], msg, l);
 		cmd.parm.cmsg.para[l+1] = 0xd;
+		cmd.command =CAPI_PUT_MESSAGE;
 /*		info->dialing = 1;
 		strcpy(dev->num[i], n);
 		isdn_info_update();
 */
-		isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
+		isdn_command(&cmd);
 	}
 }
 
 static inline int
-isdn_tty_paranoia_check(modem_info * info, char *name, const char *routine)
+isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
 {
 #ifdef MODEM_PARANOIA_CHECK
 	if (!info) {
 		printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
-		       name, routine);
+			name, routine);
 		return 1;
 	}
 	if (info->magic != ISDN_ASYNC_MAGIC) {
@@ -1119,12 +1066,9 @@
 static int
 isdn_tty_startup(modem_info * info)
 {
-	ulong flags;
-
 	if (info->flags & ISDN_ASYNC_INITIALIZED)
 		return 0;
-	save_flags(flags);
-	cli();
+	isdn_lock_drivers();
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
 #endif
@@ -1142,7 +1086,6 @@
 	info->flags |= ISDN_ASYNC_INITIALIZED;
 	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->send_outstanding = 0;
-	restore_flags(flags);
 	return 0;
 }
 
@@ -1153,15 +1096,12 @@
 static void
 isdn_tty_shutdown(modem_info * info)
 {
-	ulong flags;
-
 	if (!(info->flags & ISDN_ASYNC_INITIALIZED))
 		return;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 #endif
-	save_flags(flags);
-	cli();                  /* Disable interrupts */
+	isdn_unlock_drivers();
 	info->msr &= ~UART_MSR_RI;
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
@@ -1177,7 +1117,6 @@
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
 
 	info->flags &= ~ISDN_ASYNC_INITIALIZED;
-	restore_flags(flags);
 }
 
 /* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1207,8 +1146,8 @@
 		c = count;
 		if (c > info->xmit_size - info->xmit_count)
 			c = info->xmit_size - info->xmit_count;
-		if (info->isdn_slot && c > isdn_slot_maxbufsize(info->isdn_slot))
-			c = isdn_slot_maxbufsize(info->isdn_slot);
+		if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
+			c = dev->drv[info->isdn_driver]->maxbufsize;
 		if (c <= 0)
 			break;
 		if ((info->online > 1)
@@ -1216,17 +1155,17 @@
 		    || (info->vonline & 3)
 #endif
 			) {
-			if (from_user) {
-				if (copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c)) {
-					total = -EFAULT;
-					goto out;
-				}
-			} else
-				memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
 #ifdef CONFIG_ISDN_AUDIO
 			if (!info->vonline)
 #endif
-				isdn_tty_check_esc(info, &info->xmit_buf[info->xmit_count], c);
+				isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
+						   &(m->pluscount),
+						   &(m->lastplus),
+						   from_user);
+			if (from_user)
+				copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
+			else
+				memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
 #ifdef CONFIG_ISDN_AUDIO
 			if (info->vonline) {
 				int cc = isdn_tty_handleDLEdown(info, m, c);
@@ -1265,9 +1204,12 @@
 				if (info->vonline & 4) { /* ETX seen */
 					isdn_ctrl c;
 
+					c.command = ISDN_CMD_FAXCMD;
+					c.driver = info->isdn_driver;
+					c.arg = info->isdn_channel;
 					c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
 					c.parm.aux.subcmd = ETX;
-					isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
+					isdn_command(&c);
 				}
 				info->vonline = 0;
 #ifdef ISDN_DEBUG_MODEM_VOICE
@@ -1296,9 +1238,12 @@
 	}
 	atomic_dec(&info->xmit_lock);
 	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
-		isdn_tty_modem_xmit(info);
+		if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
+			isdn_tty_senddown(info);
+			isdn_tty_tint(info);
+		}
+		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 	}
-out:
 	if (from_user)
 		up(&info->write_sem);
 	return total;
@@ -1334,22 +1279,16 @@
 isdn_tty_flush_buffer(struct tty_struct *tty)
 {
 	modem_info *info;
-	unsigned long flags;
 
-	save_flags(flags);
-	cli();
 	if (!tty) {
-		restore_flags(flags);
 		return;
 	}
 	info = (modem_info *) tty->driver_data;
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
-		restore_flags(flags);
 		return;
 	}
 	isdn_tty_cleanup_xmit(info);
 	info->xmit_count = 0;
-	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1364,7 +1303,7 @@
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
 		return;
 	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
-		isdn_tty_modem_xmit(info);
+		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 }
 
 /*
@@ -1424,105 +1363,73 @@
 {
 	u_char status;
 	uint result;
-	ulong flags;
 
-	save_flags(flags);
-	cli();
 	status = info->lsr;
-	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 	return put_user(result, (uint *) value);
 }
 
 
 static int
-isdn_tty_get_modem_info(modem_info * info, uint * value)
+isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
 {
-	u_char control,
-	 status;
-	uint result;
-	ulong flags;
+	modem_info *info = (modem_info *) tty->driver_data;
+	u_char control, status;
+
+	if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+#ifdef ISDN_DEBUG_MODEM_IOCTL
+	printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
+#endif
 
 	control = info->mcr;
-	save_flags(flags);
-	cli();
 	status = info->msr;
-	restore_flags(flags);
-	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 	    | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 	    | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
 	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
 	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
 	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result, (uint *) value);
 }
 
 static int
-isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
+isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
+		unsigned int set, unsigned int clear)
 {
-	uint arg;
-	int pre_dtr;
+	modem_info *info = (modem_info *) tty->driver_data;
+
+	if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
-	if (get_user(arg, (uint *) value))
-		return -EFAULT;
-	switch (cmd) {
-		case TIOCMBIS:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
-#endif
-			if (arg & TIOCM_RTS) {
-				info->mcr |= UART_MCR_RTS;
-			}
-			if (arg & TIOCM_DTR) {
-				info->mcr |= UART_MCR_DTR;
-				isdn_tty_modem_ncarrier(info);
-			}
-			break;
-		case TIOCMBIC:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
-#endif
-			if (arg & TIOCM_RTS) {
-				info->mcr &= ~UART_MCR_RTS;
-			}
-			if (arg & TIOCM_DTR) {
-				info->mcr &= ~UART_MCR_DTR;
-				if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
-					isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
-					printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
-#endif
-					if (info->online)
-						info->ncarrier = 1;
-					isdn_tty_modem_hup(info, 1);
-				}
-			}
-			break;
-		case TIOCMSET:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
+	printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
 #endif
-			pre_dtr = (info->mcr & UART_MCR_DTR);
-			info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
-				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-			       | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-			if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
-				if (!(info->mcr & UART_MCR_DTR)) {
-					if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
-						isdn_tty_modem_reset_regs(info, 0);
+
+	if (set & TIOCM_RTS)
+		info->mcr |= UART_MCR_RTS;
+	if (set & TIOCM_DTR) {
+		info->mcr |= UART_MCR_DTR;
+		isdn_tty_modem_ncarrier(info);
+	}
+
+	if (clear & TIOCM_RTS)
+		info->mcr &= ~UART_MCR_RTS;
+	if (clear & TIOCM_DTR) {
+		info->mcr &= ~UART_MCR_DTR;
+		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
+			isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-						printk(KERN_DEBUG "Mhup in TIOCMSET\n");
+			printk(KERN_DEBUG "Mhup in TIOCMSET\n");
 #endif
-						if (info->online)
-							info->ncarrier = 1;
-						isdn_tty_modem_hup(info, 1);
-					}
-				} else
-					isdn_tty_modem_ncarrier(info);
-			}
-			break;
-		default:
-			return -EINVAL;
+			if (info->online)
+				info->ncarrier = 1;
+			isdn_tty_modem_hup(info, 1);
+		}
 	}
 	return 0;
 }
@@ -1572,15 +1479,6 @@
 			    ((tty->termios->c_cflag & ~CLOCAL) |
 			     (arg ? CLOCAL : 0));
 			return 0;
-		case TIOCMGET:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
-#endif
-			return isdn_tty_get_modem_info(info, (uint *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
 		case TIOCSERGETLSR:	/* Get line status register */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
@@ -1623,7 +1521,6 @@
 {
 	DECLARE_WAITQUEUE(wait, NULL);
 	int do_clocal = 0;
-	unsigned long flags;
 	int retval;
 
 	/*
@@ -1649,11 +1546,18 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
 		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
+	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1667,11 +1571,8 @@
 	printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
 	       info->line, info->count);
 #endif
-	save_flags(flags);
-	cli();
 	if (!(tty_hung_up_p(filp)))
 		info->count--;
-	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1687,7 +1588,8 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ISDN_ASYNC_CLOSING) &&
+		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ISDN_ASYNC_CLOSING) &&
 		    (do_clocal || (info->msr & UART_MSR_DCD))) {
 			break;
 		}
@@ -1728,11 +1630,10 @@
 	modem_info *info;
 	int retval, line;
 
-
 	line = tty->index;
 	if (line < 0 || line > ISDN_MAX_CHANNELS)
 		return -ENODEV;
-	info = &isdn_mdm.info[line];
+	info = &dev->mdm.info[line];
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 		return -ENODEV;
 	if (!try_module_get(info->owner)) {
@@ -1740,7 +1641,7 @@
 		return -ENODEV;
 	}
 #ifdef ISDN_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
+	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, 
 	       info->count);
 #endif
 	info->count++;
@@ -1768,7 +1669,7 @@
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
 #endif
-	(get_isdn_dev())->modempoll++;
+	dev->modempoll++;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open normal exit\n");
 #endif
@@ -1779,23 +1680,15 @@
 isdn_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
-	ulong flags;
 	ulong timeout;
 
-	if (!info)
+	if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
 		return;
-	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
-		goto out;
-
-	#warning need fixing /kkeil
-	save_flags(flags);
-	cli();
 	if (tty_hung_up_p(filp)) {
-		restore_flags(flags);
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
 #endif
-		goto out;
+		return;
 	}
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
@@ -1815,13 +1708,21 @@
 		info->count = 0;
 	}
 	if (info->count) {
-		restore_flags(flags);
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
 #endif
-		goto out;
+		return;
 	}
 	info->flags |= ISDN_ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+
 	tty->closing = 1;
 	/*
 	 * At this point we stop accepting input.  To do this, we
@@ -1830,7 +1731,7 @@
 	 * line status register.
 	 */
 	if (info->flags & ISDN_ASYNC_INITIALIZED) {
-		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
+		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -1844,7 +1745,7 @@
 				break;
 		}
 	}
-	(get_isdn_dev())->modempoll--;
+	dev->modempoll--;
 	isdn_tty_shutdown(info);
 	if (tty->driver->flush_buffer)
 		tty->driver->flush_buffer(tty);
@@ -1853,6 +1754,7 @@
 	info->tty = 0;
 	info->ncarrier = 0;
 	tty->closing = 0;
+	module_put(info->owner);
 	if (info->blocked_open) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/2);
@@ -1860,12 +1762,9 @@
 	}
 	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-	restore_flags(flags);
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_close normal exit\n");
 #endif
- out:
-	module_put(info->owner);
 }
 
 /*
@@ -1880,7 +1779,7 @@
 		return;
 	isdn_tty_shutdown(info);
 	info->count = 0;
-	info->flags &= ~ISDN_ASYNC_NORMAL_ACTIVE;
+	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1988,13 +1887,12 @@
 	memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
 	memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
 	memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
-	if ((get_isdn_dev())->profd)
-		kill_pg_info(SIGIO, SEND_SIG_PRIV,
-			process_group((get_isdn_dev())->profd));
+	if (dev->profd)
+		send_sig(SIGIO, dev->profd, 1);
 }
 
 static struct tty_operations modem_ops = {
-	.open = isdn_tty_open,
+        .open = isdn_tty_open,
 	.close = isdn_tty_close,
 	.write = isdn_tty_write,
 	.flush_chars = isdn_tty_flush_chars,
@@ -2006,16 +1904,18 @@
 	.unthrottle = isdn_tty_unthrottle,
 	.set_termios = isdn_tty_set_termios,
 	.hangup = isdn_tty_hangup,
+	.tiocmget = isdn_tty_tiocmget,
+	.tiocmset = isdn_tty_tiocmset,
 };
 
 int
-isdn_tty_init(void)
+isdn_tty_modem_init(void)
 {
-	struct isdn_modem *m;
-	int i, retval;
-	modem_info *info;
+	isdn_modem_t	*m;
+	int		i, retval;
+	modem_info	*info;
 
-	m = &isdn_mdm;
+	m = &dev->mdm;
 	m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
 	if (!m->tty_modem)
 		return -ENOMEM;
@@ -2027,7 +1927,7 @@
 	m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
 	m->tty_modem->init_termios = tty_std_termios;
 	m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
+	m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
 	m->tty_modem->driver_name = "isdn_tty";
 	tty_set_operations(m->tty_modem, &modem_ops);
 	retval = tty_register_driver(m->tty_modem);
@@ -2040,10 +1940,14 @@
 #ifdef CONFIG_ISDN_TTY_FAX
 		if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
 			printk(KERN_ERR "Could not allocate fax t30-buffer\n");
-			return -3;
+			retval = -ENOMEM;
+			goto err_unregister;
 		}
 #endif
+#ifdef MODULE
 		info->owner = THIS_MODULE;
+#endif
+		spin_lock_init(&info->readlock);
 		init_MUTEX(&info->write_sem);
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_num, "none");
@@ -2061,41 +1965,27 @@
 		info->blocked_open = 0;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		info->isdn_slot = NULL;
-		init_timer(&info->escape_timer);
-		info->escape_timer.data = (unsigned long) info;
-		info->escape_timer.function = isdn_tty_escape_timer;
-		init_timer(&info->ring_timer);
-		info->ring_timer.data = (unsigned long) info;
-		info->ring_timer.function = isdn_tty_ring_timer;
-		init_timer(&info->connect_timer);
-		info->connect_timer.data = (unsigned long) info;
-		info->connect_timer.function = isdn_tty_connect_timer;
-		init_timer(&info->read_timer);
-		info->read_timer.data = (unsigned long) info;
-		info->read_timer.function = isdn_tty_readmodem;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-		skb_queue_head_init(&info->rpqueue);
+		info->isdn_driver = -1;
+		info->isdn_channel = -1;
+		info->drv_index = -1;
 		info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
+		init_timer(&info->nc_timer);
+		info->nc_timer.function = isdn_tty_modem_do_ncarrier;
+		info->nc_timer.data = (unsigned long) info;
 		skb_queue_head_init(&info->xmit_queue);
 #ifdef CONFIG_ISDN_AUDIO
 		skb_queue_head_init(&info->dtmf_queue);
 #endif
-		info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL);
-		if (!info->xmit_buf) {
+		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
 			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
-#ifdef CONFIG_ISDN_TTY_FAX
-			kfree(info->fax);
-#endif
-			goto err_unregister_cua;
+			retval = -ENOMEM;
+			goto err_unregister;
 		}
 		/* Make room for T.70 header */
 		info->xmit_buf += 4;
 	}
 	return 0;
-
- err_unregister_cua:
+err_unregister:
 	for (i--; i >= 0; i--) {
 		info = &m->info[i];
 #ifdef CONFIG_ISDN_TTY_FAX
@@ -2117,19 +2007,19 @@
 	int i;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		info = &isdn_mdm.info[i];
+		info = &dev->mdm.info[i];
 		isdn_tty_cleanup_xmit(info);
-		skb_queue_purge(&info->rpqueue);
 #ifdef CONFIG_ISDN_TTY_FAX
 		kfree(info->fax);
 #endif
 		kfree(info->xmit_buf - 4);
 	}
-	tty_unregister_driver(isdn_mdm.tty_modem);
-	put_tty_driver(isdn_mdm.tty_modem);
-	isdn_mdm.tty_modem = NULL;
+	tty_unregister_driver(dev->mdm.tty_modem);
+	put_tty_driver(dev->mdm.tty_modem);
+	dev->mdm.tty_modem = NULL;
 }
 
+
 /*
  * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
  *      match the MSN against the MSNs (glob patterns) defined for tty_emulator,
@@ -2193,11 +2083,12 @@
  *      CID is longer.
  */
 int
-isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup)
+isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 {
 	char *eaz;
 	int i;
 	int wret;
+	int idx;
 	int si1;
 	int si2;
 	char *nr;
@@ -2219,69 +2110,76 @@
 	printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
 #endif
 	wret = 0;
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&dev->lock, flags);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		modem_info *info = &isdn_mdm.info[i];
+		modem_info *info = &dev->mdm.info[i];
 
                 if (info->count == 0)
                     continue;
 		if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
 		    (info->emu.mdmreg[REG_SI2] == si2))	{         /* SI2 is matching */
+			idx = isdn_dc2minor(di, ch);
 #ifdef ISDN_DEBUG_MODEM_ICALL
 			printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
-			printk(KERN_DEBUG "m_fi: sl=%d flags=%08lx drv=%d ch=%d usg=%d\n", sl,
+			printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
 			       info->flags, info->isdn_driver, info->isdn_channel,
-			       slot->usage);
+			       dev->usage[idx]);
 #endif
 			if (
 #ifndef FIX_FILE_TRANSFER
 				(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
 #endif
-				(!info->isdn_slot)) {
+				(info->isdn_driver == -1) &&
+				(info->isdn_channel == -1) &&
+				(USG_NONE(dev->usage[idx]))) {
 				int matchret;
 
-				if ((matchret = isdn_tty_match_icall(eaz, &info->emu, slot->di)) > wret)
+				if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
 					wret = matchret;
 				if (!matchret) {                  /* EAZ is matching */
-					info->isdn_slot = slot;
-					slot->usage |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
-					slot->priv = info;
-					slot->event_cb = isdn_tty_event_callback;
-					strcpy(slot->num, nr);
+					info->isdn_driver = di;
+					info->isdn_channel = ch;
+					info->drv_index = idx;
+					dev->m_idx[idx] = info->line;
+					dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
+					dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); 
+					strcpy(dev->num[idx], nr);
 					strcpy(info->emu.cpn, eaz);
 					info->emu.mdmreg[REG_SI1I] = si2bit[si1];
 					info->emu.mdmreg[REG_PLAN] = setup->plan;
 					info->emu.mdmreg[REG_SCREEN] = setup->screen;
-					restore_flags(flags);
+					isdn_info_update();
+					spin_unlock_irqrestore(&dev->lock, flags);
 					printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
 					       info->line);
 					info->msr |= UART_MSR_RI;
 					isdn_tty_modem_result(RESULT_RING, info);
-					mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT);
+					isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
 					return 1;
 				}
 			}
 		}
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
-	       (wret != 2)? "rejected" : "ignored");
+	       ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
 	return (wret == 2)?3:0;
 }
 
 #define TTY_IS_ACTIVE(info) \
-	(info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
+	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
 
-static int
-isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c)
+int
+isdn_tty_stat_callback(int i, isdn_ctrl *c)
 {
-	isdn_ctrl cmd;
+	int mi;
 	modem_info *info;
 	char *e;
 
-	info = slot->priv;
-	if (1) {
+	if (i < 0)
+		return 0;
+	if ((mi = dev->m_idx[i]) >= 0) {
+		info = &dev->mdm.info[mi];
 		switch (c->command) {
                         case ISDN_STAT_CINF:
                                 printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
@@ -2294,12 +2192,16 @@
 #ifdef ISDN_TTY_STAT_DEBUG
 				printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
 #endif
-				info->msr |= UART_MSR_CTS;
-				if (info->send_outstanding)
-					if (!(--info->send_outstanding))
-						info->lsr |= UART_LSR_TEMT;
-				isdn_tty_tint(info);
-				return 1;
+				if ((info->isdn_driver == c->driver) &&
+				    (info->isdn_channel == c->arg)) {
+					info->msr |= UART_MSR_CTS;
+					if (info->send_outstanding)
+						if (!(--info->send_outstanding))
+							info->lsr |= UART_LSR_TEMT;
+					isdn_tty_tint(info);
+					return 1;
+				}
+				break;
 			case ISDN_STAT_CAUSE:
 #ifdef ISDN_TTY_STAT_DEBUG
 				printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
@@ -2326,7 +2228,6 @@
 #endif
 				if (TTY_IS_ACTIVE(info)) {
 					if (info->dialing == 1) {
-						isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
 						info->dialing = 2;
 						return 1;
 					}
@@ -2376,14 +2277,14 @@
 						info->last_dir = 0;
 					info->dialing = 0;
 					info->rcvsched = 1;
-					if (USG_MODEM(slot->usage)) {
+					if (USG_MODEM(dev->usage[i])) {
 						if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
 							strcpy(info->emu.connmsg, c->parm.num);
 							isdn_tty_modem_result(RESULT_CONNECT, info);
 						} else
 							isdn_tty_modem_result(RESULT_CONNECT64000, info);
 					}
-					if (USG_VOICE(slot->usage))
+					if (USG_VOICE(dev->usage[i]))
 						isdn_tty_modem_result(RESULT_VCON, info);
 					return 1;
 				}
@@ -2400,6 +2301,34 @@
 					return 1;
 				}
 				break;
+			case ISDN_STAT_NODCH:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
+#endif
+				if (TTY_IS_ACTIVE(info)) {
+					if (info->dialing) {
+						info->dialing = 0;
+						info->last_l2 = -1;
+						info->last_si = 0;
+						sprintf(info->last_cause, "0000");
+						isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
+					}
+					isdn_tty_modem_hup(info, 0);
+					return 1;
+				}
+				break;
+			case ISDN_STAT_UNLOAD:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
+#endif
+				for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+					info = &dev->mdm.info[i];
+					if (info->isdn_driver == c->driver) {
+						if (info->online)
+							isdn_tty_modem_hup(info, 1);
+					}
+				}
+				return 1;
 #ifdef CONFIG_ISDN_TTY_FAX
 			case ISDN_STAT_FAXIND:
 				if (TTY_IS_ACTIVE(info)) {
@@ -2443,7 +2372,7 @@
 	atemu *m = &info->emu;
 	char *p;
 	char c;
-	ulong flags;
+	u_long flags;
 	struct sk_buff *skb = 0;
 	char *sp = 0;
 
@@ -2451,30 +2380,22 @@
 		printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
 		return;
 	}
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&info->readlock, flags);
 	tty = info->tty;
 	if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&info->readlock, flags);
 		return;
 	}
 
 	/* use queue instead of direct flip, if online and */
 	/* data is in queue or flip buffer is full */
 	if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
-	    (!skb_queue_empty(&info->rpqueue)))) {
-		skb = alloc_skb(strlen(msg)
-#ifdef CONFIG_ISDN_AUDIO
-			+ sizeof(isdnaudio_header)
-#endif
-			, GFP_ATOMIC);
+	    (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) {
+		skb = alloc_skb(strlen(msg), GFP_ATOMIC);
 		if (!skb) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&info->readlock, flags);
 			return;
 		}
-#ifdef CONFIG_ISDN_AUDIO
-		skb_reserve(skb, sizeof(isdnaudio_header));
-#endif
 		sp = skb_put(skb, strlen(msg));
 #ifdef CONFIG_ISDN_AUDIO
 		ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
@@ -2505,13 +2426,15 @@
 		}
 	}
 	if (skb) {
-		isdn_tty_queue_tail(info, skb, skb->len);
-		restore_flags(flags);
+		__skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
+		dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
+		spin_unlock_irqrestore(&info->readlock, flags);
 		/* Schedule dequeuing */
-		if ((get_isdn_dev())->modempoll && info->rcvsched)
-			mod_timer(&info->read_timer, jiffies + 4);
+		if ((dev->modempoll) && (info->rcvsched))
+			isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+
 	} else {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&info->readlock, flags);
 		schedule_delayed_work(&tty->flip.work, 1);
 	}
 }
@@ -2522,7 +2445,7 @@
 static void
 isdn_tty_on_hook(modem_info * info)
 {
-	if (info->isdn_slot) {
+	if (info->isdn_channel >= 0) {
 #ifdef ISDN_DEBUG_MODEM_HUP
 		printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
 #endif
@@ -2539,56 +2462,54 @@
 #define PLUSWAIT1 (HZ/2)        /* 0.5 sec. */
 #define PLUSWAIT2 (HZ*3/2)      /* 1.5 sec */
 
-static void
-isdn_tty_escape_timer(unsigned long data)
-{
-	struct modem_info *info = (struct modem_info *) data;
-
-	if (!info->online)
-		return;
-	
-	info->emu.pluscount = 0;
-	info->online = 0;
-	isdn_tty_modem_result(RESULT_OK, info);
-}
-
 /*
  * Check Buffer for Modem-escape-sequence, activate timer-callback to
  * isdn_tty_modem_escape() if sequence found.
+ *
+ * Parameters:
+ *   p          pointer to databuffer
+ *   plus       escape-character
+ *   count      length of buffer
+ *   pluscount  count of valid escape-characters so far
+ *   lastplus   timestamp of last character
  */
-static void isdn_tty_check_esc(struct modem_info *info, 
-			       const unsigned char *p, int count)
+static void
+isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
+		   u_long *lastplus, int from_user)
 {
-	unsigned char plus = info->emu.mdmreg[REG_ESC];
+	char cbuf[3];
 
 	if (plus > 127)
 		return;
-
 	if (count > 3) {
 		p += count - 3;
 		count = 3;
-		info->emu.pluscount = 0;
-		info->emu.lastplus = jiffies;
+		*pluscount = 0;
 	}
-	for (; count > 0; info->emu.lastplus = jiffies, count--) {
-		if (*(p++) != plus) {
-			info->emu.pluscount = 0;
-			continue;
-		}
-		if (info->emu.pluscount == 0) {
-			if (time_after(jiffies, info->emu.lastplus + PLUSWAIT2))
-				info->emu.pluscount = 1;
-		} else {
-			if (time_after(jiffies, info->emu.lastplus + PLUSWAIT1))
-				info->emu.pluscount = 1;
-			else
-				info->emu.pluscount++;
-		}
+	if (from_user) {
+		copy_from_user(cbuf, p, count);
+		p = cbuf;
+	}
+	while (count > 0) {
+		if (*(p++) == plus) {
+			if ((*pluscount)++) {
+				/* Time since last '+' > 0.5 sec. ? */
+				if (time_after(jiffies, *lastplus + PLUSWAIT1))
+					*pluscount = 1;
+			} else {
+				/* Time since last non-'+' < 1.5 sec. ? */
+				if (time_before(jiffies, *lastplus + PLUSWAIT2))
+					*pluscount = 0;
+			}
+			if ((*pluscount == 3) && (count == 1))
+				isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
+			if (*pluscount > 3)
+				*pluscount = 1;
+		} else
+			*pluscount = 0;
+		*lastplus = jiffies;
+		count--;
 	}
-	if (info->emu.pluscount == 3)
-		mod_timer(&info->escape_timer, jiffies + PLUSWAIT2);
-	else
-		del_timer(&info->escape_timer);
 }
 
 /*
@@ -2606,7 +2527,6 @@
 	{"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
 	 "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
 	 "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
-	ulong flags;
 	char s[ISDN_MSNLEN+10];
 
 	switch (code) {
@@ -2622,16 +2542,12 @@
 			       (info->flags & ISDN_ASYNC_CLOSING),
 			       (!info->tty));
 #endif
-			save_flags(flags);
-			cli();
 			m->mdmreg[REG_RINGCNT] = 0;
 			del_timer(&info->nc_timer);
 			info->ncarrier = 0;
 			if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
-				restore_flags(flags);
 				return;
 			}
-			restore_flags(flags);
 #ifdef CONFIG_ISDN_AUDIO
 			if (info->vonline & 1) {
 #ifdef ISDN_DEBUG_MODEM_VOICE
@@ -2683,7 +2599,7 @@
 			    /* print CID, _before_ _every_ ring */
 			    if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
 				    isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
-				    isdn_tty_at_cout(info->isdn_slot->num, info);
+				    isdn_tty_at_cout(dev->num[info->drv_index], info);
 				    if (m->mdmreg[REG_CDN] & BIT_CDN) {
 					    isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
 					    isdn_tty_at_cout(info->emu.cpn, info);
@@ -2712,7 +2628,7 @@
 					    (m->mdmreg[REG_RINGCNT] == 1)) {
 						isdn_tty_at_cout("\r\n", info);
 						isdn_tty_at_cout("CALLER NUMBER: ", info);
-						isdn_tty_at_cout(info->isdn_slot->num, info);
+						isdn_tty_at_cout(dev->num[info->drv_index], info);
 						if (m->mdmreg[REG_CDN] & BIT_CDN) {
 							isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
 							isdn_tty_at_cout(info->emu.cpn, info);
@@ -2762,18 +2678,16 @@
 		}
 	}
 	if (code == RESULT_NO_CARRIER) {
-		save_flags(flags);
-		cli();
 		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
-			restore_flags(flags);
 			return;
 		}
 		if (info->tty->ldisc.flush_buffer)
 			info->tty->ldisc.flush_buffer(info->tty);
-		if (info->flags & ISDN_ASYNC_CHECK_CD) {
+		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
+		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
+		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
 			tty_hangup(info->tty);
 		}
-		restore_flags(flags);
 	}
 }
 
@@ -3222,7 +3136,7 @@
 	if (info->msr & UART_MSR_RI) {
 		/* Accept incoming call */
 		info->last_dir = 0;
-		strcpy(info->last_num, info->isdn_slot->num);
+		strcpy(info->last_num, dev->num[info->drv_index]);
 		m->mdmreg[REG_RINGCNT] = 0;
 		info->msr &= ~UART_MSR_RI;
 		l2 = m->mdmreg[REG_L2PROT];
@@ -3236,20 +3150,28 @@
 				l2 = ISDN_PROTO_L2_X75I;
 		}
 #endif
-		cmd.arg = l2 << 8;
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
+		cmd.arg = info->isdn_channel + (l2 << 8);
 		info->last_l2 = l2;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL2, &cmd);
-		cmd.arg = m->mdmreg[REG_L3PROT] << 8;
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
 #ifdef CONFIG_ISDN_TTY_FAX
 		if (l2 == ISDN_PROTO_L2_FAX) {
 			cmd.parm.fax = info->fax;
 			info->fax->direction = ISDN_TTY_FAX_CONN_IN;
 		}
 #endif
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
+		isdn_command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_ACCEPTD;
 		info->dialing = 16;
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTD, &cmd);
-		mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ); 
+		info->emu.carrierwait = 0;
+		isdn_command(&cmd);
+		isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
 	} else
 		isdn_tty_modem_result(RESULT_NO_ANSWER, info);
 }
@@ -3293,7 +3215,7 @@
 #ifdef CONFIG_ISDN_TTY_FAX
 					case '1':
 						p[0]++;
-						if (!((get_isdn_dev())->global_features &
+						if (!(dev->global_features &
 							ISDN_FEATURE_L3_FCLASS1))
 							PARSE_ERROR1;
 						m->mdmreg[REG_SI1] = 1;
@@ -3304,7 +3226,7 @@
 						break;
 					case '2':
 						p[0]++;
-						if (!((get_isdn_dev())->global_features &
+						if (!(dev->global_features &
 							ISDN_FEATURE_L3_FCLASS2))
 							PARSE_ERROR1;
 						m->mdmreg[REG_SI1] = 1;
@@ -3326,10 +3248,10 @@
 						p[0]++;
 						strcpy(rs, "\r\n0,");
 #ifdef CONFIG_ISDN_TTY_FAX
-						if ((get_isdn_dev())->global_features &
+						if (dev->global_features &
 							ISDN_FEATURE_L3_FCLASS1)
 							strcat(rs, "1,");
-						if ((get_isdn_dev())->global_features &
+						if (dev->global_features &
 							ISDN_FEATURE_L3_FCLASS2)
 							strcat(rs, "2,");
 #endif
@@ -3604,10 +3526,12 @@
 							PARSE_ERROR1;
 						m->vpar[4] = par1;
 						m->vpar[5] = par2;
-						cmd.arg = ISDN_AUDIO_SETDD << 8;
+						cmd.driver = info->isdn_driver;
+						cmd.command = ISDN_CMD_AUDIO;
+						cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
 						cmd.parm.num[0] = par1;
 						cmd.parm.num[1] = par2;
-						isdn_slot_command(info->isdn_slot, ISDN_CMD_AUDIO, &cmd);
+						isdn_command(&cmd);
 						break;
 					} else
 					if (*p[0] == '?') {
@@ -3919,34 +3843,99 @@
 	return total;
 }
 
-static void
-isdn_tty_ring_timer(unsigned long data)
+/*
+ * Switch all modem-channels who are online and got a valid
+ * escape-sequence 1.5 seconds ago, to command-mode.
+ * This function is called every second via timer-interrupt from within
+ * timer-dispatcher isdn_timer_function()
+ */
+void
+isdn_tty_modem_escape(void)
 {
-	struct modem_info *info = (struct modem_info *) data;
-
-	if (!(info->msr & UART_MSR_RI))
-		return;
+	int ton = 0;
+	int i;
+	int midx;
 
-	isdn_tty_modem_result(RESULT_RING, info);
-	mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		if (USG_MODEM(dev->usage[i]))
+			if ((midx = dev->m_idx[i]) >= 0) {
+				modem_info *info = &dev->mdm.info[midx];
+				if (info->online) {
+					ton = 1;
+					if ((info->emu.pluscount == 3) &&
+					    time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
+						info->emu.pluscount = 0;
+						info->online = 0;
+						isdn_tty_modem_result(RESULT_OK, info);
+					}
+				}
+			}
+	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 }
-	
-static void
-isdn_tty_modem_xmit(struct modem_info *info)
+
+/*
+ * Put a RING-message to all modem-channels who have the RI-bit set.
+ * This function is called every second via timer-interrupt from within
+ * timer-dispatcher isdn_timer_function()
+ */
+void
+isdn_tty_modem_ring(void)
 {
-	isdn_tty_senddown(info);
-	isdn_tty_tint(info);
+	int ton = 0;
+	int i;
+
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		modem_info *info = &dev->mdm.info[i];
+		if (info->msr & UART_MSR_RI) {
+			ton = 1;
+			isdn_tty_modem_result(RESULT_RING, info);
+		}
+	}
+	isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
 }
 
-static void
-isdn_tty_connect_timer(unsigned long data)
+/*
+ * For all online tty's, try sending data to
+ * the lower levels.
+ */
+void
+isdn_tty_modem_xmit(void)
 {
-	struct modem_info *info = (struct modem_info *) data;
+	int ton = 1;
+	int i;
 
-	if (info->dialing) {
-		info->dialing = 0;
-		isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-		isdn_tty_modem_hup(info, 1);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		modem_info *info = &dev->mdm.info[i];
+		if (info->online) {
+			ton = 1;
+			isdn_tty_senddown(info);
+			isdn_tty_tint(info);
+		}
 	}
+	isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
 }
 
+/*
+ * Check all channels if we have a 'no carrier' timeout.
+ * Timeout value is set by Register S7.
+ */
+void
+isdn_tty_carrier_timeout(void)
+{
+	int ton = 0;
+	int i;
+
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		modem_info *info = &dev->mdm.info[i];
+		if (info->dialing) {
+			if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+				info->dialing = 0;
+				isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+				isdn_tty_modem_hup(info, 1);
+			}
+			else
+				ton = 1;
+		}
+	}
+	isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
+}
--- diff/drivers/isdn/i4l/isdn_tty.h	2003-06-30 10:07:21.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_tty.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,10 +1,13 @@
-/* Linux ISDN subsystem, tty related functions
+/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #include <linux/config.h>
@@ -98,31 +101,22 @@
 	((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
 	 (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
 
-extern int isdn_tty_init(void);
-extern int isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup);
+extern void isdn_tty_modem_escape(void);
+extern void isdn_tty_modem_ring(void);
+extern void isdn_tty_carrier_timeout(void);
+extern void isdn_tty_modem_xmit(void);
+extern int  isdn_tty_modem_init(void);
+extern void isdn_tty_exit(void);
+extern void isdn_tty_readmodem(void);
+extern int  isdn_tty_find_icall(int, int, setup_parm *);
 extern void isdn_tty_cleanup_xmit(modem_info *);
-extern int isdn_tty_capi_facility(capi_msg *cm); 
+extern int  isdn_tty_stat_callback(int, isdn_ctrl *);
+extern int  isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
+extern int  isdn_tty_capi_facility(capi_msg *cm); 
 extern void isdn_tty_at_cout(char *, modem_info *);
 extern void isdn_tty_modem_hup(modem_info *, int);
 #ifdef CONFIG_ISDN_TTY_FAX
-extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
+extern int  isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
+extern int  isdn_tty_fax_command(modem_info *, isdn_ctrl *);
 extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
 #endif
-
-extern int isdn_tty_init(void);
-extern void isdn_tty_exit(void);
-
-struct isdn_modem {
-  struct tty_driver  *tty_modem;		   /* tty-device             */
-  modem_info         info[ISDN_MAX_CHANNELS];	   /* Private data           */
-};
-
-extern struct isdn_modem isdn_mdm;
-
-static inline void
-isdn_tty_queue_tail(modem_info *info, struct sk_buff *skb, int len)
-{
-	__skb_queue_tail(&info->rpqueue, skb);
-	info->rcvcount += len;
-}
--- diff/drivers/isdn/i4l/isdn_ttyfax.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_ttyfax.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,6 @@
-/* Linux ISDN subsystem, tty_fax AT-command emulator
+/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
  *
  * Copyright 1999    by Armin Schindler (mac@melware.de)
  * Copyright 1999    by Ralf Spachmann (mel@melware.de)
@@ -6,6 +8,7 @@
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #undef ISDN_TTY_FAX_STAT_DEBUG
@@ -16,8 +19,26 @@
 #include "isdn_tty.h"
 #include "isdn_ttyfax.h"
 
+
+static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
+
 #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
 
+static char *
+isdn_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
+}
+
 /*
  * Fax Class 2 Modem results
  *
@@ -53,7 +74,7 @@
 		case 2:	/* +FCON */
 			/* Append CPN, if enabled */
 			if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
-				(!(info->isdn_slot->usage & ISDN_USAGE_OUTGOING))) {
+				(!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
 				sprintf(rs, "/%s", m->cpn);
 				isdn_tty_at_cout(rs, info);
 			}
@@ -265,7 +286,7 @@
 	__u8 RightMask;
 	__u8 fBit;
 	__u8 Data;
-	u_int i;
+	int i;
 
 	if (!info->fax->bor) {
 		for (i = 0; i < skb->len; i++) {
@@ -301,9 +322,8 @@
 	static char *cmd[] =
 	{"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
 	isdn_ctrl c;
-	int par;
-	struct isdn_slot *slot;
-	unsigned long flags;
+	int par, i;
+	u_long flags;
 
 	for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
 		if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
@@ -340,32 +360,46 @@
 		default:
 			PARSE_ERROR1;
 	}
+	c.command = ISDN_CMD_FAXCMD;
 #ifdef ISDN_TTY_FAX_CMD_DEBUG
 	printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
 	       c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
 #endif
-	if (!info->isdn_slot) {
-		save_flags(flags);
-		cli();
+	if (info->isdn_driver < 0) {
 		if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
 		    (c.parm.aux.subcmd == AT_COMMAND)) {
-			restore_flags(flags);
 			PARSE_ERROR1;
 		}
+		spin_lock_irqsave(&dev->lock, flags);
 		/* get a temporary connection to the first free fax driver */
-		slot = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
-				       ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
-		if (!slot) {
-			restore_flags(flags);
+		i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
+					  ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
+		if (i < 0) {
+			spin_unlock_irqrestore(&dev->lock, flags);
 			PARSE_ERROR1;
 		}
-		info->isdn_slot = slot;
-		isdn_slot_command(slot, ISDN_CMD_FAXCMD, &c);
-		isdn_slot_free(slot);
-		info->isdn_slot = NULL;
-		restore_flags(flags);
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		c.driver = info->isdn_driver;
+		c.arg = info->isdn_channel;
+		isdn_command(&c);
+		spin_lock_irqsave(&dev->lock, flags);
+		isdn_free_channel(info->isdn_driver, info->isdn_channel,
+				  ISDN_USAGE_FAX);
+		info->isdn_driver = -1;
+		info->isdn_channel = -1;
+		if (info->drv_index >= 0) {
+			dev->m_idx[info->drv_index] = -1;
+			info->drv_index = -1;
+		}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	} else {
-		isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
+		c.driver = info->isdn_driver;
+		c.arg = info->isdn_channel;
+		isdn_command(&c);
 	}
 	return 1;
 }
@@ -766,7 +800,10 @@
 			printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
 #endif
 			f->code = ISDN_TTY_FAX_DR;
-			isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
+			cmd.driver = info->isdn_driver;
+			cmd.arg = info->isdn_channel;
+			cmd.command = ISDN_CMD_FAXCMD;
+			isdn_command(&cmd);
 			if (f->phase == ISDN_FAX_PHASE_B) {
 				f->phase = ISDN_FAX_PHASE_C;
 			} else if (f->phase == ISDN_FAX_PHASE_D) {
@@ -818,7 +855,10 @@
 #endif
 		if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
 			f->code = ISDN_TTY_FAX_DT;
-			isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
+			cmd.driver = info->isdn_driver;
+			cmd.arg = info->isdn_channel;
+			cmd.command = ISDN_CMD_FAXCMD;
+			isdn_command(&cmd);
 			if (f->phase == ISDN_FAX_PHASE_D) {
 				f->phase = ISDN_FAX_PHASE_C;
 				isdn_tty_fax_modem_result(7, info);	/* CONNECT */
@@ -873,7 +913,10 @@
 				PARSE_ERROR1;
 			f->fet = par;
 			f->code = ISDN_TTY_FAX_ET;
-			isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
+			cmd.driver = info->isdn_driver;
+			cmd.arg = info->isdn_channel;
+			cmd.command = ISDN_CMD_FAXCMD;
+			isdn_command(&cmd);
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
 			printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
 #endif
@@ -1043,7 +1086,8 @@
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
 		printk(KERN_DEBUG "isdn_tty: FREV?\n");
 #endif
-		sprintf(rs, "\r\nRev: 1.0");
+		strcpy(rss, isdn_tty_fax_revision);
+		sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
 		isdn_tty_at_cout(rs, info);
 		return 0;
 	}
--- diff/drivers/isdn/i4l/isdn_ttyfax.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ttyfax.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,4 +1,6 @@
-/* Linux ISDN subsystem, tty_fax related functions
+/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
  *
  * Copyright 1999   by Armin Schindler (mac@melware.de)
  * Copyright 1999   by Ralf Spachmann (mel@melware.de)
@@ -6,6 +8,7 @@
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 
--- diff/drivers/isdn/i4l/isdn_v110.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_v110.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,22 +1,27 @@
-/* Linux ISDN subsystem, V.110
+/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
  * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <linux/isdn.h>
 #include "isdn_v110.h"
-#include "isdn_common.h"
 
 #undef ISDN_V110_DEBUG
 
+char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
+
 #define V110_38400 255
 #define V110_19200  15
 #define V110_9600    3
@@ -82,7 +87,7 @@
  * structures and returns a pointer to these.
  */
 static isdn_v110_stream *
-do_isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
+isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
 {
 	int i;
 	isdn_v110_stream *v;
@@ -127,8 +132,8 @@
 }
 
 /* isdn_v110_close frees private V.110 data structures */
-static void
-do_isdn_v110_close(isdn_v110_stream * v)
+void
+isdn_v110_close(isdn_v110_stream * v)
 {
 	if (v == NULL)
 		return;
@@ -510,94 +515,101 @@
 	return nskb;
 }
 
-
-void
-isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110)
-{	
-	isdn_v110_stream *v;
-	int hdrlen = isdn_slot_hdrlen(slot);
-	int maxsize = isdn_slot_maxbufsize(slot);
-
-	atomic_inc(&iv110->v110use);
-	switch (iv110->v110emu) {
-	case ISDN_PROTO_L2_V11096:
-		iv110->v110 = do_isdn_v110_open(V110_9600, hdrlen, maxsize);
-		break;
-	case ISDN_PROTO_L2_V11019:
-		iv110->v110 = do_isdn_v110_open(V110_19200, hdrlen, maxsize);
-		break;
-	case ISDN_PROTO_L2_V11038:
-		iv110->v110 = do_isdn_v110_open(V110_38400, hdrlen, maxsize);
-		break;
-	}
-	if ((v = iv110->v110)) {
-		while (v->SyncInit) {
-			struct sk_buff *skb = isdn_v110_sync(v);
-			if (isdn_slot_write(slot, skb) <= 0) {
-				dev_kfree_skb(skb);
-				/* Unable to send, try later */
-				break;
-			}
-			v->SyncInit--;
-			v->skbidle++;
-		}
-	} else
-		printk(KERN_WARNING "isdn_v110: Couldn't open stream\n");
-	atomic_dec(&iv110->v110use);
-}
-
-void
-isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110)
-{
-	while (1) {
-		atomic_inc(&iv110->v110use);
-		if (atomic_dec_and_test(&iv110->v110use)) {
-			do_isdn_v110_close(iv110->v110);
-			iv110->v110 = NULL;
-			break;
-		}
-	}
-}
-
 int
-isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110)
+isdn_v110_stat_callback(int idx, isdn_ctrl * c)
 {
-	isdn_v110_stream *v = iv110->v110;
-	int i, ret;
+	isdn_v110_stream *v = NULL;
+	int i;
+	int ret;
 
-	/* Keep the send-queue of the driver filled
-	 * with frames:
-	 * If number of outstanding frames < 3,
-	 * send down an Idle-Frame (or an Sync-Frame, if
-	 * v->SyncInit != 0). 
-	 */
-	atomic_inc(&iv110->v110use);
-	if (v->skbidle > 0) {
-		v->skbidle--;
-		ret = 1;
-	} else {
-		if (v->skbuser > 0)
-			v->skbuser--;
-		ret = 0;
-	}
-	for (i = v->skbuser + v->skbidle; i < 2; i++) {
-		struct sk_buff *skb;
-		if (v->SyncInit > 0)
-			skb = isdn_v110_sync(v);
-		else
-			skb = isdn_v110_idle(v);
-		if (skb) {
-			if (isdn_slot_write(slot, skb) <= 0) {
-				dev_kfree_skb(skb);
-				break;
+	if (idx < 0)
+		return 0;
+	switch (c->command) {
+		case ISDN_STAT_BSENT:
+                        /* Keep the send-queue of the driver filled
+			 * with frames:
+			 * If number of outstanding frames < 3,
+			 * send down an Idle-Frame (or an Sync-Frame, if
+			 * v->SyncInit != 0). 
+			 */
+			if (!(v = dev->v110[idx]))
+				return 0;
+			atomic_inc(&dev->v110use[idx]);
+			if (v->skbidle > 0) {
+				v->skbidle--;
+				ret = 1;
 			} else {
-				if (v->SyncInit)
-					v->SyncInit--;
-				v->skbidle++;
+				if (v->skbuser > 0)
+					v->skbuser--;
+				ret = 0;
+			}
+			for (i = v->skbuser + v->skbidle; i < 2; i++) {
+				struct sk_buff *skb;
+				if (v->SyncInit > 0)
+					skb = isdn_v110_sync(v);
+				else
+					skb = isdn_v110_idle(v);
+				if (skb) {
+					if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+						dev_kfree_skb(skb);
+						break;
+					} else {
+						if (v->SyncInit)
+							v->SyncInit--;
+						v->skbidle++;
+					}
+				} else
+					break;
+			}
+			atomic_dec(&dev->v110use[idx]);
+			return ret;
+		case ISDN_STAT_DHUP:
+		case ISDN_STAT_BHUP:
+			while (1) {
+				atomic_inc(&dev->v110use[idx]);
+				if (atomic_dec_and_test(&dev->v110use[idx])) {
+					isdn_v110_close(dev->v110[idx]);
+					dev->v110[idx] = NULL;
+					break;
+				}
+				mdelay(1);
 			}
-		} else
 			break;
+		case ISDN_STAT_BCONN:
+			if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
+				int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
+				int maxsize = dev->drv[c->driver]->interface->maxbufsize;
+				atomic_inc(&dev->v110use[idx]);
+				switch (dev->v110emu[idx]) {
+					case ISDN_PROTO_L2_V11096:
+						dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
+						break;
+					case ISDN_PROTO_L2_V11019:
+						dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
+						break;
+					case ISDN_PROTO_L2_V11038:
+						dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
+						break;
+					default:;
+				}
+				if ((v = dev->v110[idx])) {
+					while (v->SyncInit) {
+						struct sk_buff *skb = isdn_v110_sync(v);
+						if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+							dev_kfree_skb(skb);
+							/* Unable to send, try later */
+							break;
+						}
+						v->SyncInit--;
+						v->skbidle++;
+					}
+				} else
+					printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
+				atomic_dec(&dev->v110use[idx]);
+			}
+			break;
+		default:
+			return 0;
 	}
-	atomic_dec(&iv110->v110use);
-	return ret;
+	return 0;
 }
--- diff/drivers/isdn/i4l/isdn_v110.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_v110.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,19 +1,16 @@
-/* Linux ISDN subsystem, V.110 related functions
+/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
  * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
-#ifndef ISDN_V110_H
-#define ISDN_V110_H
-
-struct isdn_v110 {
-  int               v110emu;             /* V.110 emulator-mode 0=none */
-  atomic_t          v110use;             /* Usage-Semaphore for stream */
-  isdn_v110_stream  *v110;               /* V.110 private data         */
-};
+#ifndef _isdn_v110_h_
+#define _isdn_v110_h_
 
 /* 
  * isdn_v110_encode will take raw data and encode it using V.110 
@@ -26,10 +23,7 @@
  */
 extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
 
-extern void isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110);
-
-extern void isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110);
-
-extern int  isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110);
+extern int isdn_v110_stat_callback(int, isdn_ctrl *);
+extern void isdn_v110_close(isdn_v110_stream * v);
 
 #endif
--- diff/drivers/isdn/i4l/isdn_x25iface.c	2003-08-20 14:16:28.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_x25iface.c	2004-02-18 09:03:59.000000000 +0000
@@ -1,10 +1,10 @@
-/* * Linux ISDN subsystem, X.25 related functions
+/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * Linux ISDN subsystem, X.25 related functions
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
- */
-
-/*
+ *
  * stuff needed to support the Linux X.25 PLP code on top of devices that
  * can provide a lab_b service using the concap_proto mechanism.
  * This module supports a network interface wich provides lapb_sematics
@@ -17,6 +17,7 @@
  *
  */
 
+/* #include <linux/isdn.h> */
 #include <linux/netdevice.h>
 #include <linux/concap.h>
 #include <linux/wanrouter.h>
@@ -63,7 +64,7 @@
 /* error message helper function */
 static void illegal_state_warn( unsigned state, unsigned char firstbyte) 
 {
-	printk( KERN_WARNING "isdn_x25iface: firstbyte %x invalid in"
+	printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
 		"current state %d\n",firstbyte, state );
 }
 
@@ -72,7 +73,7 @@
 
 	if( pda  &&  pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
 	printk( KERN_WARNING
-		"isdn_x25iface_xxx: invalid pointer to proto data\n" );
+		"isdn_x25iface_xxx: illegal pointer to proto data\n" );
 	return 1;
 }
 
@@ -87,6 +88,7 @@
 		tmp -> state = WAN_UNCONFIGURED;
 		/* private data space used to hold the concap_proto data.
 		   Only to be accessed via the returned pointer */
+		spin_lock_init(&tmp->priv.lock);
 		tmp -> priv.dops       = NULL;
 		tmp -> priv.net_dev    = NULL;
 		tmp -> priv.pops       = &ix25_pops;
@@ -111,9 +113,7 @@
 		return -1;
 	}
 	IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
-	save_flags(flags);
-	cli();  /* avoid races with incoming events calling pops methods while
-		 cprot members are inconsistent */  
+	spin_lock_irqsave(&cprot->lock, flags);
 	cprot -> dops    = NULL;
 	cprot -> net_dev = NULL;
 	tmp = cprot -> proto_data;
@@ -122,8 +122,7 @@
 	} else {
 		tmp -> state = WAN_UNCONFIGURED;
 	}
-	restore_flags(flags);
-
+	spin_unlock_irqrestore(&cprot->lock, flags);
 	return ret;
 }
 
@@ -176,14 +175,12 @@
 		isdn_x25iface_proto_close(cprot);
 		return -1;
 	}
-	save_flags(flags);
-	cli();  /* avoid races with incoming events calling pops methods while
-		 cprot members are inconsistent */  
+	spin_lock_irqsave(&cprot->lock, flags);
 	cprot -> net_dev = ndev;
 	cprot -> pops = &ix25_pops;
 	cprot -> dops = dops;
 	pda -> state = WAN_DISCONNECTED;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&cprot->lock, flags);
 	return 0;
 }
 
@@ -222,8 +219,6 @@
 		printk(KERN_WARNING 
 		       "isdn_x25iface_connect_ind while unconfigured %s\n"
 		       , MY_DEVNAME(cprot->net_dev) );
-		if (skb)
-			dev_kfree_skb(skb);
 		return -1;
 	}
 	*state_p = WAN_CONNECTED;
@@ -334,7 +329,7 @@
 		       " options not yet supported\n");
 		break;
 	default:
-		printk(KERN_WARNING "isdn_x25iface_xmit: frame with invalid"
+		printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
 		       " first byte %x ignored:\n", firstbyte);
 	}
 	dev_kfree_skb(skb);
--- diff/drivers/isdn/i4l/isdn_x25iface.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_x25iface.h	2004-02-18 09:03:59.000000000 +0000
@@ -1,16 +1,17 @@
-/* Linux ISDN subsystem, x.25 related functions
+/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
+ *
+ * header for Linux ISDN subsystem, x.25 related functions
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
+ *
  */
 
 #ifndef _LINUX_ISDN_X25IFACE_H
 #define _LINUX_ISDN_X25IFACE_H
 
 #define ISDN_X25IFACE_MAGIC 0x1e75a2b9
-
-#undef DEBUG_ISDN_X25
-
+/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
 #ifdef DEBUG_ISDN_X25
 #   define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
 #else
@@ -25,6 +26,8 @@
 extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
 extern struct concap_proto     * isdn_x25iface_proto_new(void);
 
+
+
 #endif
 
 
--- diff/drivers/isdn/icn/Kconfig	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/icn/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ICN
 	tristate "ICN 2B and 4B support"
-	depends on ISDN && ISA
+	depends on ISDN_I4L && ISA
 	help
 	  This enables support for two kinds of ISDN-cards made by a German
 	  company called ICN.  2B is the standard version for a single ISDN
--- diff/drivers/isdn/pcbit/Kconfig	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/pcbit/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_PCBIT
 	tristate "PCBIT-D support"
-	depends on ISDN && ISA
+	depends on ISDN_I4L && ISA
 	help
 	  This enables support for the PCBIT ISDN-card.  This card is
 	  manufactured in Portugal by Octal.  For running this card,
--- diff/drivers/isdn/pcbit/drv.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/isdn/pcbit/drv.c	2004-02-18 09:03:59.000000000 +0000
@@ -84,6 +84,7 @@
 	dev_pcbit[board] = dev;
 	memset(dev, 0, sizeof(struct pcbit_dev));
 	init_waitqueue_head(&dev->set_running_wq);
+	spin_lock_init(&dev->lock);
 
 	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
 		dev->ph_mem = mem_base;
--- diff/drivers/isdn/pcbit/edss1.c	2002-10-16 04:27:13.000000000 +0100
+++ source/drivers/isdn/pcbit/edss1.c	2004-02-18 09:03:59.000000000 +0000
@@ -278,9 +278,7 @@
 	struct fsm_timer_entry *tentry;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_irqsave(&dev->lock, flags);
 
         for (action = fsm_table; action->init != 0xff; action++)
                 if (action->init == chan->fsm_state && action->event == event)
@@ -288,9 +286,9 @@
   
 	if (action->init == 0xff) {
 		
+		spin_unlock_irqrestore(&dev->lock, flags);
 		printk(KERN_DEBUG "fsm error: event %x on state %x\n", 
                        event, chan->fsm_state);
-		restore_flags(flags);
 		return;
 	}
 
@@ -315,7 +313,7 @@
                 add_timer(&chan->fsm_timer);
         }
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dev->lock, flags);
 
 	if (action->callb)
 		action->callb(dev, chan, data);
--- diff/drivers/isdn/pcbit/layer2.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/pcbit/layer2.c	2004-02-18 09:03:59.000000000 +0000
@@ -121,18 +121,17 @@
 
 	frame->next = NULL;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&dev->lock, flags);
 
 	if (dev->write_queue == NULL) {
 		dev->write_queue = frame;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 		pcbit_transmit(dev);
 	} else {
 		for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
 		ptr->next = frame;
 
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
 	return 0;
 }
@@ -174,15 +173,14 @@
 
 	unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&dev->lock, flags);
 
 	if (dev->free > 16 && dev->write_queue && unacked < 7) {
 
 		if (!dev->w_busy)
 			dev->w_busy = 1;
 		else {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return;
 		}
 
@@ -190,7 +188,7 @@
 		frame = dev->write_queue;
 		free = dev->free;
 
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 
 		if (frame->copied == 0) {
 
@@ -271,9 +269,7 @@
 		dev->free -= flen;
 		pcbit_tx_update(dev, flen);
 
-		save_flags(flags);
-		cli();
-
+		spin_lock_irqsave(&dev->lock, flags);
 
 		if (frame->skb == NULL || frame->copied == frame->skb->len) {
 
@@ -286,9 +282,9 @@
 			kfree(frame);
 		}
 		dev->w_busy = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 	} else {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 #ifdef DEBUG
 		printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
 		     unacked, dev->free, dev->write_queue ? "not empty" :
@@ -309,12 +305,11 @@
 	unsigned long flags, msg;
 	struct pcbit_dev *dev = (struct pcbit_dev *) data;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&dev->lock, flags);
 
 	while ((frame = dev->read_queue)) {
 		dev->read_queue = frame->next;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dev->lock, flags);
 
 		SET_MSG_CPU(msg, 0);
 		SET_MSG_PROC(msg, 0);
@@ -331,11 +326,10 @@
 
 		kfree(frame);
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&dev->lock, flags);
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 /*
@@ -460,12 +454,9 @@
 	memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
 
 	frame->copied += tt;
-
+	spin_lock_irqsave(&dev->lock, flags);
 	if (frame->copied == frame->hdr_len + frame->dt_len) {
 
-		save_flags(flags);
-		cli();
-
 		if (type1) {
 			dev->read_frame = NULL;
 		}
@@ -476,14 +467,10 @@
 		} else
 			dev->read_queue = frame;
 
-		restore_flags(flags);
-
 	} else {
-		save_flags(flags);
-		cli();
 		dev->read_frame = frame;
-		restore_flags(flags);
 	}
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 /*
--- diff/drivers/isdn/pcbit/pcbit.h	2002-10-16 04:27:15.000000000 +0100
+++ source/drivers/isdn/pcbit/pcbit.h	2004-02-18 09:03:59.000000000 +0000
@@ -51,7 +51,7 @@
 	unsigned int id;
 	unsigned int interrupt;			/* set during interrupt 
 						   processing */
-	
+	spinlock_t lock;
 	/* isdn4linux */
 
 	struct msn_entry * msn_list;		/* ISDN address list */
--- diff/drivers/isdn/sc/Kconfig	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/isdn/sc/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_SC
 	tristate "Spellcaster support"
-	depends on ISDN && ISA
+	depends on ISDN_I4L && ISA
 	help
 	  This enables support for the Spellcaster BRI ISDN boards.  This
 	  driver currently builds only in a modularized version.
--- diff/drivers/isdn/sc/command.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/sc/command.c	2004-02-18 09:03:59.000000000 +0000
@@ -32,7 +32,7 @@
 int acceptb(int card, unsigned long channel);
 
 extern int cinst;
-extern board *adapter[];
+extern board *sc_adapter[];
 
 extern int sc_ioctl(int, scs_ioctl *);
 extern int setup_buffers(int, int, unsigned int);
@@ -84,7 +84,7 @@
 	int i;
 
 	for(i = 0 ; i < cinst ; i++) {
-		if(adapter[i]->driverId == driver)
+		if(sc_adapter[i]->driverId == driver)
 			return i;
 	}
 	return -ENODEV;
@@ -105,7 +105,7 @@
 	}
 
 	pr_debug("%s: Received %s command from Link Layer\n",
-		adapter[card]->devicename, commands[cmd->command]);
+		sc_adapter[card]->devicename, commands[cmd->command]);
 
 	/*
 	 * Dispatch the command
@@ -120,7 +120,7 @@
 		if (copy_from_user(&ioc, (scs_ioctl *)cmdptr,
 				   sizeof(scs_ioctl))) {
 			pr_debug("%s: Failed to verify user space 0x%x\n",
-				adapter[card]->devicename, cmdptr);
+				sc_adapter[card]->devicename, cmdptr);
 			return -EFAULT;
 		}
 		return sc_ioctl(card, &ioc);
@@ -163,8 +163,8 @@
 		return -ENODEV;
 	}
 
-	pr_debug("%s: Sending loopback message\n", adapter[card]->devicename);
-	
+	pr_debug("%s: Sending loopback message\n",
+		sc_adapter[card]->devicename);
 
 	/*
 	 * Send the loopback message to confirm that memory transfer is
@@ -181,17 +181,17 @@
 
 	if (!status) {
 		pr_debug("%s: Loopback message successfully sent\n",
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 		if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
 			pr_debug("%s: Loopback return != sent\n",
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return -EIO;
 		}
 		return 0;
 	}
 	else {
 		pr_debug("%s: Send loopback message failed\n",
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 		return -EIO;
 	}
 
@@ -216,7 +216,7 @@
 			  cmReqClass0,
 			  cmReqStartProc,
 			  0,0,0);
-	pr_debug("%s: Sent startProc\n", adapter[card]->devicename);
+	pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename);
 	
 	return status;
 }
@@ -253,7 +253,7 @@
 				(unsigned int *) Phone);
 
 	pr_debug("%s: Dialing %s on channel %d\n",
-		adapter[card]->devicename, Phone, channel+1);
+		sc_adapter[card]->devicename, Phone, channel+1);
 	
 	return status;
 }
@@ -275,7 +275,7 @@
 
 	indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
 	pr_debug("%s: Answered incoming call on channel %s\n",
-		adapter[card]->devicename, channel+1);
+		sc_adapter[card]->devicename, channel+1);
 	return 0;
 }
 
@@ -298,7 +298,7 @@
 						 0,
 						 NULL);
 	pr_debug("%s: Sent HANGUP message to channel %d\n",
-		adapter[card]->devicename, channel+1);
+		sc_adapter[card]->devicename, channel+1);
 	return status;
 }
 
@@ -316,15 +316,16 @@
 	}
 	protocol = arg >> 8;
 	channel = arg & 0xff;
-	adapter[card]->channel[channel].l2_proto = protocol;
+	sc_adapter[card]->channel[channel].l2_proto = protocol;
 	pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
-		adapter[card]->devicename, channel+1,l2protos[adapter[card]->channel[channel].l2_proto],protocol);
+		sc_adapter[card]->devicename, channel+1,
+		l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
 
 	/*
 	 * check that the adapter is also set to the correct protocol
 	 */
 	pr_debug("%s: Sending GetFrameFormat for channel %d\n",
-		adapter[card]->devicename, channel+1);
+		sc_adapter[card]->devicename, channel+1);
 	status = sendmessage(card, CEPID, ceReqTypeCall,
  				ceReqClass0,
  				ceReqCallGetFrameFormat,
@@ -348,9 +349,9 @@
 		return -ENODEV;
 	}
 
-	adapter[card]->channel[channel].l3_proto = protocol;
+	sc_adapter[card]->channel[channel].l3_proto = protocol;
 	pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
-		adapter[card]->devicename, channel+1, l3protos[protocol]);
+		sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
 	return 0;
 }
 
@@ -368,7 +369,7 @@
 	}
 
 	pr_debug("%s: B-Channel connection accepted on channel %d\n",
-		adapter[card]->devicename, channel+1);
+		sc_adapter[card]->devicename, channel+1);
 	indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
 	return 0;
 }
@@ -380,10 +381,10 @@
 		return -ENODEV;
 	}
 
-	strcpy(adapter[card]->channel[arg].eazlist, "");
-	adapter[card]->channel[arg].eazclear = 1;
+	strcpy(sc_adapter[card]->channel[arg].eazlist, "");
+	sc_adapter[card]->channel[arg].eazclear = 1;
 	pr_debug("%s: EAZ List cleared for channel %d\n",
-		adapter[card]->devicename, arg+1);
+		sc_adapter[card]->devicename, arg+1);
 	return 0;
 }
 
@@ -394,11 +395,11 @@
 		return -ENODEV;
 	}
 
-	strcpy(adapter[card]->channel[arg].eazlist, num);
-	adapter[card]->channel[arg].eazclear = 0;
+	strcpy(sc_adapter[card]->channel[arg].eazlist, num);
+	sc_adapter[card]->channel[arg].eazclear = 0;
 	pr_debug("%s: EAZ list for channel %d set to: %s\n",
-		adapter[card]->devicename, arg+1,
-		adapter[card]->channel[arg].eazlist);
+		sc_adapter[card]->devicename, arg+1,
+		sc_adapter[card]->channel[arg].eazlist);
 	return 0;
 }
 
@@ -413,28 +414,28 @@
 
 	indicate_status(card, ISDN_STAT_STOP, 0, NULL);
 
-	if(adapter[card]->EngineUp) {
-		del_timer(&adapter[card]->stat_timer);	
+	if(sc_adapter[card]->EngineUp) {
+		del_timer(&sc_adapter[card]->stat_timer);
 	}
 
-	adapter[card]->EngineUp = 0;
+	sc_adapter[card]->EngineUp = 0;
 
-	spin_lock_irqsave(&adapter[card]->lock, flags);
-	init_timer(&adapter[card]->reset_timer);
-	adapter[card]->reset_timer.function = check_reset;
-	adapter[card]->reset_timer.data = card;
-	adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
-	add_timer(&adapter[card]->reset_timer);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
+	init_timer(&sc_adapter[card]->reset_timer);
+	sc_adapter[card]->reset_timer.function = check_reset;
+	sc_adapter[card]->reset_timer.data = card;
+	sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
+	add_timer(&sc_adapter[card]->reset_timer);
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 
-	outb(0x1,adapter[card]->ioport[SFT_RESET]); 
+	outb(0x1,sc_adapter[card]->ioport[SFT_RESET]);
 
-	pr_debug("%s: Adapter Reset\n", adapter[card]->devicename);
+	pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename);
 	return 0;
 }
 
 void flushreadfifo (int card)
 {
-	while(inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
-		inb(adapter[card]->ioport[FIFO_READ]);
+	while(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
+		inb(sc_adapter[card]->ioport[FIFO_READ]);
 }
--- diff/drivers/isdn/sc/event.c	2002-10-16 04:28:24.000000000 +0100
+++ source/drivers/isdn/sc/event.c	2004-02-18 09:03:59.000000000 +0000
@@ -21,7 +21,7 @@
 #include "card.h"
 
 extern int cinst;
-extern board *adapter[];
+extern board *sc_adapter[];
 
 #ifdef DEBUG
 static char *events[] = { "ISDN_STAT_STAVAIL",
@@ -46,9 +46,9 @@
 	isdn_ctrl cmd;
 
 	pr_debug("%s: Indicating event %s on Channel %d\n",
-		adapter[card]->devicename, events[event-256], Channel);
+		sc_adapter[card]->devicename, events[event-256], Channel);
 	if (Data != NULL){
-		pr_debug("%s: Event data: %s\n", adapter[card]->devicename,
+		pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename,
 			Data);
 		switch (event) {
 			case ISDN_STAT_BSENT:
@@ -63,7 +63,7 @@
 	}
 
 	cmd.command = event;
-	cmd.driver = adapter[card]->driverId;
+	cmd.driver = sc_adapter[card]->driverId;
 	cmd.arg = Channel;
-	return adapter[card]->card->statcallb(&cmd);
+	return sc_adapter[card]->card->statcallb(&cmd);
 }
--- diff/drivers/isdn/sc/hardware.h	2002-10-16 04:29:04.000000000 +0100
+++ source/drivers/isdn/sc/hardware.h	2004-02-18 09:03:59.000000000 +0000
@@ -108,6 +108,6 @@
 #define milliseconds(x)	(x/(1000/HZ))
 
 /* Determine if a channel number is valid for the adapter */
-#define IS_VALID_CHANNEL(y,x)	((x>0) && (x <= adapter[y]->channels))
+#define IS_VALID_CHANNEL(y,x)	((x>0) && (x <= sc_adapter[y]->channels))
 
 #endif
--- diff/drivers/isdn/sc/init.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/sc/init.c	2004-02-18 09:03:59.000000000 +0000
@@ -19,7 +19,7 @@
 MODULE_PARM(ram, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(do_reset, "i");
 
-board *adapter[MAX_CARDS];
+board *sc_adapter[MAX_CARDS];
 int cinst;
 
 static char devname[] = "scX";
@@ -305,78 +305,84 @@
 		/*
 		 * Allocate the board structure
 		 */
-		adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
-		if (adapter[cinst] == NULL) {
+		sc_adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
+		if (sc_adapter[cinst] == NULL) {
 			/*
 			 * Oops, can't alloc memory for the board
 			 */
 			kfree(interface);
 			continue;
 		}
-		memset(adapter[cinst], 0, sizeof(board));
-		spin_lock_init(&adapter[cinst]->lock);
+		memset(sc_adapter[cinst], 0, sizeof(board));
+		spin_lock_init(&sc_adapter[cinst]->lock);
 
 		if(!register_isdn(interface)) {
 			/*
 			 * Oops, couldn't register for some reason
 			 */
 			kfree(interface);
-			kfree(adapter[cinst]);
+			kfree(sc_adapter[cinst]);
 			continue;
 		}
 
-		adapter[cinst]->card = interface;
-		adapter[cinst]->driverId = interface->channels;
-		strcpy(adapter[cinst]->devicename, interface->id);
-		adapter[cinst]->nChannels = channels;
-		adapter[cinst]->ramsize = memsize;
-		adapter[cinst]->shmem_magic = magic;
-		adapter[cinst]->shmem_pgport = pgport;
-		adapter[cinst]->StartOnReset = 1;
+		sc_adapter[cinst]->card = interface;
+		sc_adapter[cinst]->driverId = interface->channels;
+		strcpy(sc_adapter[cinst]->devicename, interface->id);
+		sc_adapter[cinst]->nChannels = channels;
+		sc_adapter[cinst]->ramsize = memsize;
+		sc_adapter[cinst]->shmem_magic = magic;
+		sc_adapter[cinst]->shmem_pgport = pgport;
+		sc_adapter[cinst]->StartOnReset = 1;
 
 		/*
 		 * Allocate channels status structures
 		 */
-		adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
-		if (adapter[cinst]->channel == NULL) {
+		sc_adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
+		if (sc_adapter[cinst]->channel == NULL) {
 			/*
 			 * Oops, can't alloc memory for the channels
 			 */
 			indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL);	/* Fix me */
 			kfree(interface);
-			kfree(adapter[cinst]);
+			kfree(sc_adapter[cinst]);
 			continue;
 		}
-		memset(adapter[cinst]->channel, 0, sizeof(bchan) * channels);
+		memset(sc_adapter[cinst]->channel, 0, sizeof(bchan) * channels);
 
 		/*
 		 * Lock down the hardware resources
 		 */
-		adapter[cinst]->interrupt = irq[b];
-		if (request_irq(adapter[cinst]->interrupt, interrupt_handler, SA_INTERRUPT, 
-			interface->id, NULL))
+		sc_adapter[cinst]->interrupt = irq[b];
+		if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
+				SA_INTERRUPT, interface->id, NULL))
 		{
-			kfree(adapter[cinst]->channel);
+			kfree(sc_adapter[cinst]->channel);
 			indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL);	/* Fix me */
 			kfree(interface);
-			kfree(adapter[cinst]);
+			kfree(sc_adapter[cinst]);
 			continue;
 			
 		}
-		adapter[cinst]->iobase = io[b];
+		sc_adapter[cinst]->iobase = io[b];
 		for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
-			adapter[cinst]->ioport[i] = io[b] + i * 0x400;
-			request_region(adapter[cinst]->ioport[i], 1, interface->id);
-			pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[i]);
-		}
-		adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
-		request_region(adapter[cinst]->ioport[IRQ_SELECT], 1, interface->id);
-		pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[IRQ_SELECT]);
-		adapter[cinst]->rambase = ram[b];
-		request_region(adapter[cinst]->rambase, SRAM_PAGESIZE, interface->id);
+			sc_adapter[cinst]->ioport[i] = io[b] + i * 0x400;
+			request_region(sc_adapter[cinst]->ioport[i], 1,
+					interface->id);
+			pr_debug("Requesting I/O Port %#x\n",
+				sc_adapter[cinst]->ioport[i]);
+		}
+		sc_adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
+		request_region(sc_adapter[cinst]->ioport[IRQ_SELECT], 1,
+				interface->id);
+		pr_debug("Requesting I/O Port %#x\n",
+				sc_adapter[cinst]->ioport[IRQ_SELECT]);
+		sc_adapter[cinst]->rambase = ram[b];
+		request_region(sc_adapter[cinst]->rambase, SRAM_PAGESIZE,
+				interface->id);
 
 		pr_info("  %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n", 
-			adapter[cinst]->devicename, adapter[cinst]->driverId, 
+			sc_adapter[cinst]->devicename,
+			sc_adapter[cinst]->driverId,
 			boardname[model], channels, irq[b], io[b], ram[b]);
 		
 		/*
@@ -401,8 +407,8 @@
 		/*
 		 * kill the timers
 		 */
-		del_timer(&(adapter[i]->reset_timer));
-		del_timer(&(adapter[i]->stat_timer));
+		del_timer(&(sc_adapter[i]->reset_timer));
+		del_timer(&(sc_adapter[i]->stat_timer));
 
 		/*
 		 * Tell I4L we're toast
@@ -413,34 +419,36 @@
 		/*
 		 * Release shared RAM
 		 */
-		release_region(adapter[i]->rambase, SRAM_PAGESIZE);
+		release_region(sc_adapter[i]->rambase, SRAM_PAGESIZE);
 
 		/*
 		 * Release the IRQ
 		 */
-		FREE_IRQ(adapter[i]->interrupt, NULL);
+		FREE_IRQ(sc_adapter[i]->interrupt, NULL);
 
 		/*
 		 * Reset for a clean start
 		 */
-		outb(0xFF, adapter[i]->ioport[SFT_RESET]);
+		outb(0xFF, sc_adapter[i]->ioport[SFT_RESET]);
 
 		/*
 		 * Release the I/O Port regions
 		 */
 		for(j = 0 ; j < MAX_IO_REGS - 1; j++) {
-			release_region(adapter[i]->ioport[j], 1);
-			pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[j]);
-		}
-		release_region(adapter[i]->ioport[IRQ_SELECT], 1);
-		pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[IRQ_SELECT]);
+			release_region(sc_adapter[i]->ioport[j], 1);
+			pr_debug("Releasing I/O Port %#x\n",
+				sc_adapter[i]->ioport[j]);
+		}
+		release_region(sc_adapter[i]->ioport[IRQ_SELECT], 1);
+		pr_debug("Releasing I/O Port %#x\n",
+			sc_adapter[i]->ioport[IRQ_SELECT]);
 
 		/*
 		 * Release any memory we alloced
 		 */
-		kfree(adapter[i]->channel);
-		kfree(adapter[i]->card);
-		kfree(adapter[i]);
+		kfree(sc_adapter[i]->channel);
+		kfree(sc_adapter[i]->card);
+		kfree(sc_adapter[i]);
 	}
 	pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
 }
--- diff/drivers/isdn/sc/interrupt.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/sc/interrupt.c	2004-02-18 09:03:59.000000000 +0000
@@ -29,14 +29,14 @@
 extern void rcvpkt(int, RspMessage *);
 
 extern int cinst;
-extern board *adapter[];
+extern board *sc_adapter[];
 
 int get_card_from_irq(int irq)
 {
 	int i;
 
 	for(i = 0 ; i < cinst ; i++) {
-		if(adapter[i]->interrupt == irq)
+		if(sc_adapter[i]->interrupt == irq)
 			return i;
 	}
 	return -1;
@@ -59,7 +59,8 @@
 		return IRQ_NONE;
 	}
 
-	pr_debug("%s: Entered Interrupt handler\n", adapter[card]->devicename);
+	pr_debug("%s: Entered Interrupt handler\n",
+			sc_adapter[card]->devicename);
 	
  	/*
 	 * Pull all of the waiting messages off the response queue
@@ -69,8 +70,9 @@
 		 * Push the message to the adapter structure for
 		 * send_and_receive to snoop
 		 */
-		if(adapter[card]->want_async_messages)
-			memcpy(&(adapter[card]->async_msg), &rcvmsg, sizeof(RspMessage));
+		if(sc_adapter[card]->want_async_messages)
+			memcpy(&(sc_adapter[card]->async_msg),
+					&rcvmsg, sizeof(RspMessage));
 
 		channel = (unsigned int) rcvmsg.phy_link_no;
 		
@@ -79,7 +81,8 @@
 		 */
 		if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
 			pr_debug("%s: Invalid request Message, rsp_status = %d\n", 
-				adapter[card]->devicename, rcvmsg.rsp_status);
+				sc_adapter[card]->devicename,
+				rcvmsg.rsp_status);
 			break;	
 		}
 		
@@ -89,7 +92,7 @@
 		if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
 		{
 			pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
-						adapter[card]->devicename,
+						sc_adapter[card]->devicename,
 						rcvmsg.msg_data.response.msg_len,
 						rcvmsg.msg_data.response.buff_offset);
 			rcvpkt(card, &rcvmsg);
@@ -101,9 +104,10 @@
 		 * Handle a write acknoledgement
 		 */
 		if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
-			pr_debug("%s: Packet Send ACK on channel %d\n", adapter[card]->devicename,
+			pr_debug("%s: Packet Send ACK on channel %d\n",
+				sc_adapter[card]->devicename,
 				rcvmsg.phy_link_no);
-			adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
+			sc_adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
 			continue;
 		}
 
@@ -115,7 +119,7 @@
 			unsigned int callid;
 			setup_parm setup;	
 			pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
-						adapter[card]->devicename,
+						sc_adapter[card]->devicename,
 						rcvmsg.phy_link_no,
 						rcvmsg.rsp_status,
 						rcvmsg.msg_data.byte_array[2]);
@@ -123,16 +127,19 @@
 			memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
 			if(callid>=0x8000 && callid<=0xFFFF)
 			{		
-				pr_debug("%s: Got Dial-Out Rsp\n", adapter[card]->devicename);	
+				pr_debug("%s: Got Dial-Out Rsp\n",
+					sc_adapter[card]->devicename);
 				indicate_status(card, ISDN_STAT_DCONN,
 						(unsigned long)rcvmsg.phy_link_no-1,NULL);
 				
 			}
 			else if(callid>=0x0000 && callid<=0x7FFF)
 			{
-				pr_debug("%s: Got Incoming Call\n", adapter[card]->devicename);	
+				pr_debug("%s: Got Incoming Call\n",
+						sc_adapter[card]->devicename);
 				strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
-				strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
+				strcpy(setup.eazmsn,
+					sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
 				setup.si1 = 7;
 				setup.si2 = 0;
 				setup.plan = 0;
@@ -150,7 +157,7 @@
 		if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect)) 
 		{
 			pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
-						adapter[card]->devicename,
+						sc_adapter[card]->devicename,
 						rcvmsg.phy_link_no,
 						rcvmsg.rsp_status,
 					 	rcvmsg.msg_data.byte_array[2]);
@@ -165,15 +172,16 @@
 		 * Handle a startProc engine up message
 		 */
 		if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
-			pr_debug("%s: Received EngineUp message\n", adapter[card]->devicename);
-			adapter[card]->EngineUp = 1;
+			pr_debug("%s: Received EngineUp message\n",
+				sc_adapter[card]->devicename);
+			sc_adapter[card]->EngineUp = 1;
 			sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
 			sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
-			init_timer(&adapter[card]->stat_timer);
-			adapter[card]->stat_timer.function = check_phystat;
-			adapter[card]->stat_timer.data = card;
-			adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
-			add_timer(&adapter[card]->stat_timer);
+			init_timer(&sc_adapter[card]->stat_timer);
+			sc_adapter[card]->stat_timer.function = check_phystat;
+			sc_adapter[card]->stat_timer.data = card;
+			sc_adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
+			add_timer(&sc_adapter[card]->stat_timer);
 			continue;
 		}
 
@@ -181,7 +189,8 @@
 		 * Start proc response
 		 */
 		if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
-			pr_debug("%s: StartProc Response Status %d\n", adapter[card]->devicename,
+			pr_debug("%s: StartProc Response Status %d\n",
+				sc_adapter[card]->devicename,
 				rcvmsg.rsp_status);
 			continue;
 		}
@@ -190,7 +199,7 @@
 		 * Handle a GetMyNumber Rsp
 		 */
 		if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
-			strcpy(adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
+			strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
 			continue;
 		}
 			
@@ -206,9 +215,10 @@
 			b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
 			b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
 
-			adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
-			pr_debug("%s: PhyStat is 0x%2x\n", adapter[card]->devicename,
-				adapter[card]->nphystat);
+			sc_adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
+			pr_debug("%s: PhyStat is 0x%2x\n",
+				sc_adapter[card]->devicename,
+				sc_adapter[card]->nphystat);
 			continue;
 		}
 
@@ -223,7 +233,7 @@
 				 * Set board format to HDLC if it wasn't already
 				 */
 				pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
-						adapter[card]->devicename,
+						sc_adapter[card]->devicename,
 					rcvmsg.msg_data.byte_array[0]);
 				sendmessage(card, CEPID, ceReqTypeCall,
 						ceReqClass0,
@@ -238,11 +248,13 @@
 		 * Hmm...
 		 */
 		pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
-			adapter[card]->devicename, rcvmsg.type, rcvmsg.class, rcvmsg.code, 
+			sc_adapter[card]->devicename,
+			rcvmsg.type, rcvmsg.class, rcvmsg.code,
 			rcvmsg.phy_link_no);
 
 	}	/* while */
 
-	pr_debug("%s: Exiting Interrupt Handler\n", adapter[card]->devicename);
+	pr_debug("%s: Exiting Interrupt Handler\n",
+			sc_adapter[card]->devicename);
 	return IRQ_HANDLED;
 }
--- diff/drivers/isdn/sc/ioctl.c	2002-10-16 04:28:23.000000000 +0100
+++ source/drivers/isdn/sc/ioctl.c	2004-02-18 09:03:59.000000000 +0000
@@ -20,7 +20,7 @@
 		unsigned char,unsigned char, 
 		unsigned char, unsigned char *, RspMessage *, int);
 
-extern board *adapter[];
+extern board *sc_adapter[];
 
 
 int GetStatus(int card, boardInfo *);
@@ -33,8 +33,9 @@
 	switch(data->command) {
 	case SCIOCRESET:	/* Perform a hard reset of the adapter */
 	{
-		pr_debug("%s: SCIOCRESET: ioctl received\n", adapter[card]->devicename);
-		adapter[card]->StartOnReset = 0;
+		pr_debug("%s: SCIOCRESET: ioctl received\n",
+			sc_adapter[card]->devicename);
+		sc_adapter[card]->StartOnReset = 0;
 		return (reset(card));
 	}
 
@@ -44,10 +45,11 @@
 		char		srec[SCIOC_SRECSIZE];
 		int		status;
 
-		pr_debug("%s: SCIOLOAD: ioctl received\n", adapter[card]->devicename);
-		if(adapter[card]->EngineUp) {
+		pr_debug("%s: SCIOLOAD: ioctl received\n",
+				sc_adapter[card]->devicename);
+		if(sc_adapter[card]->EngineUp) {
 			pr_debug("%s: SCIOCLOAD: command failed, LoadProc while engine running.\n",
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return -1;
 		}
 
@@ -61,25 +63,27 @@
 				0, sizeof(srec), srec, &rcvmsg, SAR_TIMEOUT);
 		if(status) {
 			pr_debug("%s: SCIOCLOAD: command failed, status = %d\n", 
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return -1;
 		}
 		else {
-			pr_debug("%s: SCIOCLOAD: command successful\n", adapter[card]->devicename);
+			pr_debug("%s: SCIOCLOAD: command successful\n",
+					sc_adapter[card]->devicename);
 			return 0;
 		}
 	}
 
 	case SCIOCSTART:
 	{
-		pr_debug("%s: SCIOSTART: ioctl received\n", adapter[card]->devicename);
-		if(adapter[card]->EngineUp) {
+		pr_debug("%s: SCIOSTART: ioctl received\n",
+				sc_adapter[card]->devicename);
+		if(sc_adapter[card]->EngineUp) {
 			pr_debug("%s: SCIOCSTART: command failed, engine already running.\n",
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return -1;
 		}
 
-		adapter[card]->StartOnReset = 1;
+		sc_adapter[card]->StartOnReset = 1;
 		startproc(card);
 		return 0;
 	}
@@ -90,7 +94,8 @@
 		char		switchtype;
 		int 		status;
 
-		pr_debug("%s: SCIOSETSWITCH: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOSETSWITCH: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the switch type from user space
@@ -99,17 +104,19 @@
 				   sizeof(char)))
 			return -EFAULT;
 
-		pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n", adapter[card]->devicename,
+		pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n",
+			sc_adapter[card]->devicename,
 			switchtype);
 		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
 						0, sizeof(char),&switchtype,&rcvmsg, SAR_TIMEOUT);
 		if(!status && !rcvmsg.rsp_status) {
-			pr_debug("%s: SCIOCSETSWITCH: command successful\n", adapter[card]->devicename);
+			pr_debug("%s: SCIOCSETSWITCH: command successful\n",
+				sc_adapter[card]->devicename);
 			return 0;
 		}
 		else {
 			pr_debug("%s: SCIOCSETSWITCH: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 	}
@@ -120,7 +127,8 @@
 		char		switchtype;
 		int		status;
 
-		pr_debug("%s: SCIOGETSWITCH: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOGETSWITCH: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the switch type from the board
@@ -128,11 +136,12 @@
 		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
 			ceReqCallGetSwitchType, 0, 0, 0, &rcvmsg, SAR_TIMEOUT);
 		if (!status && !rcvmsg.rsp_status) {
-			pr_debug("%s: SCIOCGETSWITCH: command successful\n", adapter[card]->devicename);
+			pr_debug("%s: SCIOCGETSWITCH: command successful\n",
+					sc_adapter[card]->devicename);
 		}
 		else {
 			pr_debug("%s: SCIOCGETSWITCH: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 
@@ -154,7 +163,8 @@
 		char		spid[SCIOC_SPIDSIZE];
 		int		status;
 
-		pr_debug("%s: SCIOGETSPID: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOGETSPID: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the spid from the board
@@ -162,11 +172,12 @@
 		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
 					data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
 		if (!status) {
-			pr_debug("%s: SCIOCGETSPID: command successful\n", adapter[card]->devicename);
+			pr_debug("%s: SCIOCGETSPID: command successful\n",
+					sc_adapter[card]->devicename);
 		}
 		else {
 			pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 		strcpy(spid, rcvmsg.msg_data.byte_array);
@@ -186,7 +197,8 @@
 		char		spid[SCIOC_SPIDSIZE];
 		int 		status;
 
-		pr_debug("%s: DCBIOSETSPID: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: DCBIOSETSPID: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the spid from user space
@@ -195,18 +207,18 @@
 			return -EFAULT;
 
 		pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n", 
-			adapter[card]->devicename, data->channel, spid);
+			sc_adapter[card]->devicename, data->channel, spid);
 		status = send_and_receive(card, CEPID, ceReqTypeCall, 
 			ceReqClass0, ceReqCallSetSPID, data->channel, 
 			strlen(spid), spid, &rcvmsg, SAR_TIMEOUT);
 		if(!status && !rcvmsg.rsp_status) {
 			pr_debug("%s: SCIOCSETSPID: command successful\n", 
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return 0;
 		}
 		else {
 			pr_debug("%s: SCIOCSETSPID: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 	}
@@ -217,7 +229,8 @@
 		char		dn[SCIOC_DNSIZE];
 		int		status;
 
-		pr_debug("%s: SCIOGETDN: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOGETDN: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the dn from the board
@@ -225,11 +238,12 @@
 		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
 					data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
 		if (!status) {
-			pr_debug("%s: SCIOCGETDN: command successful\n", adapter[card]->devicename);
+			pr_debug("%s: SCIOCGETDN: command successful\n",
+					sc_adapter[card]->devicename);
 		}
 		else {
 			pr_debug("%s: SCIOCGETDN: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 
@@ -250,7 +264,8 @@
 		char		dn[SCIOC_DNSIZE];
 		int 		status;
 
-		pr_debug("%s: SCIOSETDN: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOSETDN: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the spid from user space
@@ -259,35 +274,38 @@
 			return -EFAULT;
 
 		pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n", 
-			adapter[card]->devicename, data->channel, dn);
+			sc_adapter[card]->devicename, data->channel, dn);
 		status = send_and_receive(card, CEPID, ceReqTypeCall, 
 			ceReqClass0, ceReqCallSetMyNumber, data->channel, 
 			strlen(dn),dn,&rcvmsg, SAR_TIMEOUT);
 		if(!status && !rcvmsg.rsp_status) {
 			pr_debug("%s: SCIOCSETDN: command successful\n", 
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return 0;
 		}
 		else {
 			pr_debug("%s: SCIOCSETDN: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 	}
 
 	case SCIOCTRACE:
 
-		pr_debug("%s: SCIOTRACE: ioctl received\n", adapter[card]->devicename);
-/*		adapter[card]->trace = !adapter[card]->trace; 
-		pr_debug("%s: SCIOCTRACE: tracing turned %s\n", adapter[card]->devicename,
-			adapter[card]->trace ? "ON" : "OFF"); */
+		pr_debug("%s: SCIOTRACE: ioctl received\n",
+				sc_adapter[card]->devicename);
+/*		sc_adapter[card]->trace = !sc_adapter[card]->trace;
+		pr_debug("%s: SCIOCTRACE: tracing turned %s\n",
+				sc_adapter[card]->devicename,
+			sc_adapter[card]->trace ? "ON" : "OFF"); */
 		break;
 
 	case SCIOCSTAT:
 	{
 		boardInfo bi;
 
-		pr_debug("%s: SCIOSTAT: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOSTAT: ioctl received\n",
+				sc_adapter[card]->devicename);
 		GetStatus(card, &bi);
 		
 		if (copy_to_user((boardInfo *)data->dataptr, &bi,
@@ -303,7 +321,8 @@
 		char		speed;
 		int		status;
 
-		pr_debug("%s: SCIOGETSPEED: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOGETSPEED: ioctl received\n",
+				sc_adapter[card]->devicename);
 
 		/*
 		 * Get the speed from the board
@@ -312,11 +331,11 @@
 			ceReqCallGetCallType, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
 		if (!status && !rcvmsg.rsp_status) {
 			pr_debug("%s: SCIOCGETSPEED: command successful\n",
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 		}
 		else {
 			pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n",
-				adapter[card]->devicename, status);
+				sc_adapter[card]->devicename, status);
 			return status;
 		}
 
@@ -332,11 +351,13 @@
 	}
 
 	case SCIOCSETSPEED:
-		pr_debug("%s: SCIOCSETSPEED: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOCSETSPEED: ioctl received\n",
+				sc_adapter[card]->devicename);
 		break;
 
 	case SCIOCLOOPTST:
-		pr_debug("%s: SCIOCLOOPTST: ioctl received\n", adapter[card]->devicename);
+		pr_debug("%s: SCIOCLOOPTST: ioctl received\n",
+				sc_adapter[card]->devicename);
 		break;
 
 	default:
@@ -354,16 +375,16 @@
 	/*
 	 * Fill in some of the basic info about the board
 	 */
-	bi->modelid = adapter[card]->model;
-	strcpy(bi->serial_no, adapter[card]->hwconfig.serial_no);
-	strcpy(bi->part_no, adapter[card]->hwconfig.part_no);
-	bi->iobase = adapter[card]->iobase;
-	bi->rambase = adapter[card]->rambase;
-	bi->irq = adapter[card]->interrupt;
-	bi->ramsize = adapter[card]->hwconfig.ram_size;
-	bi->interface = adapter[card]->hwconfig.st_u_sense;
-	strcpy(bi->load_ver, adapter[card]->load_ver);
-	strcpy(bi->proc_ver, adapter[card]->proc_ver);
+	bi->modelid = sc_adapter[card]->model;
+	strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no);
+	strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no);
+	bi->iobase = sc_adapter[card]->iobase;
+	bi->rambase = sc_adapter[card]->rambase;
+	bi->irq = sc_adapter[card]->interrupt;
+	bi->ramsize = sc_adapter[card]->hwconfig.ram_size;
+	bi->interface = sc_adapter[card]->hwconfig.st_u_sense;
+	strcpy(bi->load_ver, sc_adapter[card]->load_ver);
+	strcpy(bi->proc_ver, sc_adapter[card]->proc_ver);
 
 	/*
 	 * Get the current PhyStats and LnkStats
@@ -371,7 +392,7 @@
 	status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
 		ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
 	if(!status) {
-		if(adapter[card]->model < PRI_BOARD) {
+		if(sc_adapter[card]->model < PRI_BOARD) {
 			bi->l1_status = rcvmsg.msg_data.byte_array[2];
 			for(i = 0 ; i < BRI_CHANNELS ; i++)
 				bi->status.bristats[i].phy_stat =
@@ -389,11 +410,11 @@
 	/*
 	 * Get the call types for each channel
 	 */
-	for (i = 0 ; i < adapter[card]->nChannels ; i++) {
+	for (i = 0 ; i < sc_adapter[card]->nChannels ; i++) {
 		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
 			ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
 		if(!status) {
-			if (adapter[card]->model == PRI_BOARD) {
+			if (sc_adapter[card]->model == PRI_BOARD) {
 				bi->status.pristats[i].call_type = 
 					rcvmsg.msg_data.byte_array[0];
 			}
@@ -407,7 +428,7 @@
 	/*
 	 * If PRI, get the call states and service states for each channel
 	 */
-	if (adapter[card]->model == PRI_BOARD) {
+	if (sc_adapter[card]->model == PRI_BOARD) {
 		/*
 		 * Get the call states
 		 */
--- diff/drivers/isdn/sc/message.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/sc/message.c	2004-02-18 09:03:59.000000000 +0000
@@ -22,7 +22,7 @@
 #include "message.h"
 #include "card.h"
 
-extern board *adapter[];
+extern board *sc_adapter[];
 extern unsigned int cinst;
 
 /*
@@ -46,31 +46,32 @@
 		return -EINVAL;
 	}
 	
-	pr_debug("%s: Entered receivemessage\n",adapter[card]->devicename);
+	pr_debug("%s: Entered receivemessage\n",
+			sc_adapter[card]->devicename);
 
 	/*
 	 * See if there are messages waiting
 	 */
-	if (inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
+	if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
 		/*
 		 * Map in the DPM to the base page and copy the message
 		 */
-		spin_lock_irqsave(&adapter[card]->lock, flags);
-		outb((adapter[card]->shmem_magic >> 14) | 0x80,
-			adapter[card]->ioport[adapter[card]->shmem_pgport]); 
-		dpm = (DualPortMemory *) adapter[card]->rambase;
+		spin_lock_irqsave(&sc_adapter[card]->lock, flags);
+		outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
+			sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
+		dpm = (DualPortMemory *) sc_adapter[card]->rambase;
 		memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), 
 			MSG_LEN);
 		dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
-		inb(adapter[card]->ioport[FIFO_READ]);
-		spin_unlock_irqrestore(&adapter[card]->lock, flags);
+		inb(sc_adapter[card]->ioport[FIFO_READ]);
+		spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 		/*
 		 * Tell the board that the message is received
 		 */
 		pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
 				"cnt:%d (type,class,code):(%d,%d,%d) "
 				"link:%d stat:0x%x\n",
-					adapter[card]->devicename,
+					sc_adapter[card]->devicename,
 					rspmsg->sequence_no,
 					rspmsg->process_id,
 					rspmsg->time_stamp,
@@ -112,15 +113,15 @@
 	 * Make sure we only send CEPID messages when the engine is up
 	 * and CMPID messages when it is down
 	 */
-	if(adapter[card]->EngineUp && procid == CMPID) {
+	if(sc_adapter[card]->EngineUp && procid == CMPID) {
 		pr_debug("%s: Attempt to send CM message with engine up\n",
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 		return -ESRCH;
 	}
 
-	if(!adapter[card]->EngineUp && procid == CEPID) {
+	if(!sc_adapter[card]->EngineUp && procid == CEPID) {
 		pr_debug("%s: Attempt to send CE message with engine down\n",
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 		return -ESRCH;
 	}
 
@@ -139,30 +140,30 @@
 	}
 
 	sndmsg.process_id = procid;
-	sndmsg.sequence_no = adapter[card]->seq_no++ % 256;
+	sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256;
 
 	/*
 	 * wait for an empty slot in the queue
 	 */
-	while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
+	while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
 		udelay(1);
 
 	/*
 	 * Disable interrupts and map in shared memory
 	 */
-	spin_lock_irqsave(&adapter[card]->lock, flags);
-	outb((adapter[card]->shmem_magic >> 14) | 0x80,
-		adapter[card]->ioport[adapter[card]->shmem_pgport]); 
-	dpm = (DualPortMemory *) adapter[card]->rambase;	/* Fix me */
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
+	outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
+		sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
+	dpm = (DualPortMemory *) sc_adapter[card]->rambase;	/* Fix me */
 	memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
 	dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
-	outb(sndmsg.sequence_no, adapter[card]->ioport[FIFO_WRITE]);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
+	outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]);
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 		
 	pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
 			"cnt:%d (type,class,code):(%d,%d,%d) "
 			"link:%d\n ",
-				adapter[card]->devicename,
+				sc_adapter[card]->devicename,
 				sndmsg.sequence_no,
 				sndmsg.process_id,
 				sndmsg.time_stamp,
@@ -194,14 +195,14 @@
 		return -EINVAL;
 	}
 
-	adapter[card]->want_async_messages = 1;
+	sc_adapter[card]->want_async_messages = 1;
 	retval = sendmessage(card, procid, type, class, code, link, 
 			data_len, (unsigned int *) data);
   
 	if (retval) {
 		pr_debug("%s: SendMessage failed in SAR\n",
-			adapter[card]->devicename);
-		adapter[card]->want_async_messages = 0;
+			sc_adapter[card]->devicename);
+		sc_adapter[card]->want_async_messages = 0;
 		return -EIO;
 	}
 
@@ -216,26 +217,26 @@
 		/*
 		 * See if we got our message back
 		 */
-		if ((adapter[card]->async_msg.type == type) &&
-		    (adapter[card]->async_msg.class == class) &&
-		    (adapter[card]->async_msg.code == code) &&
-		    (adapter[card]->async_msg.phy_link_no == link)) {
+		if ((sc_adapter[card]->async_msg.type == type) &&
+		    (sc_adapter[card]->async_msg.class == class) &&
+		    (sc_adapter[card]->async_msg.code == code) &&
+		    (sc_adapter[card]->async_msg.phy_link_no == link)) {
 
 			/*
 			 * Got it!
 			 */
 			pr_debug("%s: Got ASYNC message\n",
-				adapter[card]->devicename);
-			memcpy(mesgdata, &(adapter[card]->async_msg), 
+				sc_adapter[card]->devicename);
+			memcpy(mesgdata, &(sc_adapter[card]->async_msg),
 				sizeof(RspMessage));
-			adapter[card]->want_async_messages = 0;
+			sc_adapter[card]->want_async_messages = 0;
 			return 0;
 		}
 
    		tries++;
 	}
 
-	pr_debug("%s: SAR message timeout\n", adapter[card]->devicename);
-	adapter[card]->want_async_messages = 0;
+	pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename);
+	sc_adapter[card]->want_async_messages = 0;
 	return -ETIME;
 }
--- diff/drivers/isdn/sc/packet.c	2002-10-16 04:29:06.000000000 +0100
+++ source/drivers/isdn/sc/packet.c	2004-02-18 09:03:59.000000000 +0000
@@ -20,7 +20,7 @@
 #include "message.h"
 #include "card.h"
 
-extern board *adapter[];
+extern board *sc_adapter[];
 extern unsigned int cinst;
 
 extern int get_card_from_id(int);
@@ -45,26 +45,29 @@
 	}
 
 	pr_debug("%s: sndpkt: frst = 0x%x nxt = %d  f = %d n = %d\n",
-		adapter[card]->devicename,
-		adapter[card]->channel[channel].first_sendbuf,
-		adapter[card]->channel[channel].next_sendbuf,
-		adapter[card]->channel[channel].free_sendbufs,
-		adapter[card]->channel[channel].num_sendbufs);
-
-	if(!adapter[card]->channel[channel].free_sendbufs) {
-		pr_debug("%s: out of TX buffers\n", adapter[card]->devicename);
+		sc_adapter[card]->devicename,
+		sc_adapter[card]->channel[channel].first_sendbuf,
+		sc_adapter[card]->channel[channel].next_sendbuf,
+		sc_adapter[card]->channel[channel].free_sendbufs,
+		sc_adapter[card]->channel[channel].num_sendbufs);
+
+	if(!sc_adapter[card]->channel[channel].free_sendbufs) {
+		pr_debug("%s: out of TX buffers\n",
+				sc_adapter[card]->devicename);
 		return -EINVAL;
 	}
 
 	if(data->len > BUFFER_SIZE) {
-		pr_debug("%s: data overflows buffer size (data > buffer)\n", adapter[card]->devicename);
+		pr_debug("%s: data overflows buffer size (data > buffer)\n",
+			sc_adapter[card]->devicename);
 		return -EINVAL;
 	}
 
-	ReqLnkWrite.buff_offset = adapter[card]->channel[channel].next_sendbuf *
-		BUFFER_SIZE + adapter[card]->channel[channel].first_sendbuf;
+	ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf *
+		BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf;
 	ReqLnkWrite.msg_len = data->len; /* sk_buff size */
-	pr_debug("%s: writing %d bytes to buffer offset 0x%x\n", adapter[card]->devicename,
+	pr_debug("%s: writing %d bytes to buffer offset 0x%x\n",
+			sc_adapter[card]->devicename,
 			ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
 	memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
 
@@ -72,24 +75,25 @@
 	 * sendmessage
 	 */
 	pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n",
-		adapter[card]->devicename,
+		sc_adapter[card]->devicename,
 		ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
-		adapter[card]->channel[channel].next_sendbuf);
+		sc_adapter[card]->channel[channel].next_sendbuf);
 
 	status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
 				channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
 	len = data->len;
 	if(status) {
-		pr_debug("%s: failed to send packet, status = %d\n", adapter[card]->devicename, status);
+		pr_debug("%s: failed to send packet, status = %d\n",
+				sc_adapter[card]->devicename, status);
 		return -1;
 	}
 	else {
-		adapter[card]->channel[channel].free_sendbufs--;
-		adapter[card]->channel[channel].next_sendbuf =
-			++adapter[card]->channel[channel].next_sendbuf ==
-			adapter[card]->channel[channel].num_sendbufs ? 0 :
-			adapter[card]->channel[channel].next_sendbuf;
-			pr_debug("%s: packet sent successfully\n", adapter[card]->devicename);
+		sc_adapter[card]->channel[channel].free_sendbufs--;
+		sc_adapter[card]->channel[channel].next_sendbuf =
+			++sc_adapter[card]->channel[channel].next_sendbuf ==
+			sc_adapter[card]->channel[channel].num_sendbufs ? 0 :
+			sc_adapter[card]->channel[channel].next_sendbuf;
+			pr_debug("%s: packet sent successfully\n", sc_adapter[card]->devicename);
 		dev_kfree_skb(data);
 		indicate_status(card,ISDN_STAT_BSENT,channel, (char *)&len);
 	}
@@ -110,33 +114,37 @@
 	case 0x01:
 	case 0x02:
 	case 0x70:
-		pr_debug("%s: error status code: 0x%x\n", adapter[card]->devicename, rcvmsg->rsp_status);
+		pr_debug("%s: error status code: 0x%x\n",
+			sc_adapter[card]->devicename, rcvmsg->rsp_status);
 		return;
 	case 0x00: 
 	    if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) {
 			printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n",
-				adapter[card]->devicename);
+				sc_adapter[card]->devicename);
 			return;
 		}
 		skb_put(skb, rcvmsg->msg_data.response.msg_len);
 		pr_debug("%s: getting data from offset: 0x%x\n",
-			adapter[card]->devicename,rcvmsg->msg_data.response.buff_offset);
+			sc_adapter[card]->devicename,
+			rcvmsg->msg_data.response.buff_offset);
 		memcpy_fromshmem(card,
 			skb_put(skb, rcvmsg->msg_data.response.msg_len),
 		 	(char *)rcvmsg->msg_data.response.buff_offset,
 			rcvmsg->msg_data.response.msg_len);
-		adapter[card]->card->rcvcallb_skb(adapter[card]->driverId,
+		sc_adapter[card]->card->rcvcallb_skb(sc_adapter[card]->driverId,
 			rcvmsg->phy_link_no-1, skb);
 
 	case 0x03:
 		/*
 	 	 * Recycle the buffer
 	 	 */
-		pr_debug("%s: buffer size : %d\n", adapter[card]->devicename, BUFFER_SIZE);
+		pr_debug("%s: buffer size : %d\n",
+				sc_adapter[card]->devicename, BUFFER_SIZE);
 /*		memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
 		newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
 		newll.msg_len = BUFFER_SIZE;
-		pr_debug("%s: recycled buffer at offset 0x%x size %d\n", adapter[card]->devicename,
+		pr_debug("%s: recycled buffer at offset 0x%x size %d\n",
+			sc_adapter[card]->devicename,
 			newll.buff_offset, newll.msg_len);
 		sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
 			rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll);
@@ -158,40 +166,45 @@
 	/*
 	 * Calculate the buffer offsets (send/recv/send/recv)
 	 */
-	pr_debug("%s: setting up channel buffer space in shared RAM\n", adapter[card]->devicename);
+	pr_debug("%s: setting up channel buffer space in shared RAM\n",
+			sc_adapter[card]->devicename);
 	buffer_size = BUFFER_SIZE;
-	nBuffers = ((adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
+	nBuffers = ((sc_adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
 	nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers;
-	pr_debug("%s: calculating buffer space: %d buffers, %d big\n", adapter[card]->devicename,
+	pr_debug("%s: calculating buffer space: %d buffers, %d big\n",
+		sc_adapter[card]->devicename,
 		nBuffers, buffer_size);
 	if(nBuffers < 2) {
-		pr_debug("%s: not enough buffer space\n", adapter[card]->devicename);
+		pr_debug("%s: not enough buffer space\n",
+			sc_adapter[card]->devicename);
 		return -1;
 	}
 	cBase = (nBuffers * buffer_size) * (c - 1);
-	pr_debug("%s: channel buffer offset from shared RAM: 0x%x\n", adapter[card]->devicename, cBase);
-	adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
-	adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
-	adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
-	adapter[card]->channel[c-1].next_sendbuf = 0;
+	pr_debug("%s: channel buffer offset from shared RAM: 0x%x\n",
+			sc_adapter[card]->devicename, cBase);
+	sc_adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
+	sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
+	sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
+	sc_adapter[card]->channel[c-1].next_sendbuf = 0;
 	pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
-				adapter[card]->devicename,
-				adapter[card]->channel[c-1].first_sendbuf,
-				adapter[card]->channel[c-1].num_sendbufs,
-				adapter[card]->channel[c-1].free_sendbufs,
-				adapter[card]->channel[c-1].next_sendbuf);
+				sc_adapter[card]->devicename,
+				sc_adapter[card]->channel[c-1].first_sendbuf,
+				sc_adapter[card]->channel[c-1].num_sendbufs,
+				sc_adapter[card]->channel[c-1].free_sendbufs,
+				sc_adapter[card]->channel[c-1].next_sendbuf);
 
 	/*
 	 * Prep the receive buffers
 	 */
-	pr_debug("%s: adding %d RecvBuffers:\n", adapter[card]->devicename, nBuffers /2);
+	pr_debug("%s: adding %d RecvBuffers:\n",
+			sc_adapter[card]->devicename, nBuffers /2);
 	for (i = 0 ; i < nBuffers / 2; i++) {
 		RcvBuffOffset.buff_offset = 
-			((adapter[card]->channel[c-1].first_sendbuf +
+			((sc_adapter[card]->channel[c-1].first_sendbuf +
 			(nBuffers / 2) * buffer_size) + (buffer_size * i));
 		RcvBuffOffset.msg_len = buffer_size;
 		pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n",
-				adapter[card]->devicename,
+				sc_adapter[card]->devicename,
 				i + 1, RcvBuffOffset.buff_offset, 
 				RcvBuffOffset.msg_len,buffer_size);
 		sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
@@ -202,11 +215,11 @@
 
 int print_skb(int card,char *skb_p, int len){
 	int i,data;
-	pr_debug("%s: data at 0x%x len: 0x%x\n",adapter[card]->devicename,
+	pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename,
 			skb_p,len);
 	for(i=1;i<=len;i++,skb_p++){
 		data = (int) (0xff & (*skb_p));
-		pr_debug("%s: data =  0x%x",adapter[card]->devicename,data);
+		pr_debug("%s: data =  0x%x", sc_adapter[card]->devicename,data);
 		if(!(i%4))
 			pr_debug(" ");
 		if(!(i%32))
--- diff/drivers/isdn/sc/shmem.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/sc/shmem.c	2004-02-18 09:03:59.000000000 +0000
@@ -24,7 +24,7 @@
 /*
  * Main adapter array
  */
-extern board *adapter[];
+extern board *sc_adapter[];
 extern int cinst;
 
 /*
@@ -49,21 +49,23 @@
 	 * determine the page to load from the address
 	 */
 	ch = (unsigned long) dest / SRAM_PAGESIZE;
-	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+	pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
 	/*
 	 * Block interrupts and load the page
 	 */
-	spin_lock_irqsave(&adapter[card]->lock, flags);
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
 
-	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
-		adapter[card]->ioport[adapter[card]->shmem_pgport]);
-	ret = memcpy_toio(adapter[card]->rambase + 
+	outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
+	ret = memcpy_toio(sc_adapter[card]->rambase +
 		((unsigned long) dest % 0x4000), src, n);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
-	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
-		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
-	pr_debug("%s: copying %d bytes from %#x to %#x\n",adapter[card]->devicename, n,
-		 (unsigned long) src, adapter[card]->rambase + ((unsigned long) dest %0x4000));
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
+	pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
+		((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	pr_debug("%s: copying %d bytes from %#x to %#x\n",
+		sc_adapter[card]->devicename, n,
+		(unsigned long) src,
+		sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
 
 	return ret;
 }
@@ -90,24 +92,24 @@
 	 * determine the page to load from the address
 	 */
 	ch = (unsigned long) src / SRAM_PAGESIZE;
-	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+	pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
 	
 	
 	/*
 	 * Block interrupts and load the page
 	 */
-	spin_lock_irqsave(&adapter[card]->lock, flags);
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
 
-	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
-		adapter[card]->ioport[adapter[card]->shmem_pgport]);
-	ret = memcpy_fromio(dest,(void *)(adapter[card]->rambase + 
+	outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
+	ret = memcpy_fromio(dest,(void *)(sc_adapter[card]->rambase +
 		((unsigned long) src % 0x4000)), n);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
-	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
-		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
+	pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
+		((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
 /*	pr_debug("%s: copying %d bytes from %#x to %#x\n",
-		adapter[card]->devicename, n,
-		adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
+		sc_adapter[card]->devicename, n,
+		sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
 
 	return ret;
 }
@@ -131,20 +133,20 @@
 	 * determine the page to load from the address
 	 */
 	ch = (unsigned long) dest / SRAM_PAGESIZE;
-	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+	pr_debug("%s: loaded page %d\n",sc_adapter[card]->devicename,ch);
 
 	/*
 	 * Block interrupts and load the page
 	 */
-	spin_lock_irqsave(&adapter[card]->lock, flags);
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
 
-	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
-		adapter[card]->ioport[adapter[card]->shmem_pgport]);
-	ret = memset_io(adapter[card]->rambase + 
+	outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
+	ret = memset_io(sc_adapter[card]->rambase +
 		((unsigned long) dest % 0x4000), c, n);
-	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
-		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
+	pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
+		((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 
 	return ret;
 }
--- diff/drivers/isdn/sc/timer.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/sc/timer.c	2004-02-18 09:03:59.000000000 +0000
@@ -20,7 +20,7 @@
 #include "message.h"
 #include "card.h"
 
-extern board *adapter[];
+extern board *sc_adapter[];
 
 extern void flushreadfifo(int);
 extern int  startproc(int);
@@ -35,11 +35,11 @@
 void setup_ports(int card)
 {
 
-	outb((adapter[card]->rambase >> 12), adapter[card]->ioport[EXP_BASE]);
+	outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);
 
 	/* And the IRQ */
-	outb((adapter[card]->interrupt | 0x80), 
-		adapter[card]->ioport[IRQ_SELECT]);
+	outb((sc_adapter[card]->interrupt | 0x80),
+		sc_adapter[card]->ioport[IRQ_SELECT]);
 }
 
 /*
@@ -57,28 +57,29 @@
 	unsigned long sig;
 	int card = (unsigned int) data;
 
-	pr_debug("%s: check_timer timer called\n", adapter[card]->devicename);
+	pr_debug("%s: check_timer timer called\n",
+		sc_adapter[card]->devicename);
 
 	/* Setup the io ports */
 	setup_ports(card);
 
-	spin_lock_irqsave(&adapter[card]->lock, flags);
-	outb(adapter[card]->ioport[adapter[card]->shmem_pgport],
-		(adapter[card]->shmem_magic>>14) | 0x80);	
-	sig = (unsigned long) *((unsigned long *)(adapter[card]->rambase + SIG_OFFSET));	
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
+	outb(sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport],
+		(sc_adapter[card]->shmem_magic>>14) | 0x80);
+	sig = (unsigned long) *((unsigned long *)(sc_adapter[card]->rambase + SIG_OFFSET));
 
 	/* check the signature */
 	if(sig == SIGNATURE) {
 		flushreadfifo(card);
-		spin_unlock_irqrestore(&adapter[card]->lock, flags);
+		spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 		/* See if we need to do a startproc */
-		if (adapter[card]->StartOnReset)
+		if (sc_adapter[card]->StartOnReset)
 			startproc(card);
 	} else  {
 		pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
-			adapter[card]->devicename, CHECKRESET_TIME);
-		mod_timer(&adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
-		spin_unlock_irqrestore(&adapter[card]->lock, flags);
+			sc_adapter[card]->devicename, CHECKRESET_TIME);
+		mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
+		spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 	}
 }
 
@@ -87,7 +88,7 @@
  * Must be very fast as this function runs in the context of
  * an interrupt handler.
  *
- * Send check adapter->phystat to see if the channels are up
+ * Send check sc_adapter->phystat to see if the channels are up
  * If they are, tell ISDN4Linux that the board is up. If not,
  * tell IADN4Linux that it is up. Always reset the timer to
  * fire again (endless loop).
@@ -97,31 +98,31 @@
 	unsigned long flags;
 	int card = (unsigned int) data;
 
-	pr_debug("%s: Checking status...\n", adapter[card]->devicename);
+	pr_debug("%s: Checking status...\n", sc_adapter[card]->devicename);
 	/* 
 	 * check the results of the last PhyStat and change only if
 	 * has changed drastically
 	 */
-	if (adapter[card]->nphystat && !adapter[card]->phystat) {   /* All is well */
+	if (sc_adapter[card]->nphystat && !sc_adapter[card]->phystat) {   /* All is well */
 		pr_debug("PhyStat transition to RUN\n");
 		pr_info("%s: Switch contacted, transmitter enabled\n", 
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 		indicate_status(card, ISDN_STAT_RUN, 0, NULL);
 	}
-	else if (!adapter[card]->nphystat && adapter[card]->phystat) {   /* All is not well */
+	else if (!sc_adapter[card]->nphystat && sc_adapter[card]->phystat) {   /* All is not well */
 		pr_debug("PhyStat transition to STOP\n");
 		pr_info("%s: Switch connection lost, transmitter disabled\n", 
-			adapter[card]->devicename);
+			sc_adapter[card]->devicename);
 
 		indicate_status(card, ISDN_STAT_STOP, 0, NULL);
 	}
 
-	adapter[card]->phystat = adapter[card]->nphystat;
+	sc_adapter[card]->phystat = sc_adapter[card]->nphystat;
 
 	/* Reinitialize the timer */
-	spin_lock_irqsave(&adapter[card]->lock, flags);
-	mod_timer(&adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
-	spin_unlock_irqrestore(&adapter[card]->lock, flags);
+	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
+	mod_timer(&sc_adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
+	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
 
 	/* Send a new cePhyStatus message */
 	sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
--- diff/drivers/isdn/tpam/Kconfig	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/tpam/Kconfig	2004-02-18 09:03:59.000000000 +0000
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_TPAM
 	tristate "Auvertech TurboPAM support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && ISDN && PCI
+	depends on EXPERIMENTAL && ISDN_I4L && PCI
 	help
 	  This enables support for the Auvertech TurboPAM ISDN-card.
 	  For running this card, additional firmware is necessary, which has
--- diff/drivers/macintosh/macserial.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/macintosh/macserial.c	2004-02-18 09:04:00.000000000 +0000
@@ -1777,47 +1777,65 @@
 	return put_user(status,value);
 }
 
-static int get_modem_info(struct mac_serial *info, unsigned int *value)
+static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
 	unsigned char control, status;
-	unsigned int result;
 	unsigned long flags;
 
+#ifdef CONFIG_KGDB
+	if (info->kgdb_channel)
+		return -ENODEV;
+#endif
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
 	spin_lock_irqsave(&info->lock, flags);
 	control = info->curregs[5];
 	status = read_zsreg(info->zs_channel, 0);
 	spin_unlock_irqrestore(&info->lock, flags);
-	result =  ((control & RTS) ? TIOCM_RTS: 0)
+	return    ((control & RTS) ? TIOCM_RTS: 0)
 		| ((control & DTR) ? TIOCM_DTR: 0)
 		| ((status  & DCD) ? TIOCM_CAR: 0)
 		| ((status  & CTS) ? 0: TIOCM_CTS);
-	return put_user(result,value);
 }
 
-static int set_modem_info(struct mac_serial *info, unsigned int cmd,
-			  unsigned int *value)
+static int rs_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
 {
+	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
 	unsigned int arg, bits;
 	unsigned long flags;
 
-	if (get_user(arg, value))
-		return -EFAULT;
-	bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
-	spin_lock_irqsave(&info->lock, flags);
-	switch (cmd) {
-	case TIOCMBIS:
-		info->curregs[5] |= bits;
-		break;
-	case TIOCMBIC:
-		info->curregs[5] &= ~bits;
-		break;
-	case TIOCMSET:
-		info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
-		break;
-	default:
-		spin_unlock_irqrestore(&info->lock, flags);
-		return -EINVAL;
+#ifdef CONFIG_KGDB
+	if (info->kgdb_channel)
+		return -ENODEV;
+#endif
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
 	}
+
+	spin_lock_irqsave(&info->lock, flags);
+	if (set & TIOCM_RTS)
+		info->curregs[5] |= RTS;
+	if (set & TIOCM_DTR)
+		info->curregs[5] |= DTR;
+	if (clear & TIOCM_RTS)
+		info->curregs[5] &= ~RTS;
+	if (clear & TIOCM_DTR)
+		info->curregs[5] &= ~DTR;
+
 	info->pendregs[5] = info->curregs[5];
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	spin_unlock_irqrestore(&info->lock, flags);
@@ -1863,12 +1881,6 @@
 	}
 
 	switch (cmd) {
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
 			return get_serial_info(info,
 					(struct serial_struct __user *) arg);
@@ -2488,6 +2500,8 @@
 	.break_ctl = rs_break,
 	.wait_until_sent = rs_wait_until_sent,
 	.read_proc = macserial_read_proc,
+	.tiocmget = rs_tiocmget,
+	.tiocmset = rs_tiocmset,
 };
 
 static int macserial_init(void)
--- diff/drivers/macintosh/via-pmu.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/macintosh/via-pmu.c	2004-02-18 09:04:00.000000000 +0000
@@ -44,6 +44,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
+#include <linux/syscalls.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -2292,8 +2293,6 @@
 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 }
 
-extern long sys_sync(void);
-
 static int __pmac
 pmac_suspend_devices(void)
 {
--- diff/drivers/md/Kconfig	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/md/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -170,5 +170,23 @@
 	  Recent tools use a new version of the ioctl interface, only
           select this option if you intend using such tools.
 
+config DM_CRYPT
+	tristate "Crypt target support"
+	depends on BLK_DEV_DM && EXPERIMENTAL
+	select CRYPTO
+	---help---
+	  This device-mapper target allows you to create a device that
+	  transparently encrypts the data on it. You'll need to activate
+	  the ciphers you're going to use in the cryptoapi configuration.
+
+	  Information on how to use dm-crypt can be found on
+
+	  http://www.saout.de/misc/dm-crypt/
+
+	  To compile this code as a module, choose M here: the module will
+	  be called dm-crypt.
+
+	  If unsure, say N.
+
 endmenu
 
--- diff/drivers/md/Makefile	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/Makefile	2004-02-18 09:04:00.000000000 +0000
@@ -23,6 +23,7 @@
 obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
 obj-$(CONFIG_BLK_DEV_MD)	+= md.o
 obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
+obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
 
 quiet_cmd_unroll = UNROLL  $@
       cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \
--- diff/drivers/md/dm-stripe.c	2003-09-30 15:46:14.000000000 +0100
+++ source/drivers/md/dm-stripe.c	2004-02-18 09:04:00.000000000 +0000
@@ -195,12 +195,12 @@
 		break;
 
 	case STATUSTYPE_TABLE:
-		offset = snprintf(result, maxlen, "%d " SECTOR_FORMAT,
+		offset = scnprintf(result, maxlen, "%d " SECTOR_FORMAT,
 				  sc->stripes, sc->chunk_mask + 1);
 		for (i = 0; i < sc->stripes; i++) {
 			format_dev_t(buffer, sc->stripe[i].dev->bdev->bd_dev);
 			offset +=
-			    snprintf(result + offset, maxlen - offset,
+			    scnprintf(result + offset, maxlen - offset,
 				     " %s " SECTOR_FORMAT, buffer,
 				     sc->stripe[i].physical_start);
 		}
--- diff/drivers/md/dm-table.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/md/dm-table.c	2004-02-18 09:04:00.000000000 +0000
@@ -149,7 +149,7 @@
 	return 0;
 }
 
-static void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size)
+void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size)
 {
 	unsigned long size;
 	void *addr;
@@ -205,7 +205,7 @@
 
 int dm_table_create(struct dm_table **result, int mode, unsigned num_targets)
 {
-	struct dm_table *t = kmalloc(sizeof(*t), GFP_NOIO);
+	struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
 
 	if (!t)
 		return -ENOMEM;
@@ -655,6 +655,11 @@
 	memset(tgt, 0, sizeof(*tgt));
 	set_default_limits(&tgt->limits);
 
+	if (!len) {
+		tgt->error = "zero-length target";
+		return -EINVAL;
+	}
+
 	tgt->type = dm_get_target_type(type);
 	if (!tgt->type) {
 		tgt->error = "unknown target type";
@@ -858,6 +863,7 @@
 }
 
 
+EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
 EXPORT_SYMBOL(dm_table_event);
--- diff/drivers/md/dm.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/dm.c	2004-02-18 09:04:00.000000000 +0000
@@ -5,6 +5,7 @@
  */
 
 #include "dm.h"
+#include "dm-bio-list.h"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -27,11 +28,6 @@
 	atomic_t io_count;
 };
 
-struct deferred_io {
-	struct bio *bio;
-	struct deferred_io *next;
-};
-
 /*
  * Bits for the md->flags field.
  */
@@ -52,7 +48,7 @@
 	 */
 	atomic_t pending;
 	wait_queue_head_t wait;
-	struct deferred_io *deferred;
+ 	struct bio_list deferred;
 
 	/*
 	 * The current mapping.
@@ -188,38 +184,19 @@
 	mempool_free(io, md->io_pool);
 }
 
-static inline struct deferred_io *alloc_deferred(void)
-{
-	return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
-}
-
-static inline void free_deferred(struct deferred_io *di)
-{
-	kfree(di);
-}
-
 /*
  * Add the bio to the list of deferred io.
  */
 static int queue_io(struct mapped_device *md, struct bio *bio)
 {
-	struct deferred_io *di;
-
-	di = alloc_deferred();
-	if (!di)
-		return -ENOMEM;
-
 	down_write(&md->lock);
 
 	if (!test_bit(DMF_BLOCK_IO, &md->flags)) {
 		up_write(&md->lock);
-		free_deferred(di);
 		return 1;
 	}
 
-	di->bio = bio;
-	di->next = md->deferred;
-	md->deferred = di;
+	bio_list_add(&md->deferred, bio);
 
 	up_write(&md->lock);
 	return 0;		/* deferred successfully */
@@ -233,15 +210,6 @@
  *   interests of getting something for people to use I give
  *   you this clearly demarcated crap.
  *---------------------------------------------------------------*/
-static inline sector_t to_sector(unsigned int bytes)
-{
-	return bytes >> SECTOR_SHIFT;
-}
-
-static inline unsigned int to_bytes(sector_t sector)
-{
-	return sector << SECTOR_SHIFT;
-}
 
 /*
  * Decrements the number of outstanding ios that a bio has been
@@ -249,14 +217,8 @@
  */
 static inline void dec_pending(struct dm_io *io, int error)
 {
-	static spinlock_t _uptodate_lock = SPIN_LOCK_UNLOCKED;
-	unsigned long flags;
-
-	if (error) {
-		spin_lock_irqsave(&_uptodate_lock, flags);
+	if (error)
 		io->error = error;
-		spin_unlock_irqrestore(&_uptodate_lock, flags);
-	}
 
 	if (atomic_dec_and_test(&io->io_count)) {
 		if (atomic_dec_and_test(&io->md->pending))
@@ -376,6 +338,7 @@
 	clone->bi_idx = idx;
 	clone->bi_vcnt = idx + bv_count;
 	clone->bi_size = to_bytes(len);
+	clone->bi_flags &= ~(1 << BIO_SEG_VALID);
 
 	return clone;
 }
@@ -592,41 +555,28 @@
 
 	/* get a minor number for the dev */
 	r = persistent ? specific_minor(minor) : next_free_minor(&minor);
-	if (r < 0) {
-		kfree(md);
-		return NULL;
-	}
+	if (r < 0)
+		goto bad1;
 
 	memset(md, 0, sizeof(*md));
 	init_rwsem(&md->lock);
 	atomic_set(&md->holders, 1);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
-	if (!md->queue) {
-		kfree(md);
-		return NULL;
-	}
+	if (!md->queue)
+		goto bad1;
 
 	md->queue->queuedata = md;
 	blk_queue_make_request(md->queue, dm_request);
 
 	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
 				     mempool_free_slab, _io_cache);
-	if (!md->io_pool) {
-		free_minor(minor);
-		blk_put_queue(md->queue);
-		kfree(md);
-		return NULL;
-	}
+ 	if (!md->io_pool)
+ 		goto bad2;
 
 	md->disk = alloc_disk(1);
-	if (!md->disk) {
-		mempool_destroy(md->io_pool);
-		free_minor(minor);
-		blk_put_queue(md->queue);
-		kfree(md);
-		return NULL;
-	}
+	if (!md->disk)
+		goto bad3;
 
 	md->disk->major = _major;
 	md->disk->first_minor = minor;
@@ -641,6 +591,16 @@
 	init_waitqueue_head(&md->eventq);
 
 	return md;
+
+
+ bad3:
+	mempool_destroy(md->io_pool);
+ bad2:
+	blk_put_queue(md->queue);
+	free_minor(minor);
+ bad1:
+	kfree(md);
+	return NULL;
 }
 
 static void free_dev(struct mapped_device *md)
@@ -752,14 +712,14 @@
 /*
  * Requeue the deferred bios by calling generic_make_request.
  */
-static void flush_deferred_io(struct deferred_io *c)
+static void flush_deferred_io(struct bio *c)
 {
-	struct deferred_io *n;
+	struct bio *n;
 
 	while (c) {
-		n = c->next;
-		generic_make_request(c->bio);
-		free_deferred(c);
+		n = c->bi_next;
+		c->bi_next = NULL;
+		generic_make_request(c);
 		c = n;
 	}
 }
@@ -841,7 +801,7 @@
 
 int dm_resume(struct mapped_device *md)
 {
-	struct deferred_io *def;
+	struct bio *def;
 
 	down_write(&md->lock);
 	if (!md->map ||
@@ -854,8 +814,7 @@
 	dm_table_resume_targets(md->map);
 	clear_bit(DMF_SUSPENDED, &md->flags);
 	clear_bit(DMF_BLOCK_IO, &md->flags);
-	def = md->deferred;
-	md->deferred = NULL;
+	def = bio_list_get(&md->deferred);
 	up_write(&md->lock);
 
 	flush_deferred_io(def);
--- diff/drivers/md/dm.h	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/md/dm.h	2004-02-18 09:04:00.000000000 +0000
@@ -151,6 +151,16 @@
 	return dm_round_up(n, size) / size;
 }
 
+static inline sector_t to_sector(unsigned long n)
+{
+	return (n >> 9);
+}
+
+static inline unsigned long to_bytes(sector_t n)
+{
+	return (n << 9);
+}
+
 /*
  * The device-mapper can be driven through one of two interfaces;
  * ioctl or filesystem, depending which patch you have applied.
@@ -167,4 +177,6 @@
 int dm_stripe_init(void);
 void dm_stripe_exit(void);
 
+void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
+
 #endif
--- diff/drivers/md/md.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/md.c	2004-02-18 09:04:00.000000000 +0000
@@ -52,6 +52,9 @@
 #define MAJOR_NR MD_MAJOR
 #define MD_DRIVER
 
+/* 63 partitions with the alternate major number (mdp) */
+#define MdpMinorShift 6
+
 #define DEBUG 0
 #define dprintk(x...) ((void)(DEBUG && printk(x)))
 
@@ -178,14 +181,14 @@
 	spin_unlock(&all_mddevs_lock);
 }
 
-static mddev_t * mddev_find(int unit)
+static mddev_t * mddev_find(dev_t unit)
 {
 	mddev_t *mddev, *new = NULL;
 
  retry:
 	spin_lock(&all_mddevs_lock);
 	list_for_each_entry(mddev, &all_mddevs, all_mddevs)
-		if (mdidx(mddev) == unit) {
+		if (mddev->unit == unit) {
 			mddev_get(mddev);
 			spin_unlock(&all_mddevs_lock);
 			if (new)
@@ -206,7 +209,12 @@
 
 	memset(new, 0, sizeof(*new));
 
-	new->__minor = unit;
+	new->unit = unit;
+	if (MAJOR(unit) == MD_MAJOR)
+		new->md_minor = MINOR(unit);
+	else
+		new->md_minor = MINOR(unit) >> MdpMinorShift;
+
 	init_MUTEX(&new->reconfig_sem);
 	INIT_LIST_HEAD(&new->disks);
 	INIT_LIST_HEAD(&new->all_mddevs);
@@ -660,7 +668,7 @@
 	sb->level = mddev->level;
 	sb->size  = mddev->size;
 	sb->raid_disks = mddev->raid_disks;
-	sb->md_minor = mddev->__minor;
+	sb->md_minor = mddev->md_minor;
 	sb->not_persistent = !mddev->persistent;
 	sb->utime = mddev->utime;
 	sb->state = 0;
@@ -1442,13 +1450,16 @@
 	return 1;
 }
 
+static int mdp_major = 0;
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
 {
 	static DECLARE_MUTEX(disks_sem);
-	int unit = *part;
-	mddev_t *mddev = mddev_find(unit);
+	mddev_t *mddev = mddev_find(dev);
 	struct gendisk *disk;
+	int partitioned = (MAJOR(dev) != MD_MAJOR);
+	int shift = partitioned ? MdpMinorShift : 0;
+	int unit = MINOR(dev) >> shift;
 
 	if (!mddev)
 		return NULL;
@@ -1459,15 +1470,18 @@
 		mddev_put(mddev);
 		return NULL;
 	}
-	disk = alloc_disk(1);
+	disk = alloc_disk(1 << shift);
 	if (!disk) {
 		up(&disks_sem);
 		mddev_put(mddev);
 		return NULL;
 	}
-	disk->major = MD_MAJOR;
-	disk->first_minor = mdidx(mddev);
-	sprintf(disk->disk_name, "md%d", mdidx(mddev));
+	disk->major = MAJOR(dev);
+	disk->first_minor = unit << shift;
+	if (partitioned)
+		sprintf(disk->disk_name, "md_d%d", unit);
+	else
+		sprintf(disk->disk_name, "md%d", unit);
 	disk->fops = &md_fops;
 	disk->private_data = mddev;
 	disk->queue = mddev->queue;
@@ -1496,7 +1510,6 @@
 	mdk_rdev_t *rdev;
 	struct gendisk *disk;
 	char b[BDEVNAME_SIZE];
-	int unit;
 
 	if (list_empty(&mddev->disks)) {
 		MD_BUG();
@@ -1588,8 +1601,7 @@
 		invalidate_bdev(rdev->bdev, 0);
 	}
 
-	unit = mdidx(mddev);
-	md_probe(0, &unit, NULL);
+	md_probe(mddev->unit, NULL, NULL);
 	disk = mddev->gendisk;
 	if (!disk)
 		return -ENOMEM;
@@ -1636,6 +1648,7 @@
 	mddev->queue->queuedata = mddev;
 	mddev->queue->make_request_fn = mddev->pers->make_request;
 
+	mddev->changed = 1;
 	return 0;
 }
 
@@ -1735,6 +1748,7 @@
 		disk = mddev->gendisk;
 		if (disk)
 			set_capacity(disk, 0);
+		mddev->changed = 1;
 	} else
 		printk(KERN_INFO "md: %s switched to read-only mode.\n",
 			mdname(mddev));
@@ -1791,6 +1805,7 @@
 
 	printk(KERN_INFO "md: autorun ...\n");
 	while (!list_empty(&pending_raid_disks)) {
+		dev_t dev;
 		rdev0 = list_entry(pending_raid_disks.next,
 					 mdk_rdev_t, same_set);
 
@@ -1808,8 +1823,14 @@
 		 * mostly sane superblocks. It's time to allocate the
 		 * mddev.
 		 */
-
-		mddev = mddev_find(rdev0->preferred_minor);
+		if (rdev0->preferred_minor < 0 || rdev0->preferred_minor >= MAX_MD_DEVS) {
+			printk(KERN_INFO "md: unit number in %s is bad: %d\n",
+			       bdevname(rdev0->bdev, b), rdev0->preferred_minor);
+			break;
+		}
+		dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+		md_probe(dev, NULL, NULL);
+		mddev = mddev_find(dev);
 		if (!mddev) {
 			printk(KERN_ERR 
 				"md: cannot allocate memory for md drive.\n");
@@ -1824,7 +1845,7 @@
 				"md: %s already running, cannot run %s\n",
 				mdname(mddev), bdevname(rdev0->bdev,b));
 			mddev_unlock(mddev);
-		} else if (rdev0->preferred_minor >= 0 && rdev0->preferred_minor < MAX_MD_DEVS) {
+		} else {
 			printk(KERN_INFO "md: created %s\n", mdname(mddev));
 			ITERATE_RDEV_GENERIC(candidates,rdev,tmp) {
 				list_del_init(&rdev->same_set);
@@ -1833,9 +1854,7 @@
 			}
 			autorun_array(mddev);
 			mddev_unlock(mddev);
-		} else
-			printk(KERN_WARNING "md: %s had invalid preferred minor %d\n",
-			       bdevname(rdev->bdev, b), rdev0->preferred_minor);
+		}
 		/* on success, candidates will be empty, on error
 		 * it won't...
 		 */
@@ -1955,7 +1974,7 @@
 	info.size          = mddev->size;
 	info.nr_disks      = nr;
 	info.raid_disks    = mddev->raid_disks;
-	info.md_minor      = mddev->__minor;
+	info.md_minor      = mddev->md_minor;
 	info.not_persistent= !mddev->persistent;
 
 	info.utime         = mddev->utime;
@@ -2326,7 +2345,7 @@
 	mddev->level         = info->level;
 	mddev->size          = info->size;
 	mddev->raid_disks    = info->raid_disks;
-	/* don't set __minor, it is determined by which /dev/md* was
+	/* don't set md_minor, it is determined by which /dev/md* was
 	 * openned
 	 */
 	if (info->state & (1<<MD_SB_CLEAN))
@@ -2366,7 +2385,6 @@
 			unsigned int cmd, unsigned long arg)
 {
 	char b[BDEVNAME_SIZE];
-	unsigned int minor = iminor(inode);
 	int err = 0;
 	struct hd_geometry *loc = (struct hd_geometry *) arg;
 	mddev_t *mddev = NULL;
@@ -2374,11 +2392,6 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (minor >= MAX_MD_DEVS) {
-		MD_BUG();
-		return -EINVAL;
-	}
-
 	/*
 	 * Commands dealing with the RAID driver but not any
 	 * particular array:
@@ -2419,6 +2432,14 @@
 		/* START_ARRAY doesn't need to lock the array as autostart_array
 		 * does the locking, and it could even be a different array
 		 */
+		static int cnt = 3;
+		if (cnt > 0 ) {
+			printk(KERN_WARNING
+			       "md: %s(pid %d) used deprecated START_ARRAY ioctl. "
+			       "This will not be supported beyond 2.6\n",
+			       current->comm, current->pid);
+			cnt--;
+		}
 		err = autostart_array(new_decode_dev(arg));
 		if (err) {
 			printk(KERN_WARNING "md: autostart %s failed!\n",
@@ -2612,6 +2633,7 @@
 	mddev_get(mddev);
 	mddev_unlock(mddev);
 
+	check_disk_change(inode->i_bdev);
  out:
 	return err;
 }
@@ -2627,12 +2649,28 @@
 	return 0;
 }
 
+static int md_media_changed(struct gendisk *disk)
+{
+	mddev_t *mddev = disk->private_data;
+
+	return mddev->changed;
+}
+
+static int md_revalidate(struct gendisk *disk)
+{
+	mddev_t *mddev = disk->private_data;
+
+	mddev->changed = 0;
+	return 0;
+}
 static struct block_device_operations md_fops =
 {
 	.owner		= THIS_MODULE,
 	.open		= md_open,
 	.release	= md_release,
 	.ioctl		= md_ioctl,
+	.media_changed	= md_media_changed,
+	.revalidate_disk= md_revalidate,
 };
 
 int md_thread(void * arg)
@@ -3497,16 +3535,26 @@
 
 	if (register_blkdev(MAJOR_NR, "md"))
 		return -1;
-
+	if ((mdp_major=register_blkdev(0, "mdp"))<=0) {
+		unregister_blkdev(MAJOR_NR, "md");
+		return -1;
+	}
 	devfs_mk_dir("md");
 	blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE,
 				md_probe, NULL, NULL);
+	blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE,
+			    md_probe, NULL, NULL);
 
-	for (minor=0; minor < MAX_MD_DEVS; ++minor) {
+	for (minor=0; minor < MAX_MD_DEVS; ++minor)
 		devfs_mk_bdev(MKDEV(MAJOR_NR, minor),
 				S_IFBLK|S_IRUSR|S_IWUSR,
 				"md/%d", minor);
-	}
+
+	for (minor=0; minor < MAX_MD_DEVS; ++minor)
+		devfs_mk_bdev(MKDEV(mdp_major, minor<<MdpMinorShift),
+			      S_IFBLK|S_IRUSR|S_IWUSR,
+			      "md/d%d", minor);
+
 
 	register_reboot_notifier(&md_notifier);
 	raid_table_header = register_sysctl_table(raid_root_table, 1);
@@ -3568,11 +3616,16 @@
 	struct list_head *tmp;
 	int i;
 	blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS);
+	blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift);
 	for (i=0; i < MAX_MD_DEVS; i++)
 		devfs_remove("md/%d", i);
+	for (i=0; i < MAX_MD_DEVS; i++)
+		devfs_remove("md/d%d", i);
+
 	devfs_remove("md");
 
 	unregister_blkdev(MAJOR_NR,"md");
+	unregister_blkdev(mdp_major, "mdp");
 	unregister_reboot_notifier(&md_notifier);
 	unregister_sysctl_table(raid_table_header);
 	remove_proc_entry("mdstat", NULL);
--- diff/drivers/md/raid1.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/raid1.c	2004-02-18 09:04:00.000000000 +0000
@@ -42,7 +42,7 @@
 	mddev_t *mddev = data;
 	r1bio_t *r1_bio;
 
-	/* allocate a r1bio with room for raid_disks entries in the write_bios array */
+	/* allocate a r1bio with room for raid_disks entries in the bios array */
 	r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks,
 			 gfp_flags);
 	if (r1_bio)
@@ -56,8 +56,8 @@
 	kfree(r1_bio);
 }
 
-//#define RESYNC_BLOCK_SIZE (64*1024)
-#define RESYNC_BLOCK_SIZE PAGE_SIZE
+#define RESYNC_BLOCK_SIZE (64*1024)
+//#define RESYNC_BLOCK_SIZE PAGE_SIZE
 #define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
 #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
 #define RESYNC_WINDOW (2048*1024)
@@ -73,38 +73,39 @@
 	r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev);
 	if (!r1_bio)
 		return NULL;
-	bio = bio_alloc(gfp_flags, RESYNC_PAGES);
-	if (!bio)
-		goto out_free_r1_bio;
 
+	/*
+	 * Allocate bios : 1 for reading, n-1 for writing
+	 */
+	for (j = conf->raid_disks ; j-- ; ) {
+		bio = bio_alloc(gfp_flags, RESYNC_PAGES);
+		if (!bio)
+			goto out_free_bio;
+		r1_bio->bios[j] = bio;
+	}
+	/*
+	 * Allocate RESYNC_PAGES data pages and attach them to
+	 * the first bio;
+	 */
+	bio = r1_bio->bios[0];
 	for (i = 0; i < RESYNC_PAGES; i++) {
 		page = alloc_page(gfp_flags);
 		if (unlikely(!page))
 			goto out_free_pages;
 
 		bio->bi_io_vec[i].bv_page = page;
-		bio->bi_io_vec[i].bv_len = PAGE_SIZE;
-		bio->bi_io_vec[i].bv_offset = 0;
 	}
 
-	/*
-	 * Allocate a single data page for this iovec.
-	 */
-	bio->bi_vcnt = RESYNC_PAGES;
-	bio->bi_idx = 0;
-	bio->bi_size = RESYNC_BLOCK_SIZE;
-	bio->bi_end_io = NULL;
-	atomic_set(&bio->bi_cnt, 1);
-
 	r1_bio->master_bio = bio;
 
 	return r1_bio;
 
 out_free_pages:
-	for (j = 0; j < i; j++)
-		__free_page(bio->bi_io_vec[j].bv_page);
-	bio_put(bio);
-out_free_r1_bio:
+	for ( ; i > 0 ; i--)
+		__free_page(bio->bi_io_vec[i-1].bv_page);
+out_free_bio:
+	while ( j < conf->raid_disks )
+		bio_put(r1_bio->bios[++j]);
 	r1bio_pool_free(r1_bio, conf->mddev);
 	return NULL;
 }
@@ -114,17 +115,15 @@
 	int i;
 	conf_t *conf = data;
 	r1bio_t *r1bio = __r1_bio;
-	struct bio *bio = r1bio->master_bio;
+	struct bio *bio = r1bio->bios[0];
 
-	if (atomic_read(&bio->bi_cnt) != 1)
-		BUG();
 	for (i = 0; i < RESYNC_PAGES; i++) {
 		__free_page(bio->bi_io_vec[i].bv_page);
 		bio->bi_io_vec[i].bv_page = NULL;
 	}
-	if (atomic_read(&bio->bi_cnt) != 1)
-		BUG();
-	bio_put(bio);
+	for (i=0 ; i < conf->raid_disks; i++)
+		bio_put(r1bio->bios[i]);
+
 	r1bio_pool_free(r1bio, conf->mddev);
 }
 
@@ -132,19 +131,10 @@
 {
 	int i;
 
-	if (r1_bio->read_bio) {
-		if (atomic_read(&r1_bio->read_bio->bi_cnt) != 1)
-			BUG();
-		bio_put(r1_bio->read_bio);
-		r1_bio->read_bio = NULL;
-	}
 	for (i = 0; i < conf->raid_disks; i++) {
-		struct bio **bio = r1_bio->write_bios + i;
-		if (*bio) {
-			if (atomic_read(&(*bio)->bi_cnt) != 1)
-				BUG();
+		struct bio **bio = r1_bio->bios + i;
+		if (*bio)
 			bio_put(*bio);
-		}
 		*bio = NULL;
 	}
 }
@@ -173,15 +163,8 @@
 static inline void put_buf(r1bio_t *r1_bio)
 {
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
-	struct bio *bio = r1_bio->master_bio;
 	unsigned long flags;
 
-	/*
-	 * undo any possible partial request fixup magic:
-	 */
-	if (bio->bi_size != RESYNC_BLOCK_SIZE)
-		bio->bi_io_vec[bio->bi_vcnt-1].bv_len = PAGE_SIZE;
-	put_all_bios(conf, r1_bio);
 	mempool_free(r1_bio, conf->r1buf_pool);
 
 	spin_lock_irqsave(&conf->resync_lock, flags);
@@ -258,10 +241,10 @@
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
 	conf->mirrors[disk].head_position =
-		r1_bio->sector + (r1_bio->master_bio->bi_size >> 9);
+		r1_bio->sector + (r1_bio->sectors);
 }
 
-static int raid1_end_request(struct bio *bio, unsigned int bytes_done, int error)
+static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -271,13 +254,7 @@
 	if (bio->bi_size)
 		return 1;
 	
-	if (r1_bio->cmd == READ || r1_bio->cmd == READA)
-		mirror = r1_bio->read_disk;
-	else {
-		for (mirror = 0; mirror < conf->raid_disks; mirror++)
-			if (r1_bio->write_bios[mirror] == bio)
-				break;
-	}
+	mirror = r1_bio->read_disk;
 	/*
 	 * this branch is our 'one mirror IO has finished' event handler:
 	 */
@@ -296,42 +273,74 @@
 		set_bit(R1BIO_Uptodate, &r1_bio->state);
 
 	update_head_pos(mirror, r1_bio);
-	if ((r1_bio->cmd == READ) || (r1_bio->cmd == READA)) {
-		if (!r1_bio->read_bio)
-			BUG();
+
+	/*
+	 * we have only one bio on the read side
+	 */
+	if (uptodate)
+		raid_end_bio_io(r1_bio);
+	else {
 		/*
-		 * we have only one bio on the read side
+		 * oops, read error:
 		 */
-		if (uptodate)
-			raid_end_bio_io(r1_bio);
-		else {
-			/*
-			 * oops, read error:
-			 */
-			char b[BDEVNAME_SIZE];
-			printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
-				bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
-			reschedule_retry(r1_bio);
-		}
-	} else {
+		char b[BDEVNAME_SIZE];
+		printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
+		       bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
+		reschedule_retry(r1_bio);
+	}
 
-		if (r1_bio->read_bio)
-			BUG();
+	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+	return 0;
+}
+
+static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+{
+	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
+	int mirror;
+	conf_t *conf = mddev_to_conf(r1_bio->mddev);
+
+	if (bio->bi_size)
+		return 1;
+
+	for (mirror = 0; mirror < conf->raid_disks; mirror++)
+		if (r1_bio->bios[mirror] == bio)
+			break;
+
+	/*
+	 * this branch is our 'one mirror IO has finished' event handler:
+	 */
+	if (!uptodate)
+		md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
+	else
 		/*
-		 * WRITE:
+		 * Set R1BIO_Uptodate in our master bio, so that
+		 * we will return a good error code for to the higher
+		 * levels even if IO on some other mirrored buffer fails.
 		 *
-		 * Let's see if all mirrored write operations have finished
-		 * already.
+		 * The 'master' represents the composite IO operation to
+		 * user-side. So if something waits for IO, then it will
+		 * wait for the 'master' bio.
 		 */
-		if (atomic_dec_and_test(&r1_bio->remaining)) {
-			md_write_end(r1_bio->mddev);
-			raid_end_bio_io(r1_bio);
-		}	
+		set_bit(R1BIO_Uptodate, &r1_bio->state);
+
+	update_head_pos(mirror, r1_bio);
+
+	/*
+	 *
+	 * Let's see if all mirrored write operations have finished
+	 * already.
+	 */
+	if (atomic_dec_and_test(&r1_bio->remaining)) {
+		md_write_end(r1_bio->mddev);
+		raid_end_bio_io(r1_bio);
 	}
+
 	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
 	return 0;
 }
 
+
 /*
  * This routine returns the disk from which the requested read should
  * be done. There is a per-array 'next expected sequential IO' sector
@@ -490,26 +499,25 @@
 	r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
 
 	r1_bio->master_bio = bio;
+	r1_bio->sectors = bio->bi_size >> 9;
 
 	r1_bio->mddev = mddev;
 	r1_bio->sector = bio->bi_sector;
-	r1_bio->cmd = bio_data_dir(bio);
 
-	if (r1_bio->cmd == READ) {
+	if (bio_data_dir(bio) == READ) {
 		/*
 		 * read balancing logic:
 		 */
 		mirror = conf->mirrors + read_balance(conf, bio, r1_bio);
 
 		read_bio = bio_clone(bio, GFP_NOIO);
-		if (r1_bio->read_bio)
-			BUG();
-		r1_bio->read_bio = read_bio;
+
+		r1_bio->bios[r1_bio->read_disk] = read_bio;
 
 		read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset;
 		read_bio->bi_bdev = mirror->rdev->bdev;
-		read_bio->bi_end_io = raid1_end_request;
-		read_bio->bi_rw = r1_bio->cmd;
+		read_bio->bi_end_io = raid1_end_read_request;
+		read_bio->bi_rw = READ;
 		read_bio->bi_private = r1_bio;
 
 		generic_make_request(read_bio);
@@ -521,16 +529,16 @@
 	 */
 	/* first select target devices under spinlock and
 	 * inc refcount on their rdev.  Record them by setting
-	 * write_bios[x] to bio
+	 * bios[x] to bio
 	 */
 	spin_lock_irq(&conf->device_lock);
 	for (i = 0;  i < disks; i++) {
 		if (conf->mirrors[i].rdev &&
 		    !conf->mirrors[i].rdev->faulty) {
 			atomic_inc(&conf->mirrors[i].rdev->nr_pending);
-			r1_bio->write_bios[i] = bio;
+			r1_bio->bios[i] = bio;
 		} else
-			r1_bio->write_bios[i] = NULL;
+			r1_bio->bios[i] = NULL;
 	}
 	spin_unlock_irq(&conf->device_lock);
 
@@ -538,16 +546,16 @@
 	md_write_start(mddev);
 	for (i = 0; i < disks; i++) {
 		struct bio *mbio;
-		if (!r1_bio->write_bios[i])
+		if (!r1_bio->bios[i])
 			continue;
 
 		mbio = bio_clone(bio, GFP_NOIO);
-		r1_bio->write_bios[i] = mbio;
+		r1_bio->bios[i] = mbio;
 
 		mbio->bi_sector	= r1_bio->sector + conf->mirrors[i].rdev->data_offset;
 		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
-		mbio->bi_end_io	= raid1_end_request;
-		mbio->bi_rw = r1_bio->cmd;
+		mbio->bi_end_io	= raid1_end_write_request;
+		mbio->bi_rw = WRITE;
 		mbio->bi_private = r1_bio;
 
 		atomic_inc(&r1_bio->remaining);
@@ -744,7 +752,7 @@
 	if (bio->bi_size)
 		return 1;
 
-	if (r1_bio->read_bio != bio)
+	if (r1_bio->bios[r1_bio->read_disk] != bio)
 		BUG();
 	update_head_pos(r1_bio->read_disk, r1_bio);
 	/*
@@ -775,7 +783,7 @@
 		return 1;
 
 	for (i = 0; i < conf->raid_disks; i++)
-		if (r1_bio->write_bios[i] == bio) {
+		if (r1_bio->bios[i] == bio) {
 			mirror = i;
 			break;
 		}
@@ -784,7 +792,7 @@
 	update_head_pos(mirror, r1_bio);
 
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
-		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, uptodate);
+		md_done_sync(mddev, r1_bio->sectors, uptodate);
 		put_buf(r1_bio);
 	}
 	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
@@ -796,12 +804,11 @@
 	conf_t *conf = mddev_to_conf(mddev);
 	int i;
 	int disks = conf->raid_disks;
-	struct bio *bio, *mbio;
+	struct bio *bio, *wbio;
 
-	bio = r1_bio->master_bio;
+	bio = r1_bio->bios[r1_bio->read_disk];
 
 	/*
-	 * have to allocate lots of bio structures and
 	 * schedule writes
 	 */
 	if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) {
@@ -814,52 +821,25 @@
 			" for block %llu\n",
 			bdevname(bio->bi_bdev,b), 
 			(unsigned long long)r1_bio->sector);
-		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
+		md_done_sync(mddev, r1_bio->sectors, 0);
 		put_buf(r1_bio);
 		return;
 	}
 
-	spin_lock_irq(&conf->device_lock);
-	for (i = 0; i < disks ; i++) {
-		r1_bio->write_bios[i] = NULL;
-		if (!conf->mirrors[i].rdev || 
-		    conf->mirrors[i].rdev->faulty)
-			continue;
-		if (conf->mirrors[i].rdev->bdev == bio->bi_bdev)
-			/*
-			 * we read from here, no need to write
-			 */
-			continue;
-		if (conf->mirrors[i].rdev->in_sync && 
-			r1_bio->sector + (bio->bi_size>>9) <= mddev->recovery_cp)
-			/*
-			 * don't need to write this we are just rebuilding
-			 */
-			continue;
-		atomic_inc(&conf->mirrors[i].rdev->nr_pending);
-		r1_bio->write_bios[i] = bio;
-	}
-	spin_unlock_irq(&conf->device_lock);
-
 	atomic_set(&r1_bio->remaining, 1);
-	for (i = disks; i-- ; ) {
-		if (!r1_bio->write_bios[i])
+	for (i = 0; i < disks ; i++) {
+		wbio = r1_bio->bios[i];
+		if (wbio->bi_end_io != end_sync_write)
 			continue;
-		mbio = bio_clone(bio, GFP_NOIO);
-		r1_bio->write_bios[i] = mbio;
-		mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
-		mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset;
-		mbio->bi_end_io	= end_sync_write;
-		mbio->bi_rw = WRITE;
-		mbio->bi_private = r1_bio;
 
+		atomic_inc(&conf->mirrors[i].rdev->nr_pending);
 		atomic_inc(&r1_bio->remaining);
-		md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9);
-		generic_make_request(mbio);
+		md_sync_acct(conf->mirrors[i].rdev, wbio->bi_size >> 9);
+		generic_make_request(wbio);
 	}
 
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
-		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 1);
+		md_done_sync(mddev, r1_bio->sectors, 1);
 		put_buf(r1_bio);
 	}
 }
@@ -896,30 +876,26 @@
 		mddev = r1_bio->mddev;
 		conf = mddev_to_conf(mddev);
 		bio = r1_bio->master_bio;
-		switch(r1_bio->cmd) {
-		case SPECIAL:
+		if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
 			sync_request_write(mddev, r1_bio);
-			break;
-		case READ:
-		case READA:
+		} else {
 			if (map(mddev, &rdev) == -1) {
 				printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
-				" read error for block %llu\n",
-				bdevname(bio->bi_bdev,b),
-				(unsigned long long)r1_bio->sector);
+				       " read error for block %llu\n",
+				       bdevname(bio->bi_bdev,b),
+				       (unsigned long long)r1_bio->sector);
 				raid_end_bio_io(r1_bio);
-				break;
-			}
-			printk(KERN_ERR "raid1: %s: redirecting sector %llu to"
-				" another mirror\n",
-				bdevname(rdev->bdev,b),
-				(unsigned long long)r1_bio->sector);
-			bio->bi_bdev = rdev->bdev;
-			bio->bi_sector = r1_bio->sector + rdev->data_offset;
-			bio->bi_rw = r1_bio->cmd;
+			} else {
+				printk(KERN_ERR "raid1: %s: redirecting sector %llu to"
+				       " another mirror\n",
+				       bdevname(rdev->bdev,b),
+				       (unsigned long long)r1_bio->sector);
+				bio->bi_bdev = rdev->bdev;
+				bio->bi_sector = r1_bio->sector + rdev->data_offset;
+				bio->bi_rw = READ;
 
-			generic_make_request(bio);
-			break;
+				generic_make_request(bio);
+			}
 		}
 	}
 	spin_unlock_irqrestore(&retry_list_lock, flags);
@@ -955,9 +931,10 @@
 	conf_t *conf = mddev_to_conf(mddev);
 	mirror_info_t *mirror;
 	r1bio_t *r1_bio;
-	struct bio *read_bio, *bio;
+	struct bio *bio;
 	sector_t max_sector, nr_sectors;
-	int disk, partial;
+	int disk;
+	int i;
 
 	if (!conf->r1buf_pool)
 		if (init_resync(conf))
@@ -1007,38 +984,77 @@
 
 	r1_bio->mddev = mddev;
 	r1_bio->sector = sector_nr;
-	r1_bio->cmd = SPECIAL;
+	set_bit(R1BIO_IsSync, &r1_bio->state);
 	r1_bio->read_disk = disk;
 
-	bio = r1_bio->master_bio;
-	nr_sectors = RESYNC_BLOCK_SIZE >> 9;
-	if (max_sector - sector_nr < nr_sectors)
-		nr_sectors = max_sector - sector_nr;
-	bio->bi_size = nr_sectors << 9;
-	bio->bi_vcnt = (bio->bi_size + PAGE_SIZE-1) / PAGE_SIZE;
-	/*
-	 * Is there a partial page at the end of the request?
-	 */
-	partial = bio->bi_size % PAGE_SIZE;
-	if (partial)
-		bio->bi_io_vec[bio->bi_vcnt-1].bv_len = partial;
-
+	for (i=0; i < conf->raid_disks; i++) {
+		bio = r1_bio->bios[i];
 
-	read_bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
-
-	read_bio->bi_sector = sector_nr + mirror->rdev->data_offset;
-	read_bio->bi_bdev = mirror->rdev->bdev;
-	read_bio->bi_end_io = end_sync_read;
-	read_bio->bi_rw = READ;
-	read_bio->bi_private = r1_bio;
-
-	if (r1_bio->read_bio)
-		BUG();
-	r1_bio->read_bio = read_bio;
+		/* take from bio_init */
+		bio->bi_next = NULL;
+		bio->bi_flags |= 1 << BIO_UPTODATE;
+		bio->bi_rw = 0;
+		bio->bi_vcnt = 0;
+		bio->bi_idx = 0;
+		bio->bi_phys_segments = 0;
+		bio->bi_hw_segments = 0;
+		bio->bi_size = 0;
+		bio->bi_end_io = NULL;
+		bio->bi_private = NULL;
+
+		if (i == disk) {
+			bio->bi_rw = READ;
+			bio->bi_end_io = end_sync_read;
+		} else if (conf->mirrors[i].rdev &&
+			   !conf->mirrors[i].rdev->faulty &&
+			   (!conf->mirrors[i].rdev->in_sync ||
+			    sector_nr + RESYNC_SECTORS > mddev->recovery_cp)) {
+			bio->bi_rw = WRITE;
+			bio->bi_end_io = end_sync_write;
+		} else
+			continue;
+		bio->bi_sector = sector_nr + conf->mirrors[i].rdev->data_offset;
+		bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+		bio->bi_private = r1_bio;
+	}
+	nr_sectors = 0;
+	do {
+		struct page *page;
+		int len = PAGE_SIZE;
+		if (sector_nr + (len>>9) > max_sector)
+			len = (max_sector - sector_nr) << 9;
+		if (len == 0)
+			break;
+		for (i=0 ; i < conf->raid_disks; i++) {
+			bio = r1_bio->bios[i];
+			if (bio->bi_end_io) {
+				page = r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page;
+				if (bio_add_page(bio, page, len, 0) == 0) {
+					/* stop here */
+					r1_bio->bios[0]->bi_io_vec[bio->bi_vcnt].bv_page = page;
+					while (i > 0) {
+						i--;
+						bio = r1_bio->bios[i];
+						if (bio->bi_end_io==NULL) continue;
+						/* remove last page from this bio */
+						bio->bi_vcnt--;
+						bio->bi_size -= len;
+						bio->bi_flags &= ~(1<< BIO_SEG_VALID);
+					}
+					goto bio_full;
+				}
+			}
+		}
+		nr_sectors += len>>9;
+		sector_nr += len>>9;
+	} while (r1_bio->bios[disk]->bi_vcnt < RESYNC_PAGES);
+ bio_full:
+	bio = r1_bio->bios[disk];
+	r1_bio->sectors = nr_sectors;
 
 	md_sync_acct(mirror->rdev, nr_sectors);
 
-	generic_make_request(read_bio);
+	generic_make_request(bio);
 
 	return nr_sectors;
 }
--- diff/drivers/md/raid5.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/raid5.c	2004-02-18 09:04:00.000000000 +0000
@@ -284,7 +284,7 @@
 	kmem_cache_t *sc;
 	int devs = conf->raid_disks;
 
-	sprintf(conf->cache_name, "md/raid5-%d", conf->mddev->__minor);
+	sprintf(conf->cache_name, "raid5/%s", mdname(conf->mddev));
 
 	sc = kmem_cache_create(conf->cache_name, 
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
--- diff/drivers/md/raid6main.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/md/raid6main.c	2004-02-18 09:04:00.000000000 +0000
@@ -303,7 +303,7 @@
 	kmem_cache_t *sc;
 	int devs = conf->raid_disks;
 
-	sprintf(conf->cache_name, "md/raid6-%d", conf->mddev->__minor);
+	sprintf(conf->cache_name, "raid6/%s", mdname(conf->mddev));
 
 	sc = kmem_cache_create(conf->cache_name,
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
--- diff/drivers/media/dvb/Kconfig	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/media/dvb/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -18,11 +18,12 @@
 	  Please report problems regarding this driver to the LinuxDVB 
 	  mailing list.
 
-	  You might want add the following lines to your /etc/modules.conf:
+	  You might want add the following lines to your /etc/modprobe.conf:
 	  	
 	  	alias char-major-250 dvb
 	  	alias dvb dvb-ttpci
-	  	below dvb-ttpci alps_bsru6 alps_bsrv2 \
+	  	install dvb-ttpci /sbin/modprobe --first-time -i dvb-ttpci && \
+			/sbin/modprobe -a alps_bsru6 alps_bsrv2 \
 	  			grundig_29504-401 grundig_29504-491 \
 	  			ves1820
 
--- diff/drivers/media/dvb/dvb-core/dvb_net.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/media/dvb/dvb-core/dvb_net.c	2004-02-18 09:04:00.000000000 +0000
@@ -523,7 +523,8 @@
         net->base_addr = pid;
                 
 	if ((result = register_netdev(net)) < 0) {
-		kfree(net);
+		dvbnet->device[if_num] = NULL;
+		free_netdev(net);
 		return result;
 	}
 
@@ -545,6 +546,7 @@
 	flush_scheduled_work();
         unregister_netdev(net);
 	dvbnet->state[num]=0;
+	dvbnet->device[num] = NULL;
 	free_netdev(net);
 
 	return 0;
--- diff/drivers/media/dvb/frontends/alps_tdlb7.c	2003-10-27 09:20:37.000000000 +0000
+++ source/drivers/media/dvb/frontends/alps_tdlb7.c	2004-02-18 09:04:00.000000000 +0000
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
 
--- diff/drivers/media/dvb/frontends/sp887x.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/media/dvb/frontends/sp887x.c	2004-02-18 09:04:00.000000000 +0000
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/fcntl.h>
--- diff/drivers/media/dvb/frontends/tda1004x.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/media/dvb/frontends/tda1004x.c	2004-02-18 09:04:00.000000000 +0000
@@ -37,6 +37,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/fcntl.h>
--- diff/drivers/media/radio/Kconfig	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/media/radio/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -223,6 +223,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-sf16fmi.
 
+config RADIO_SF16FMR2
+	tristate "SF16FMR2 Radio"
+	depends on ISA && VIDEO_DEV
+	---help---
+	  Choose Y here if you have one of these FM radio cards.
+
+	  In order to control your radio card, you will need to use programs
+	  that are compatible with the Video For Linux API.  Information on
+	  this API and pointers to "v4l" programs may be found on the WWW at
+	  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-sf16fmr2.
+
 config RADIO_TERRATEC
 	tristate "TerraTec ActiveRadio ISA Standalone"
 	depends on ISA && VIDEO_DEV
--- diff/drivers/media/radio/Makefile	2003-02-13 11:46:52.000000000 +0000
+++ source/drivers/media/radio/Makefile	2004-02-18 09:04:00.000000000 +0000
@@ -7,6 +7,7 @@
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
+obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
--- diff/drivers/media/video/videocodec.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/media/video/videocodec.c	2004-02-18 09:04:00.000000000 +0000
@@ -392,15 +392,15 @@
 	videocodec_buf = (char *) kmalloc(size, GFP_KERNEL);
 
 	i = 0;
-	i += snprintf(videocodec_buf + i, size - 1,
+	i += scnprintf(videocodec_buf + i, size - 1,
 		      "<S>lave or attached <M>aster name  type flags    magic    ");
-	i += snprintf(videocodec_buf + i, size - 1, "(connected as)\n");
+	i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n");
 
 	h = codeclist_top;
 	while (h) {
 		if (i > (size - LINESIZE))
 			break;	// security check
-		i += snprintf(videocodec_buf + i, size,
+		i += scnprintf(videocodec_buf + i, size -i -1,
 			      "S %32s %04x %08lx %08lx (TEMPLATE)\n",
 			      h->codec->name, h->codec->type,
 			      h->codec->flags, h->codec->magic);
@@ -408,7 +408,7 @@
 		while (a) {
 			if (i > (size - LINESIZE))
 				break;	// security check
-			i += snprintf(videocodec_buf + i, size,
+			i += scnprintf(videocodec_buf + i, size -i -1,
 				      "M %32s %04x %08lx %08lx (%s)\n",
 				      a->codec->master_data->name,
 				      a->codec->master_data->type,
--- diff/drivers/message/fusion/mptbase.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/message/fusion/mptbase.h	2004-02-18 09:04:00.000000000 +0000
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2003 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.00.02"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.00.02"
+#define MPT_LINUX_VERSION_COMMON	"3.00.03"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.00.03"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
--- diff/drivers/message/fusion/mptlan.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/message/fusion/mptlan.c	2004-02-18 09:04:00.000000000 +0000
@@ -1437,7 +1437,7 @@
 	SET_MODULE_OWNER(dev);
 
 	if (register_netdev(dev) != 0) {
-		kfree(dev);
+		free_netdev(dev);
 		dev = NULL;
 	}
 	return dev;
--- diff/drivers/message/fusion/mptscsih.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/message/fusion/mptscsih.c	2004-02-18 09:04:00.000000000 +0000
@@ -1973,7 +1973,6 @@
 	if (mpt_scsi_hosts > 0)
 		return 0;
 
-	mptscsih_exit();
 	return -ENODEV;
 
 }
--- diff/drivers/mtd/maps/solutionengine.c	2003-06-30 10:07:21.000000000 +0100
+++ source/drivers/mtd/maps/solutionengine.c	2004-02-18 09:04:00.000000000 +0000
@@ -97,7 +97,7 @@
 
 	nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
 
-#if CONFIG_MTD_SUPERH_RESERVE
+#ifdef CONFIG_MTD_SUPERH_RESERVE
 	if (nr_parts <= 0) {
 		printk(KERN_NOTICE "Using configured partition at 0x%08x.\n",
 		       CONFIG_MTD_SUPERH_RESERVE);
--- diff/drivers/net/3c503.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/3c503.c	2004-02-18 09:04:00.000000000 +0000
@@ -337,6 +337,9 @@
     dev->open = &el2_open;
     dev->stop = &el2_close;
     dev->ethtool_ops = &netdev_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
 
     if (dev->mem_start)
 	printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
--- diff/drivers/net/3c509.c	2003-11-25 15:24:57.000000000 +0000
+++ source/drivers/net/3c509.c	2004-02-18 09:04:00.000000000 +0000
@@ -678,6 +678,8 @@
 		err = el3_common_init(dev);
 
 		if (err) {
+			device->driver_data = NULL;
+			free_netdev(dev);
 			return -ENOMEM;
 		}
 
@@ -737,6 +739,8 @@
 	err = el3_common_init(dev);
 
 	if (err) {
+		eisa_set_drvdata (edev, NULL);
+		free_netdev(dev);
 		return err;
 	}
 
--- diff/drivers/net/3c59x.c	2004-02-09 10:36:10.000000000 +0000
+++ source/drivers/net/3c59x.c	2004-02-18 09:04:00.000000000 +0000
@@ -291,6 +291,8 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(global_enable_wol, "i");
+MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(compaq_ioaddr, "i");
@@ -304,6 +306,8 @@
 MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if options is unset");
 MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
 MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
+MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
+MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if options is unset");
 MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
 MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
@@ -813,6 +817,7 @@
 		flow_ctrl:1,					/* Use 802.3x flow control (PAUSE only) */
 		partner_flow_ctrl:1,			/* Partner supports flow control */
 		has_nway:1,
+		enable_wol:1,					/* Wake-on-LAN is enabled */
 		pm_state_valid:1,				/* power_state[] has sane contents */
 		open:1,
 		medialock:1,
@@ -909,8 +914,10 @@
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int global_options = -1;
 static int global_full_duplex = -1;
+static int global_enable_wol = -1;
 
 /* #define dev_alloc_skb dev_alloc_skb_debug */
 
@@ -920,6 +927,18 @@
 
 static int vortex_cards_found;
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void poll_vortex(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned long flags;
+	local_save_flags(flags);
+	local_irq_disable();
+	(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL);
+	local_irq_restore(flags);
+} 
+#endif
+
 #ifdef CONFIG_PM
 
 static int vortex_suspend (struct pci_dev *pdev, u32 state)
@@ -1130,6 +1149,8 @@
 			vortex_debug = 7;
 		if (option & 0x4000)
 			vortex_debug = 2;
+		if (option & 0x0400)
+			vp->enable_wol = 1;
 	}
 
 	print_info = (vortex_debug > 1);
@@ -1217,12 +1238,16 @@
 
 	if (global_full_duplex > 0)
 		vp->full_duplex = 1;
+	if (global_enable_wol > 0)
+		vp->enable_wol = 1;
 
 	if (card_idx < MAX_UNITS) {
 		if (full_duplex[card_idx] > 0)
 			vp->full_duplex = 1;
 		if (flow_ctrl[card_idx] > 0)
 			vp->flow_ctrl = 1;
+		if (enable_wol[card_idx] > 0)
+			vp->enable_wol = 1;
 	}
 
 	vp->force_fd = vp->full_duplex;
@@ -1450,7 +1475,10 @@
 	dev->set_multicast_list = set_rx_mode;
 	dev->tx_timeout = vortex_tx_timeout;
 	dev->watchdog_timeo = (watchdog * HZ) / 1000;
-	if (pdev) {
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = poll_vortex; 
+#endif
+	if (pdev && vp->enable_wol) {
 		vp->pm_state_valid = 1;
  		pci_save_state(VORTEX_PCI(vp), vp->power_state);
  		acpi_set_WOL(dev);
@@ -1507,7 +1535,7 @@
 	unsigned int config;
 	int i;
 
-	if (VORTEX_PCI(vp)) {
+	if (VORTEX_PCI(vp) && vp->enable_wol) {
 		pci_set_power_state(VORTEX_PCI(vp), 0);	/* Go active */
 		pci_restore_state(VORTEX_PCI(vp), vp->power_state);
 	}
@@ -2656,7 +2684,7 @@
 	if (vp->full_bus_master_tx)
 		outl(0, ioaddr + DownListPtr);
 
-	if (VORTEX_PCI(vp)) {
+	if (VORTEX_PCI(vp) && vp->enable_wol) {
 		pci_save_state(VORTEX_PCI(vp), vp->power_state);
 		acpi_set_WOL(dev);
 	}
@@ -3033,7 +3061,7 @@
 	/* Should really use issue_and_wait() here */
 	outw(TotalReset|0x14, dev->base_addr + EL3_CMD);
 
-	if (VORTEX_PCI(vp)) {
+	if (VORTEX_PCI(vp) && vp->enable_wol) {
 		pci_set_power_state(VORTEX_PCI(vp), 0);	/* Go active */
 		if (vp->pm_state_valid)
 			pci_restore_state(VORTEX_PCI(vp), vp->power_state);
--- diff/drivers/net/8390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/8390.c	2004-02-18 09:04:00.000000000 +0000
@@ -516,6 +516,15 @@
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void ei_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	ei_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 /**
  * ei_tx_err - handle transmitter error
  * @dev: network device which threw the exception
@@ -1124,6 +1133,9 @@
 EXPORT_SYMBOL(ei_open);
 EXPORT_SYMBOL(ei_close);
 EXPORT_SYMBOL(ei_interrupt);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+EXPORT_SYMBOL(ei_poll);
+#endif
 EXPORT_SYMBOL(ei_tx_timeout);
 EXPORT_SYMBOL(NS8390_init);
 EXPORT_SYMBOL(__alloc_ei_netdev);
--- diff/drivers/net/8390.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/8390.h	2004-02-18 09:04:00.000000000 +0000
@@ -39,6 +39,10 @@
 #define ei_debug 1
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void ei_poll(struct net_device *dev);
+#endif
+
 extern void NS8390_init(struct net_device *dev, int startp);
 extern int ei_open(struct net_device *dev);
 extern int ei_close(struct net_device *dev);
--- diff/drivers/net/Kconfig	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -1354,8 +1354,9 @@
 	  say N.
 
 config E100
-	tristate "EtherExpressPro/100 support (e100, Alternate Intel driver)"
+	tristate "Intel(R) PRO/100+ support"
 	depends on NET_PCI && PCI
+	select MII
 	---help---
 	  This driver supports Intel(R) PRO/100 family of adapters, which 
 	  includes:
@@ -1428,6 +1429,10 @@
 	  <file:Documentation/networking/net-modules.txt>.  The module
 	  will be called e100.
 
+config E100_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on E100
+
 config LNE390
 	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
 	depends on NET_PCI && EISA && EXPERIMENTAL
@@ -2476,6 +2481,13 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called shaper.  If unsure, say N.
 
+config NETCONSOLE
+	tristate "Network console logging support (EXPERIMENTAL)"
+	depends on NETDEVICES && EXPERIMENTAL
+	---help---
+	If you want to log kernel messages over the network, enable this.
+	See Documentation/networking/netconsole.txt for details.
+
 source "drivers/net/wan/Kconfig"
 
 source "drivers/net/pcmcia/Kconfig"
--- diff/drivers/net/Makefile	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/Makefile	2004-02-18 09:04:00.000000000 +0000
@@ -8,7 +8,6 @@
   obj-$(CONFIG_ISDN) += slhc.o
 endif
 
-obj-$(CONFIG_E100) += e100/
 obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_BONDING) += bonding/
@@ -39,13 +38,13 @@
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
+obj-$(CONFIG_E100) += e100.o
 obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_EPIC100) += epic100.o
 obj-$(CONFIG_SIS190) += sis190.o
 obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_ACENIC) += acenic.o
-obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_NATSEMI) += natsemi.o
 obj-$(CONFIG_NS83820) += ns83820.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
@@ -188,3 +187,6 @@
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
 
+# Must come after all NICs that might use them
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_KGDB) += kgdb_eth.o
--- diff/drivers/net/ac3200.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ac3200.c	2004-02-18 09:04:00.000000000 +0000
@@ -276,6 +276,9 @@
 
 	dev->open = &ac_open;
 	dev->stop = &ac_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out1:
--- diff/drivers/net/acenic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/acenic.c	2004-02-18 09:04:00.000000000 +0000
@@ -731,12 +731,6 @@
 			break;
 		}
 
-		if (register_netdev(dev)) {
-			printk(KERN_ERR "acenic: device registration failed\n");
-			free_netdev(dev);
-			continue;
-		}
-
 		switch(pdev->vendor) {
 		case PCI_VENDOR_ID_ALTEON:
 			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
@@ -824,6 +818,13 @@
 			continue;
 		}
 
+		if (register_netdev(dev)) {
+			printk(KERN_ERR "acenic: device registration failed\n");
+			ace_init_cleanup(dev);
+			free_netdev(dev);
+			continue;
+		}
+
 		if (ap->pci_using_dac)
 			dev->features |= NETIF_F_HIGHDMA;
 
@@ -874,6 +875,7 @@
 	while (root_dev) {
 		ap = root_dev->priv;
 		next = ap->next;
+		unregister_netdev(root_dev);
 
 		regs = ap->regs;
 
@@ -1133,7 +1135,6 @@
 	if (dev->irq)
 		free_irq(dev->irq, dev);
 
-	unregister_netdev(dev);
 	iounmap(ap->regs);
 }
 
--- diff/drivers/net/amd8111e.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/amd8111e.c	2004-02-18 09:04:00.000000000 +0000
@@ -1153,6 +1153,17 @@
 	return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void amd8111e_poll(struct net_device *dev)
+{ 
+	unsigned long flags;
+	local_save_flags(flags); 
+	local_irq_disable();
+	amd8111e_interrupt(0, dev, NULL);
+	local_irq_restore(flags); 
+} 
+#endif
+
 /*
 This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down.
 */
@@ -1884,6 +1895,9 @@
 	dev->irq =pdev->irq;
 	dev->tx_timeout = amd8111e_tx_timeout; 
 	dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = amd8111e_poll; 
+#endif
 
 #if AMD8111E_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
--- diff/drivers/net/apne.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/apne.c	2004-02-18 09:04:00.000000000 +0000
@@ -333,6 +333,9 @@
     ei_status.get_8390_hdr = &apne_get_8390_hdr;
     dev->open = &apne_open;
     dev->stop = &apne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
     NS8390_init(dev, 0);
 
     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
@@ -580,6 +583,8 @@
 
 	pcmcia_reset();
 
+	release_region(IOBASE, 0x20);
+
 	free_netdev(apne_dev);
 }
 
--- diff/drivers/net/appletalk/cops.c	2003-09-17 12:28:07.000000000 +0100
+++ source/drivers/net/appletalk/cops.c	2004-02-18 09:04:00.000000000 +0000
@@ -262,7 +262,7 @@
 out1:
 	cleanup_card(dev);
 out:
-	kfree(dev);
+	free_netdev(dev);
 	return ERR_PTR(err);
 }
 
--- diff/drivers/net/arm/am79c961a.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/arm/am79c961a.c	2004-02-18 09:04:00.000000000 +0000
@@ -672,6 +672,10 @@
 	dev->base_addr = 0x220;
 	dev->irq = IRQ_EBSA110_ETHERNET;
 
+    	ret = -ENODEV;
+	if (!request_region(dev->base_addr, 0x18, dev->name))
+		goto nodev;
+
 	/*
 	 * Reset the device.
 	 */
@@ -682,14 +686,10 @@
 	 * Check the manufacturer part of the
 	 * ether address.
 	 */
-    	ret = -ENODEV;
 	if (inb(dev->base_addr) != 0x08 ||
 	    inb(dev->base_addr + 2) != 0x00 ||
 	    inb(dev->base_addr + 4) != 0x2b)
-	    	goto nodev;
-
-	if (!request_region(dev->base_addr, 0x18, dev->name))
-		goto nodev;
+	    	goto release;
 
 	am79c961_banner();
 	printk(KERN_INFO "%s: ether address ", dev->name);
--- diff/drivers/net/bonding/bond_3ad.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bond_3ad.c	2004-02-18 09:04:00.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+ * Copyright(c) 1999 - 2004 Intel Corporation. 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
@@ -48,7 +48,7 @@
  *	  problem on very high Tx traffic load where packets may get dropped
  *	  by the slave.
  *
- * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Code cleanup and style changes
  */
 
--- diff/drivers/net/bonding/bond_3ad.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bond_3ad.h	2004-02-18 09:04:00.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+ * Copyright(c) 1999 - 2004 Intel Corporation. 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
@@ -29,7 +29,7 @@
  *	- Renamed bond_3ad_link_status_changed() to
  *	  bond_3ad_handle_link_change() for compatibility with TLB.
  *
- * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Code cleanup and style changes
  */
 
--- diff/drivers/net/bonding/bond_alb.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bond_alb.c	2004-02-18 09:04:00.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+ * Copyright(c) 1999 - 2004 Intel Corporation. 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
@@ -29,8 +29,11 @@
  *	- Add support for setting bond's MAC address with special
  *	  handling required for ALB/TLB.
  *
- * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Code cleanup and style changes
+ *
+ * 2003/12/30 - Amir Noam <amir.noam at intel dot com>
+ *	- Fixed: Cannot remove and re-enslave the original active slave.
  */
 
 //#define BONDING_DEBUG 1
@@ -992,6 +995,7 @@
 static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
 {
 	struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
+	struct slave *has_bond_addr = bond->curr_active_slave;
 	int i, j, found = 0;
 
 	if (bond->slave_cnt == 0) {
@@ -1049,6 +1053,15 @@
 			free_mac_slave = tmp_slave1;
 			break;
 		}
+
+		if (!has_bond_addr) {
+			if (!memcmp(tmp_slave1->dev->dev_addr,
+				    bond->dev->dev_addr,
+				    ETH_ALEN)) {
+
+				has_bond_addr = tmp_slave1;
+			}
+		}
 	}
 
 	if (free_mac_slave) {
@@ -1059,7 +1072,8 @@
 		       ": Warning: the hw address of slave %s is in use by "
 		       "the bond; giving it the hw address of %s\n",
 		       slave->dev->name, free_mac_slave->dev->name);
-	} else {
+
+	} else if (has_bond_addr) {
 		printk(KERN_ERR DRV_NAME
 		       ": Error: the hw address of slave %s is in use by the "
 		       "bond; couldn't find a slave with a free hw address to "
@@ -1171,7 +1185,7 @@
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 {
 	struct bonding *bond = bond_dev->priv;
-	struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data;
+	struct ethhdr *eth_data;
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct slave *tx_slave = NULL;
 	static u32 ip_bcast = 0xffffffff;
@@ -1180,6 +1194,9 @@
 	u32 hash_index = 0;
 	u8 *hash_start = NULL;
 
+	skb->mac.raw = (unsigned char *)skb->data;
+	eth_data = (struct ethhdr *)skb->data;
+
 	/* make sure that the curr_active_slave and the slaves list do
 	 * not change during tx
 	 */
@@ -1217,8 +1234,7 @@
 			break;
 		}
 
-		if (ipx_hdr(skb)->ipx_type !=
-		    __constant_htons(IPX_TYPE_NCP)) {
+		if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) {
 			/* The only protocol worth balancing in
 			 * this family since it has an "ARP" like
 			 * mechanism
--- diff/drivers/net/bonding/bond_alb.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bond_alb.h	2004-02-18 09:04:00.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+ * Copyright(c) 1999 - 2004 Intel Corporation. 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
@@ -25,7 +25,7 @@
  *	- Add support for setting bond's MAC address with special
  *	  handling required for ALB/TLB.
  *
- * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Code cleanup and style changes
  */
 
--- diff/drivers/net/bonding/bond_main.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bond_main.c	2004-02-18 09:04:00.000000000 +0000
@@ -452,6 +452,15 @@
  *	  o Change struct member names and types.
  *	  o Chomp trailing spaces, remove empty lines, fix indentations.
  *	  o Re-organize code according to context.
+ *
+ * 2003/12/30 - Amir Noam <amir.noam at intel dot com>
+ *	- Fixed: Cannot remove and re-enslave the original active slave.
+ *	- Fixed: Releasing the original active slave causes mac address duplication.
+ *	- Add support for slaves that use ethtool_ops.
+ *	  Set version to 2.5.3.
+ *
+ * 2004/01/05 - Amir Noam <amir.noam at intel dot com>
+ *	- Save bonding parameters per bond instead of using the global values.
  */
 
 //#define BONDING_DEBUG 1
@@ -503,7 +512,6 @@
 /* monitor all links that often (in milliseconds). <=0 disables monitoring */
 #define BOND_LINK_MON_INTERV	0
 #define BOND_LINK_ARP_INTERV	0
-#define MAX_ARP_IP_TARGETS	16
 
 static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int miimon	= BOND_LINK_MON_INTERV;
@@ -514,7 +522,7 @@
 static char *primary	= NULL;
 static char *lacp_rate	= NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
-static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, };
+static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
 
 MODULE_PARM(max_bonds, "i");
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
@@ -534,7 +542,7 @@
 MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)");
 MODULE_PARM(arp_interval, "i");
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
-MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s");
+MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(BOND_MAX_ARP_TARGETS) "s");
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 
 /*----------------------------- Global variables ----------------------------*/
@@ -548,7 +556,7 @@
 static struct proc_dir_entry *bond_proc_dir = NULL;
 #endif
 
-static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ;
+static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
 static int arp_ip_count	= 0;
 static u32 my_ip	= 0;
 static int bond_mode	= BOND_MODE_ROUNDROBIN;
@@ -584,11 +592,15 @@
 {	NULL,			-1},
 };
 
+/*-------------------------- Forward declarations ---------------------------*/
+
+static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode);
+
 /*---------------------------- General routines -----------------------------*/
 
-static const char *bond_mode_name(void)
+static const char *bond_mode_name(int mode)
 {
-	switch (bond_mode) {
+	switch (mode) {
 	case BOND_MODE_ROUNDROBIN :
 		return "load balancing (round-robin)";
 	case BOND_MODE_ACTIVEBACKUP :
@@ -623,44 +635,55 @@
 	struct ifreq ifr;
 	struct ethtool_cmd etool;
 
-	ioctl = slave_dev->do_ioctl;
-	if (ioctl) {
-		etool.cmd = ETHTOOL_GSET;
-		ifr.ifr_data = (char*)&etool;
-		if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
-			slave->speed = etool.speed;
-			slave->duplex = etool.duplex;
-		} else {
-			goto err_out;
+	/* Fake speed and duplex */
+	slave->speed = SPEED_100;
+	slave->duplex = DUPLEX_FULL;
+
+	if (slave_dev->ethtool_ops) {
+		u32 res;
+
+		if (!slave_dev->ethtool_ops->get_settings) {
+			return -1;
 		}
-	} else {
-		goto err_out;
+
+		res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
+		if (res < 0) {
+			return -1;
+		}
+
+		goto verify;
 	}
 
-	switch (slave->speed) {
+	ioctl = slave_dev->do_ioctl;
+	strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
+	etool.cmd = ETHTOOL_GSET;
+	ifr.ifr_data = (char*)&etool;
+	if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) {
+		return -1;
+	}
+
+verify:
+	switch (etool.speed) {
 	case SPEED_10:
 	case SPEED_100:
 	case SPEED_1000:
 		break;
 	default:
-		goto err_out;
+		return -1;
 	}
 
-	switch (slave->duplex) {
+	switch (etool.duplex) {
 	case DUPLEX_FULL:
 	case DUPLEX_HALF:
 		break;
 	default:
-		goto err_out;
+		return -1;
 	}
 
-	return 0;
+	slave->speed = etool.speed;
+	slave->duplex = etool.duplex;
 
-err_out:
-	/* Fake speed and duplex */
-	slave->speed = SPEED_100;
-	slave->duplex = DUPLEX_FULL;
-	return -1;
+	return 0;
 }
 
 /*
@@ -679,14 +702,14 @@
  * It'd be nice if there was a good way to tell if a driver supports
  * netif_carrier, but there really isn't.
  */
-static int bond_check_dev_link(struct net_device *slave_dev, int reporting)
+static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting)
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
 	struct mii_ioctl_data *mii;
 	struct ethtool_value etool;
 
-	if (use_carrier) {
+	if (bond->params.use_carrier) {
 		return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
 	}
 
@@ -705,6 +728,7 @@
 		 */
 
 		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+		strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
 		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
 		if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
 			mii->reg_num = MII_BMSR;
@@ -712,10 +736,23 @@
 				return (mii->val_out & BMSR_LSTATUS);
 			}
 		}
+	}
+
+	/* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
+	/* for a period of time so we attempt to get link status   */
+	/* from it last if the above MII ioctls fail...            */
+	if (slave_dev->ethtool_ops) {
+		if (slave_dev->ethtool_ops->get_link) {
+			u32 link;
+
+			link = slave_dev->ethtool_ops->get_link(slave_dev);
+
+			return link ? BMSR_LSTATUS : 0;
+		}
+	}
 
-		/* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
-		/* for a period of time so we attempt to get link status   */
-		/* from it last if the above MII ioctls fail...            */
+	if (ioctl) {
+		strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
 		etool.cmd = ETHTOOL_GLINK;
 		ifr.ifr_data = (char*)&etool;
 		if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
@@ -769,7 +806,7 @@
  */
 static void bond_set_promiscuity(struct bonding *bond, int inc)
 {
-	if (USES_PRIMARY(bond_mode)) {
+	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
 			dev_set_promiscuity(bond->curr_active_slave->dev, inc);
@@ -788,7 +825,7 @@
  */
 static void bond_set_allmulti(struct bonding *bond, int inc)
 {
-	if (USES_PRIMARY(bond_mode)) {
+	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
 			dev_set_allmulti(bond->curr_active_slave->dev, inc);
@@ -808,7 +845,7 @@
  */
 static void bond_mc_add(struct bonding *bond, void *addr, int alen)
 {
-	if (USES_PRIMARY(bond_mode)) {
+	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
 			dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0);
@@ -828,7 +865,7 @@
  */
 static void bond_mc_delete(struct bonding *bond, void *addr, int alen)
 {
-	if (USES_PRIMARY(bond_mode)) {
+	if (USES_PRIMARY(bond->params.mode)) {
 		/* write lock already acquired */
 		if (bond->curr_active_slave) {
 			dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0);
@@ -888,13 +925,14 @@
  */
 static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev)
 {
+	struct bonding *bond = bond_dev->priv;
 	struct dev_mc_list *dmi;
 
 	for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
 		dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
 	}
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		/* del lacpdu mc addr from mc list */
 		u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
@@ -913,7 +951,7 @@
 {
 	struct dev_mc_list *dmi;
 
-	if (!USES_PRIMARY(bond_mode)) {
+	if (!USES_PRIMARY(bond->params.mode)) {
 		/* nothing to do -  mc list is already up-to-date on
 		 * all slaves
 		 */
@@ -959,7 +997,7 @@
 {
 	struct slave *new_active, *old_active;
 	struct slave *bestslave = NULL;
-	int mintime;
+	int mintime = bond->params.updelay;
 	int i;
 
 	new_active = old_active = bond->curr_active_slave;
@@ -972,15 +1010,13 @@
 		}
 	}
 
-	mintime = updelay;
-
 	/* first try the primary link; if arping, a link must tx/rx traffic
 	 * before it can be considered the curr_active_slave - also, we would skip
 	 * slaves between the curr_active_slave and primary_slave that may be up
 	 * and able to arp
 	 */
 	if ((bond->primary_slave) &&
-	    (!arp_interval) &&
+	    (!bond->params.arp_interval) &&
 	    (IS_UP(bond->primary_slave->dev))) {
 		new_active = bond->primary_slave;
 	}
@@ -1030,28 +1066,28 @@
 
 	if (new_active) {
 		if (new_active->link == BOND_LINK_BACK) {
-			if (USES_PRIMARY(bond_mode)) {
+			if (USES_PRIMARY(bond->params.mode)) {
 				printk(KERN_INFO DRV_NAME
 				       ": %s: making interface %s the new "
 				       "active one %d ms earlier.\n",
 				       bond->dev->name, new_active->dev->name,
-				       (updelay - new_active->delay) * miimon);
+				       (bond->params.updelay - new_active->delay) * bond->params.miimon);
 			}
 
 			new_active->delay = 0;
 			new_active->link = BOND_LINK_UP;
 			new_active->jiffies = jiffies;
 
-			if (bond_mode == BOND_MODE_8023AD) {
+			if (bond->params.mode == BOND_MODE_8023AD) {
 				bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
 			}
 
-			if ((bond_mode == BOND_MODE_TLB) ||
-			    (bond_mode == BOND_MODE_ALB)) {
+			if ((bond->params.mode == BOND_MODE_TLB) ||
+			    (bond->params.mode == BOND_MODE_ALB)) {
 				bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
 			}
 		} else {
-			if (USES_PRIMARY(bond_mode)) {
+			if (USES_PRIMARY(bond->params.mode)) {
 				printk(KERN_INFO DRV_NAME
 				       ": %s: making interface %s the new "
 				       "active one.\n",
@@ -1060,7 +1096,7 @@
 		}
 	}
 
-	if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
+	if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
 		if (old_active) {
 			bond_set_slave_inactive_flags(old_active);
 		}
@@ -1070,12 +1106,12 @@
 		}
 	}
 
-	if (USES_PRIMARY(bond_mode)) {
+	if (USES_PRIMARY(bond->params.mode)) {
 		bond_mc_swap(bond, new_active, old_active);
 	}
 
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
+	if ((bond->params.mode == BOND_MODE_TLB) ||
+	    (bond->params.mode == BOND_MODE_ALB)) {
 		bond_alb_handle_active_change(bond, new_active);
 	} else {
 		bond->curr_active_slave = new_active;
@@ -1230,13 +1266,13 @@
 			return -EINVAL;
 		}
 
-		if ((bond_mode == BOND_MODE_8023AD) ||
-		    (bond_mode == BOND_MODE_TLB)    ||
-		    (bond_mode == BOND_MODE_ALB)) {
+		if ((bond->params.mode == BOND_MODE_8023AD) ||
+		    (bond->params.mode == BOND_MODE_TLB)    ||
+		    (bond->params.mode == BOND_MODE_ALB)) {
 			printk(KERN_ERR DRV_NAME
 			       ": Error: to use %s mode, you must upgrade "
 			       "ifenslave.\n",
-			       bond_mode_name());
+			       bond_mode_name(bond->params.mode));
 			return -EOPNOTSUPP;
 		}
 	}
@@ -1292,8 +1328,8 @@
 
 	new_slave->dev = slave_dev;
 
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
+	if ((bond->params.mode == BOND_MODE_TLB) ||
+	    (bond->params.mode == BOND_MODE_ALB)) {
 		/* bond_alb_init_slave() must be called before all other stages since
 		 * it might fail and we do not want to have to undo everything
 		 */
@@ -1308,7 +1344,7 @@
 	 * curr_active_slave, and that is taken care of later when calling
 	 * bond_change_active()
 	 */
-	if (!USES_PRIMARY(bond_mode)) {
+	if (!USES_PRIMARY(bond->params.mode)) {
 		/* set promiscuity level to new slave */
 		if (bond_dev->flags & IFF_PROMISC) {
 			dev_set_promiscuity(slave_dev, 1);
@@ -1325,7 +1361,7 @@
 		}
 	}
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		/* add lacpdu mc addr to mc list */
 		u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
@@ -1339,10 +1375,10 @@
 	new_slave->delay = 0;
 	new_slave->link_failure_count = 0;
 
-	if (miimon && !use_carrier) {
-		link_reporting = bond_check_dev_link(slave_dev, 1);
+	if (bond->params.miimon && !bond->params.use_carrier) {
+		link_reporting = bond_check_dev_link(bond, slave_dev, 1);
 
-		if ((link_reporting == -1) && !arp_interval) {
+		if ((link_reporting == -1) && !bond->params.arp_interval) {
 			/*
 			 * miimon is set but a bonded network driver
 			 * does not support ETHTOOL/MII and
@@ -1372,13 +1408,13 @@
 	}
 
 	/* check for initial state */
-	if (!miimon ||
-	    (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) {
-		if (updelay) {
+	if (!bond->params.miimon ||
+	    (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) {
+		if (bond->params.updelay) {
 			dprintk("Initial state of slave_dev is "
 				"BOND_LINK_BACK\n");
 			new_slave->link  = BOND_LINK_BACK;
-			new_slave->delay = updelay;
+			new_slave->delay = bond->params.updelay;
 		} else {
 			dprintk("Initial state of slave_dev is "
 				"BOND_LINK_UP\n");
@@ -1398,7 +1434,7 @@
 		       "forced to 100Mbps, duplex forced to Full.\n",
 		       new_slave->dev->name);
 
-		if (bond_mode == BOND_MODE_8023AD) {
+		if (bond->params.mode == BOND_MODE_8023AD) {
 			printk(KERN_WARNING
 			       "Operation of 802.3ad mode requires ETHTOOL "
 			       "support in base driver for proper aggregator "
@@ -1406,14 +1442,14 @@
 		}
 	}
 
-	if (USES_PRIMARY(bond_mode) && primary) {
+	if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
 		/* if there is a primary slave, remember it */
-		if (strcmp(primary, new_slave->dev->name) == 0) {
+		if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
 			bond->primary_slave = new_slave;
 		}
 	}
 
-	switch (bond_mode) {
+	switch (bond->params.mode) {
 	case BOND_MODE_ACTIVEBACKUP:
 		/* if we're in active-backup mode, we need one and only one active
 		 * interface. The backup interfaces will have their NOARP flag set
@@ -1447,7 +1483,7 @@
 			 * can be called only after the mac address of the bond is set
 			 */
 			bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL,
-					    lacp_fast);
+					    bond->params.lacp_fast);
 		} else {
 			SLAVE_AD_INFO(new_slave).id =
 				SLAVE_AD_INFO(new_slave->prev).id + 1;
@@ -1557,7 +1593,7 @@
 static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 {
 	struct bonding *bond = bond_dev->priv;
-	struct slave *slave;
+	struct slave *slave, *oldcurrent;
 	struct sockaddr addr;
 	int mac_addr_differ;
 
@@ -1603,7 +1639,7 @@
 	}
 
 	/* Inform AD package of unbinding of slave. */
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		/* must be called before the slave is
 		 * detached from the list
 		 */
@@ -1617,6 +1653,8 @@
 	       ? "active" : "backup",
 	       slave_dev->name);
 
+	oldcurrent = bond->curr_active_slave;
+
 	bond->current_arp_slave = NULL;
 
 	/* release the slave from its bond */
@@ -1626,34 +1664,38 @@
 		bond->primary_slave = NULL;
 	}
 
-	if (bond->curr_active_slave == slave) {
+	if (oldcurrent == slave) {
 		bond_change_active_slave(bond, NULL);
-		bond_select_active_slave(bond);
 	}
 
-	if (!bond->curr_active_slave) {
-		printk(KERN_INFO DRV_NAME
-		       ": %s: now running without any active "
-		       "interface !\n",
-		       bond_dev->name);
-	}
-
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
-		/* must be called only after the slave has been
+	if ((bond->params.mode == BOND_MODE_TLB) ||
+	    (bond->params.mode == BOND_MODE_ALB)) {
+		/* Must be called only after the slave has been
 		 * detached from the list and the curr_active_slave
-		 * has been replaced (if our_slave == old_current)
+		 * has been cleared (if our_slave == old_current),
+		 * but before a new active slave is selected.
 		 */
 		bond_alb_deinit_slave(bond, slave);
 	}
 
+	if (oldcurrent == slave) {
+		bond_select_active_slave(bond);
+
+		if (!bond->curr_active_slave) {
+			printk(KERN_INFO DRV_NAME
+			       ": %s: now running without any active "
+			       "interface !\n",
+			       bond_dev->name);
+		}
+	}
+
 	write_unlock_bh(&bond->lock);
 
 	/* If the mode USES_PRIMARY, then we should only remove its
 	 * promisc and mc settings if it was the curr_active_slave, but that was
 	 * already taken care of above when we detached the slave
 	 */
-	if (!USES_PRIMARY(bond_mode)) {
+	if (!USES_PRIMARY(bond->params.mode)) {
 		/* unset promiscuity level from slave */
 		if (bond_dev->flags & IFF_PROMISC) {
 			dev_set_promiscuity(slave_dev, -1);
@@ -1725,15 +1767,15 @@
 		/* Inform AD package of unbinding of slave
 		 * before slave is detached from the list.
 		 */
-		if (bond_mode == BOND_MODE_8023AD) {
+		if (bond->params.mode == BOND_MODE_8023AD) {
 			bond_3ad_unbind_slave(slave);
 		}
 
 		slave_dev = slave->dev;
 		bond_detach_slave(bond, slave);
 
-		if ((bond_mode == BOND_MODE_TLB) ||
-		    (bond_mode == BOND_MODE_ALB)) {
+		if ((bond->params.mode == BOND_MODE_TLB) ||
+		    (bond->params.mode == BOND_MODE_ALB)) {
 			/* must be called only after the slave
 			 * has been detached from the list
 			 */
@@ -1750,7 +1792,7 @@
 		 * promisc and mc settings if it was the curr_active_slave, but that was
 		 * already taken care of above when we detached the slave
 		 */
-		if (!USES_PRIMARY(bond_mode)) {
+		if (!USES_PRIMARY(bond->params.mode)) {
 			/* unset promiscuity level from slave */
 			if (bond_dev->flags & IFF_PROMISC) {
 				dev_set_promiscuity(slave_dev, -1);
@@ -1824,6 +1866,10 @@
 	struct slave *new_active = NULL;
 	int res = 0;
 
+	if (!USES_PRIMARY(bond->params.mode)) {
+		return -EINVAL;
+	}
+
 	/* Verify that master_dev is indeed the master of slave_dev */
 	if (!(slave_dev->flags & IFF_SLAVE) ||
 	    (slave_dev->master != bond_dev)) {
@@ -1912,8 +1958,8 @@
 {
 	struct bonding *bond = bond_dev->priv;
 
-	info->bond_mode = bond_mode;
-	info->miimon = miimon;
+	info->bond_mode = bond->params.mode;
+	info->miimon = bond->params.miimon;
 
 	read_lock_bh(&bond->lock);
 	info->num_slaves = bond->slave_cnt;
@@ -1963,11 +2009,13 @@
 	struct bonding *bond = bond_dev->priv;
 	struct slave *slave, *oldcurrent;
 	int do_failover = 0;
-	int delta_in_ticks = (miimon * HZ) / 1000;
+	int delta_in_ticks;
 	int i;
 
 	read_lock(&bond->lock);
 
+	delta_in_ticks = (bond->params.miimon * HZ) / 1000;
+
 	if (bond->kill_timers) {
 		goto out;
 	}
@@ -1992,7 +2040,7 @@
 		u16 old_speed = slave->speed;
 		u8 old_duplex = slave->duplex;
 
-		link_state = bond_check_dev_link(slave_dev, 0);
+		link_state = bond_check_dev_link(bond, slave_dev, 0);
 
 		switch (slave->link) {
 		case BOND_LINK_UP:	/* the link was up */
@@ -2001,26 +2049,26 @@
 				break;
 			} else { /* link going down */
 				slave->link  = BOND_LINK_FAIL;
-				slave->delay = downdelay;
+				slave->delay = bond->params.downdelay;
 
 				if (slave->link_failure_count < UINT_MAX) {
 					slave->link_failure_count++;
 				}
 
-				if (downdelay) {
+				if (bond->params.downdelay) {
 					printk(KERN_INFO DRV_NAME
 					       ": %s: link status down for %s "
 					       "interface %s, disabling it in "
 					       "%d ms.\n",
 					       bond_dev->name,
 					       IS_UP(slave_dev)
-					       ? ((bond_mode == BOND_MODE_ACTIVEBACKUP)
+					       ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
 						  ? ((slave == oldcurrent)
 						     ? "active " : "backup ")
 						  : "")
 					       : "idle ",
 					       slave_dev->name,
-					       downdelay * miimon);
+					       bond->params.downdelay * bond->params.miimon);
 				}
 			}
 			/* no break ! fall through the BOND_LINK_FAIL test to
@@ -2036,8 +2084,8 @@
 					/* in active/backup mode, we must
 					 * completely disable this interface
 					 */
-					if ((bond_mode == BOND_MODE_ACTIVEBACKUP) ||
-					    (bond_mode == BOND_MODE_8023AD)) {
+					if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) ||
+					    (bond->params.mode == BOND_MODE_8023AD)) {
 						bond_set_slave_inactive_flags(slave);
 					}
 
@@ -2049,12 +2097,12 @@
 					       slave_dev->name);
 
 					/* notify ad that the link status has changed */
-					if (bond_mode == BOND_MODE_8023AD) {
+					if (bond->params.mode == BOND_MODE_8023AD) {
 						bond_3ad_handle_link_change(slave, BOND_LINK_DOWN);
 					}
 
-					if ((bond_mode == BOND_MODE_TLB) ||
-					    (bond_mode == BOND_MODE_ALB)) {
+					if ((bond->params.mode == BOND_MODE_TLB) ||
+					    (bond->params.mode == BOND_MODE_ALB)) {
 						bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN);
 					}
 
@@ -2072,7 +2120,7 @@
 				       ": %s: link status up again after %d "
 				       "ms for interface %s.\n",
 				       bond_dev->name,
-				       (downdelay - slave->delay) * miimon,
+				       (bond->params.downdelay - slave->delay) * bond->params.miimon,
 				       slave_dev->name);
 			}
 			break;
@@ -2082,9 +2130,9 @@
 				break;
 			} else {	/* link going up */
 				slave->link  = BOND_LINK_BACK;
-				slave->delay = updelay;
+				slave->delay = bond->params.updelay;
 
-				if (updelay) {
+				if (bond->params.updelay) {
 					/* if updelay == 0, no need to
 					   advertise about a 0 ms delay */
 					printk(KERN_INFO DRV_NAME
@@ -2093,7 +2141,7 @@
 					       "in %d ms.\n",
 					       bond_dev->name,
 					       slave_dev->name,
-					       updelay * miimon);
+					       bond->params.updelay * bond->params.miimon);
 				}
 			}
 			/* no break ! fall through the BOND_LINK_BACK state in
@@ -2108,7 +2156,7 @@
 				       ": %s: link status down again after %d "
 				       "ms for interface %s.\n",
 				       bond_dev->name,
-				       (updelay - slave->delay) * miimon,
+				       (bond->params.updelay - slave->delay) * bond->params.miimon,
 				       slave_dev->name);
 			} else {
 				/* link stays up */
@@ -2117,10 +2165,10 @@
 					slave->link = BOND_LINK_UP;
 					slave->jiffies = jiffies;
 
-					if (bond_mode == BOND_MODE_8023AD) {
+					if (bond->params.mode == BOND_MODE_8023AD) {
 						/* prevent it from being the active one */
 						slave->state = BOND_STATE_BACKUP;
-					} else if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
+					} else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
 						/* make it immediately active */
 						slave->state = BOND_STATE_ACTIVE;
 					} else if (slave != bond->primary_slave) {
@@ -2135,12 +2183,12 @@
 					       slave_dev->name);
 
 					/* notify ad that the link status has changed */
-					if (bond_mode == BOND_MODE_8023AD) {
+					if (bond->params.mode == BOND_MODE_8023AD) {
 						bond_3ad_handle_link_change(slave, BOND_LINK_UP);
 					}
 
-					if ((bond_mode == BOND_MODE_TLB) ||
-					    (bond_mode == BOND_MODE_ALB)) {
+					if ((bond->params.mode == BOND_MODE_TLB) ||
+					    (bond->params.mode == BOND_MODE_ALB)) {
 						bond_alb_handle_link_change(bond, slave, BOND_LINK_UP);
 					}
 
@@ -2162,7 +2210,7 @@
 
 		bond_update_speed_duplex(slave);
 
-		if (bond_mode == BOND_MODE_8023AD) {
+		if (bond->params.mode == BOND_MODE_8023AD) {
 			if (old_speed != slave->speed) {
 				bond_3ad_adapter_speed_changed(slave);
 			}
@@ -2190,17 +2238,20 @@
 	}
 
 re_arm:
-	mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
+	if (bond->params.miimon) {
+		mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
+	}
 out:
 	read_unlock(&bond->lock);
 }
 
-static void bond_arp_send_all(struct slave *slave)
+static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
 	int i;
+	u32 *targets = bond->params.arp_targets;
 
-	for (i = 0; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) {
-		arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[i], slave->dev,
+	for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
+		arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev,
 			 my_ip, NULL, slave->dev->dev_addr,
 			 NULL);
 	}
@@ -2218,11 +2269,13 @@
 	struct bonding *bond = bond_dev->priv;
 	struct slave *slave, *oldcurrent;
 	int do_failover = 0;
-	int delta_in_ticks = (arp_interval * HZ) / 1000;
+	int delta_in_ticks;
 	int i;
 
 	read_lock(&bond->lock);
 
+	delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
+
 	if (bond->kill_timers) {
 		goto out;
 	}
@@ -2307,7 +2360,7 @@
 		 * to be unstable during low/no traffic periods
 		 */
 		if (IS_UP(slave->dev)) {
-			bond_arp_send_all(slave);
+			bond_arp_send_all(bond, slave);
 		}
 	}
 
@@ -2327,7 +2380,9 @@
 	}
 
 re_arm:
-	mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+	if (bond->params.arp_interval) {
+		mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+	}
 out:
 	read_unlock(&bond->lock);
 }
@@ -2351,11 +2406,13 @@
 {
 	struct bonding *bond = bond_dev->priv;
 	struct slave *slave;
-	int delta_in_ticks = (arp_interval * HZ) / 1000;
+	int delta_in_ticks;
 	int i;
 
 	read_lock(&bond->lock);
 
+	delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
+
 	if (bond->kill_timers) {
 		goto out;
 	}
@@ -2514,7 +2571,7 @@
 		 * rx traffic
 		 */
 		if (slave && my_ip) {
-			bond_arp_send_all(slave);
+			bond_arp_send_all(bond, slave);
 		}
 	}
 
@@ -2535,7 +2592,7 @@
 				if (IS_UP(slave->dev)) {
 					slave->link = BOND_LINK_BACK;
 					bond_set_slave_active_flags(slave);
-					bond_arp_send_all(slave);
+					bond_arp_send_all(bond, slave);
 					slave->jiffies = jiffies;
 					bond->current_arp_slave = slave;
 					break;
@@ -2567,7 +2624,9 @@
 	}
 
 re_arm:
-	mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+	if (bond->params.arp_interval) {
+		mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+	}
 out:
 	read_unlock(&bond->lock);
 }
@@ -2625,33 +2684,40 @@
 	read_unlock(&dev_base_lock);
 }
 
-static void bond_info_show_master(struct seq_file *seq, struct bonding *bond)
+static void bond_info_show_master(struct seq_file *seq)
 {
+	struct bonding *bond = seq->private;
 	struct slave *curr;
 
 	read_lock(&bond->curr_slave_lock);
 	curr = bond->curr_active_slave;
 	read_unlock(&bond->curr_slave_lock);
 
-	seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name());
+	seq_printf(seq, "Bonding Mode: %s\n",
+		   bond_mode_name(bond->params.mode));
 
-	if (USES_PRIMARY(bond_mode)) {
-		if (curr) {
-			seq_printf(seq,
-				   "Currently Active Slave: %s\n",
-				   curr->dev->name);
-		}
+	if (USES_PRIMARY(bond->params.mode)) {
+		seq_printf(seq, "Primary Slave: %s\n",
+			   (bond->params.primary[0]) ?
+			   	bond->params.primary : "None");
+
+		seq_printf(seq, "Currently Active Slave: %s\n",
+			   (curr) ? curr->dev->name : "None");
 	}
 
 	seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down");
-	seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon);
-	seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon);
-	seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon);
+	seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
+	seq_printf(seq, "Up Delay (ms): %d\n",
+		   bond->params.updelay * bond->params.miimon);
+	seq_printf(seq, "Down Delay (ms): %d\n",
+		   bond->params.downdelay * bond->params.miimon);
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
 
 		seq_puts(seq, "\n802.3ad info\n");
+		seq_printf(seq, "LACP rate: %s\n",
+			   (bond->params.lacp_fast) ? "fast" : "slow");
 
 		if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
 			seq_printf(seq, "bond %s has no active aggregator\n",
@@ -2680,6 +2746,8 @@
 
 static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave)
 {
+	struct bonding *bond = seq->private;
+
 	seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
 	seq_printf(seq, "MII Status: %s\n",
 		   (slave->link == BOND_LINK_UP) ?  "up" : "down");
@@ -2697,7 +2765,7 @@
 			   slave->perm_hwaddr[5]);
 	}
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		const struct aggregator *agg
 			= SLAVE_AD_INFO(slave).port.aggregator;
 
@@ -2714,7 +2782,7 @@
 {
 	if (v == SEQ_START_TOKEN) {
 		seq_printf(seq, "%s\n", version);
-		bond_info_show_master(seq, seq->private);
+		bond_info_show_master(seq);
 	} else {
 		bond_info_show_slave(seq, v);
 	}
@@ -2989,14 +3057,14 @@
 
 	bond->kill_timers = 0;
 
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
+	if ((bond->params.mode == BOND_MODE_TLB) ||
+	    (bond->params.mode == BOND_MODE_ALB)) {
 		struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer);
 
 		/* bond_alb_initialize must be called before the timer
 		 * is started.
 		 */
-		if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) {
+		if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) {
 			/* something went wrong - fail the open operation */
 			return -1;
 		}
@@ -3008,7 +3076,7 @@
 		add_timer(alb_timer);
 	}
 
-	if (miimon) {  /* link check interval, in milliseconds. */
+	if (bond->params.miimon) {  /* link check interval, in milliseconds. */
 		init_timer(mii_timer);
 		mii_timer->expires  = jiffies + 1;
 		mii_timer->data     = (unsigned long)bond_dev;
@@ -3016,11 +3084,11 @@
 		add_timer(mii_timer);
 	}
 
-	if (arp_interval) {  /* arp interval, in milliseconds. */
+	if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
 		init_timer(arp_timer);
 		arp_timer->expires  = jiffies + 1;
 		arp_timer->data     = (unsigned long)bond_dev;
-		if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
+		if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
 			arp_timer->function = (void *)&bond_activebackup_arp_mon;
 		} else {
 			arp_timer->function = (void *)&bond_loadbalance_arp_mon;
@@ -3028,7 +3096,7 @@
 		add_timer(arp_timer);
 	}
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer);
 		init_timer(ad_timer);
 		ad_timer->expires  = jiffies + 1;
@@ -3051,7 +3119,7 @@
 
 	bond_mc_list_destroy(bond);
 
-	if (bond_mode == BOND_MODE_8023AD) {
+	if (bond->params.mode == BOND_MODE_8023AD) {
 		/* Unregister the receive of LACPDUs */
 		bond_unregister_lacpdu(bond);
 	}
@@ -3065,15 +3133,15 @@
 	 * because a running timer might be trying to hold it too
 	 */
 
-	if (miimon) {  /* link check interval, in milliseconds. */
+	if (bond->params.miimon) {  /* link check interval, in milliseconds. */
 		del_timer_sync(&bond->mii_timer);
 	}
 
-	if (arp_interval) {  /* arp interval, in milliseconds. */
+	if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
 		del_timer_sync(&bond->arp_timer);
 	}
 
-	switch (bond_mode) {
+	switch (bond->params.mode) {
 	case BOND_MODE_8023AD:
 		del_timer_sync(&(BOND_AD_INFO(bond).ad_timer));
 		break;
@@ -3088,8 +3156,8 @@
 	/* Release the bonded slaves */
 	bond_release_all(bond_dev);
 
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
+	if ((bond->params.mode == BOND_MODE_TLB) ||
+	    (bond->params.mode == BOND_MODE_ALB)) {
 		/* Must be called only after all
 		 * slaves have been released
 		 */
@@ -3269,11 +3337,7 @@
 			break;
 		case BOND_CHANGE_ACTIVE_OLD:
 		case SIOCBONDCHANGEACTIVE:
-			if (USES_PRIMARY(bond_mode)) {
-				res = bond_ioctl_change_active(bond_dev, slave_dev);
-			} else {
-				res = -EINVAL;
-			}
+			res = bond_ioctl_change_active(bond_dev, slave_dev);
 			break;
 		default:
 			res = -EOPNOTSUPP;
@@ -3556,7 +3620,7 @@
 
 	/* if we are sending arp packets, try to at least
 	   identify our own ip address */
-	if (arp_interval && !my_ip &&
+	if (bond->params.arp_interval && !my_ip &&
 		(skb->protocol == __constant_htons(ETH_P_ARP))) {
 		char *the_ip = (char *)skb->data +
 				sizeof(struct ethhdr) +
@@ -3717,13 +3781,47 @@
 /*------------------------- Device initialization ---------------------------*/
 
 /*
+ * set bond mode specific net device operations
+ */
+static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode)
+{
+	switch (mode) {
+	case BOND_MODE_ROUNDROBIN:
+		bond_dev->hard_start_xmit = bond_xmit_roundrobin;
+		break;
+	case BOND_MODE_ACTIVEBACKUP:
+		bond_dev->hard_start_xmit = bond_xmit_activebackup;
+		break;
+	case BOND_MODE_XOR:
+		bond_dev->hard_start_xmit = bond_xmit_xor;
+		break;
+	case BOND_MODE_BROADCAST:
+		bond_dev->hard_start_xmit = bond_xmit_broadcast;
+		break;
+	case BOND_MODE_8023AD:
+		bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
+		break;
+	case BOND_MODE_TLB:
+	case BOND_MODE_ALB:
+		bond_dev->hard_start_xmit = bond_alb_xmit;
+		bond_dev->set_mac_address = bond_alb_set_mac_address;
+		break;
+	default:
+		/* Should never happen, mode already checked */
+		printk(KERN_ERR DRV_NAME
+		       ": Error: Unknown bonding mode %d\n",
+		       mode);
+		break;
+	}
+}
+
+/*
  * Does not allocate but creates a /proc entry.
  * Allowed to fail.
  */
-static int __init bond_init(struct net_device *bond_dev)
+static int __init bond_init(struct net_device *bond_dev, struct bond_params *params)
 {
 	struct bonding *bond = bond_dev->priv;
-	int count;
 
 	dprintk("Begin bond_init for %s\n", bond_dev->name);
 
@@ -3731,6 +3829,8 @@
 	rwlock_init(&bond->lock);
 	rwlock_init(&bond->curr_slave_lock);
 
+	bond->params = *params; /* copy params struct */
+
 	/* Initialize pointers */
 	bond->first_slave = NULL;
 	bond->curr_active_slave = NULL;
@@ -3747,33 +3847,7 @@
 	bond_dev->change_mtu = bond_change_mtu;
 	bond_dev->set_mac_address = bond_set_mac_address;
 
-	switch (bond_mode) {
-	case BOND_MODE_ROUNDROBIN:
-		bond_dev->hard_start_xmit = bond_xmit_roundrobin;
-		break;
-	case BOND_MODE_ACTIVEBACKUP:
-		bond_dev->hard_start_xmit = bond_xmit_activebackup;
-		break;
-	case BOND_MODE_XOR:
-		bond_dev->hard_start_xmit = bond_xmit_xor;
-		break;
-	case BOND_MODE_BROADCAST:
-		bond_dev->hard_start_xmit = bond_xmit_broadcast;
-		break;
-	case BOND_MODE_8023AD:
-		bond_dev->hard_start_xmit = bond_3ad_xmit_xor; /* extern */
-		break;
-	case BOND_MODE_TLB:
-	case BOND_MODE_ALB:
-		bond_dev->hard_start_xmit = bond_alb_xmit; /* extern */
-		bond_dev->set_mac_address = bond_alb_set_mac_address; /* extern */
-		break;
-	default:
-		printk(KERN_ERR DRV_NAME
-		       ": Error: Unknown bonding mode %d\n",
-		       bond_mode);
-		return -EINVAL;
-	}
+	bond_set_mode_ops(bond_dev, bond->params.mode);
 
 	bond_dev->destructor = free_netdev;
 #ifdef CONFIG_NET_FASTROUTE
@@ -3784,27 +3858,6 @@
 	bond_dev->tx_queue_len = 0;
 	bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
 
-	printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name);
-	if (miimon) {
-		printk(" MII link monitoring set to %d ms", miimon);
-		updelay /= miimon;
-		downdelay /= miimon;
-	} else {
-		printk("out MII link monitoring");
-	}
-	printk(", in %s mode.\n", bond_mode_name());
-
-	printk(KERN_INFO DRV_NAME ": %s registered with", bond_dev->name);
-	if (arp_interval > 0) {
-		printk(" ARP monitoring set to %d ms with %d target(s):",
-		       arp_interval, arp_ip_count);
-		for (count=0 ; count<arp_ip_count ; count++) {
-			printk(" %s", arp_ip_target[count]);
-		}
-		printk("\n");
-	} else {
-		printk("out ARP monitoring\n");
-	}
 
 #ifdef CONFIG_PROC_FS
 	bond_create_proc_entry(bond);
@@ -3870,7 +3923,7 @@
 	return -1;
 }
 
-static int bond_check_params(void)
+static int bond_check_params(struct bond_params *params)
 {
 	/*
 	 * Convert string parameters.
@@ -3889,7 +3942,7 @@
 		if (bond_mode != BOND_MODE_8023AD) {
 			printk(KERN_INFO DRV_NAME
 			       ": lacp_rate param is irrelevant in mode %s\n",
-			       bond_mode_name());
+			       bond_mode_name(bond_mode));
 		} else {
 			lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl);
 			if (lacp_fast == -1) {
@@ -3933,17 +3986,17 @@
 		downdelay = 0;
 	}
 
+	if ((use_carrier != 0) && (use_carrier != 1)) {
+		printk(KERN_WARNING DRV_NAME
+		       ": Warning: use_carrier module parameter (%d), "
+		       "not of valid value (0/1), so it was set to 1\n",
+		       use_carrier);
+		use_carrier = 1;
+	}
+
 	/* reset values for 802.3ad */
 	if (bond_mode == BOND_MODE_8023AD) {
-		if (arp_interval) {
-			printk(KERN_WARNING DRV_NAME
-			       ": Warning: ARP monitoring can't be used "
-			       "simultaneously with 802.3ad, disabling ARP "
-			       "monitoring\n");
-			arp_interval = 0;
-		}
-
-		if (miimon) {
+		if (!miimon) {
 			printk(KERN_WARNING DRV_NAME
 			       ": Warning: miimon must be specified, "
 			       "otherwise bonding will not detect link "
@@ -4002,25 +4055,23 @@
 		}
 
 		if ((updelay % miimon) != 0) {
-			/* updelay will be rounded in bond_init() when it
-			 * is divided by miimon, we just inform user here
-			 */
 			printk(KERN_WARNING DRV_NAME
 			       ": Warning: updelay (%d) is not a multiple "
 			       "of miimon (%d), updelay rounded to %d ms\n",
 			       updelay, miimon, (updelay / miimon) * miimon);
 		}
 
+		updelay /= miimon;
+
 		if ((downdelay % miimon) != 0) {
-			/* downdelay will be rounded in bond_init() when it
-			 * is divided by miimon, we just inform user here
-			 */
 			printk(KERN_WARNING DRV_NAME
 			       ": Warning: downdelay (%d) is not a multiple "
 			       "of miimon (%d), downdelay rounded to %d ms\n",
 			       downdelay, miimon,
 			       (downdelay / miimon) * miimon);
 		}
+
+		downdelay /= miimon;
 	}
 
 	if (arp_interval < 0) {
@@ -4032,7 +4083,7 @@
 	}
 
 	for (arp_ip_count = 0;
-	     (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count];
+	     (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count];
 	     arp_ip_count++) {
 		/* not complete check, but should be good enough to
 		   catch mistakes */
@@ -4058,7 +4109,23 @@
 		arp_interval = 0;
 	}
 
-	if (!miimon && !arp_interval) {
+	if (miimon) {
+		printk(KERN_INFO DRV_NAME
+		       ": MII link monitoring set to %d ms\n",
+		       miimon);
+	} else if (arp_interval) {
+		int i;
+
+		printk(KERN_INFO DRV_NAME
+		       ": ARP monitoring set to %d ms with %d target(s):",
+		       arp_interval, arp_ip_count);
+
+		for (i = 0; i < arp_ip_count; i++)
+			printk (" %s", arp_ip_target[i]);
+
+		printk("\n");
+
+	} else {
 		/* miimon and arp_interval not set, we need one so things
 		 * work as expected, see bonding.txt for details
 		 */
@@ -4076,21 +4143,39 @@
 		printk(KERN_WARNING DRV_NAME
 		       ": Warning: %s primary device specified but has no "
 		       "effect in %s mode\n",
-		       primary, bond_mode_name());
+		       primary, bond_mode_name(bond_mode));
 		primary = NULL;
 	}
 
+	/* fill params struct with the proper values */
+	params->mode = bond_mode;
+	params->miimon = miimon;
+	params->arp_interval = arp_interval;
+	params->updelay = updelay;
+	params->downdelay = downdelay;
+	params->use_carrier = use_carrier;
+	params->lacp_fast = lacp_fast;
+	params->primary[0] = 0;
+
+	if (primary) {
+		strncpy(params->primary, primary, IFNAMSIZ);
+		params->primary[IFNAMSIZ - 1] = 0;
+	}
+
+	memcpy(params->arp_targets, arp_target, sizeof(arp_target));
+
 	return 0;
 }
 
 static int __init bonding_init(void)
 {
+	struct bond_params params;
 	int i;
 	int res;
 
 	printk(KERN_INFO "%s", version);
 
-	res = bond_check_params();
+	res = bond_check_params(&params);
 	if (res) {
 		return res;
 	}
@@ -4120,7 +4205,7 @@
 		 * /proc files), but before register_netdevice(), because we
 		 * need to set function pointers.
 		 */
-		res = bond_init(bond_dev);
+		res = bond_init(bond_dev, &params);
 		if (res < 0) {
 			free_netdev(bond_dev);
 			goto out_err;
--- diff/drivers/net/bonding/bonding.h	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/bonding/bonding.h	2004-02-18 09:04:00.000000000 +0000
@@ -23,7 +23,7 @@
  * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Added support for Transmit load balancing mode.
  *
- * 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Code cleanup and style changes
  */
 
@@ -36,11 +36,13 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"2.5.0"
-#define DRV_RELDATE	"December 1, 2003"
+#define DRV_VERSION	"2.5.4"
+#define DRV_RELDATE	"December 30, 2003"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
+#define BOND_MAX_ARP_TARGETS	16
+
 #ifdef BONDING_DEBUG
 #define dprintk(fmt, args...) \
 	printk(KERN_DEBUG     \
@@ -133,6 +135,18 @@
 		bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave)
 
 
+struct bond_params {
+	int mode;
+	int miimon;
+	int arp_interval;
+	int use_carrier;
+	int updelay;
+	int downdelay;
+	int lacp_fast;
+	char primary[IFNAMSIZ];
+	u32 arp_targets[BOND_MAX_ARP_TARGETS];
+};
+
 struct slave {
 	struct net_device *dev; /* first - usefull for panic debug */
 	struct slave *next;
@@ -181,6 +195,7 @@
 	u16      flags;
 	struct   ad_bond_info ad_info;
 	struct   alb_bond_info alb_info;
+	struct   bond_params params;
 };
 
 /**
--- diff/drivers/net/bsd_comp.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/net/bsd_comp.c	2004-02-18 09:04:00.000000000 +0000
@@ -1176,3 +1176,4 @@
 module_init(bsdcomp_init);
 module_exit(bsdcomp_cleanup);
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS));
--- diff/drivers/net/depca.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/depca.c	2004-02-18 09:04:00.000000000 +0000
@@ -2086,7 +2086,7 @@
 {
         int err = 0;
 
-#if CONFIG_MCA
+#ifdef CONFIG_MCA
         err = mca_register_driver (&depca_mca_driver);
 #endif
 #ifdef CONFIG_EISA
@@ -2101,7 +2101,7 @@
 static void __exit depca_module_exit (void)
 {
 	int i;
-#if CONFIG_MCA
+#ifdef CONFIG_MCA
         mca_unregister_driver (&depca_mca_driver);
 #endif
 #ifdef CONFIG_EISA
--- diff/drivers/net/dgrs.c	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/net/dgrs.c	2004-02-18 09:04:00.000000000 +0000
@@ -121,11 +121,22 @@
 #include "dgrs_asstruct.h"
 #include "dgrs_bcomm.h"
 
+#ifdef CONFIG_PCI
 static struct pci_device_id dgrs_pci_tbl[] = {
 	{ SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
+#endif
+
+#ifdef CONFIG_EISA
+static struct eisa_device_id dgrs_eisa_tbl[] = {
+	{ "DBI0A01" },
+	{ }
+};
+MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
+#endif
+
 MODULE_LICENSE("GPL");
 
 
@@ -179,11 +190,6 @@
 static int	dgrs_nicmode;
 
 /*
- *	Chain of device structures
- */
-static struct net_device *dgrs_root_dev;
-
-/*
  *	Private per-board data structure (dev->priv)
  */
 typedef struct
@@ -191,7 +197,6 @@
 	/*
 	 *	Stuff for generic ethercard I/F
 	 */
-	struct net_device		*next_dev;
 	struct net_device_stats	stats;
 
 	/*
@@ -1187,7 +1192,7 @@
 	priv->intrcnt = 0;
 	for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
 	{
-		barrier();		/* gcc 2.95 needs this */
+		cpu_relax();
 		if (priv->intrcnt >= 2)
 			break;
 	}
@@ -1200,16 +1205,6 @@
 	}
 
 	/*
-	 *	Register the /proc/ioports information...
-	 */
-	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...
 	 */
 	dev->open = &dgrs_open;
@@ -1242,22 +1237,23 @@
 	return (0);
 }
 
-static int __init 
+static struct net_device * __init 
 dgrs_found_device(
 	int		io,
 	ulong		mem,
 	int		irq,
 	ulong		plxreg,
-	ulong		plxdma
+	ulong		plxdma,
+	struct device   *pdev
 )
 {
-	DGRS_PRIV	*priv;
-	struct net_device *dev, *aux;
-	int i, ret;
+	DGRS_PRIV *priv;
+	struct net_device *dev;
+	int i, ret = -ENOMEM;
 
 	dev = alloc_etherdev(sizeof(DGRS_PRIV));
 	if (!dev)
-		return -ENOMEM;
+		goto err0;
 
 	priv = (DGRS_PRIV *)dev->priv;
 
@@ -1272,19 +1268,19 @@
 	priv->chan = 1;
 	priv->devtbl[0] = dev;
 
-	dev->init = dgrs_probe1;
 	SET_MODULE_OWNER(dev);
-
-	if (register_netdev(dev) != 0) {
-		free_netdev(dev);
-		return -EIO;
-	}
-
-	priv->next_dev = dgrs_root_dev;
-	dgrs_root_dev = dev;
+	SET_NETDEV_DEV(dev, pdev);
+	
+	ret = dgrs_probe1(dev);
+	if (ret) 
+		goto err1;
+
+	ret = register_netdev(dev);
+	if (ret)
+		goto err2;
 
 	if ( !dgrs_nicmode )
-		return (0);	/* Switch mode, we are done */
+		return dev;	/* Switch mode, we are done */
 
 	/*
 	 * Operating card as N separate NICs
@@ -1302,8 +1298,7 @@
 		if (!devN) 
 			goto fail;
 
-		/* Make it an exact copy of dev[0]... */
-		*devN = *dev;
+		/* Don't copy the network device structure! */
 
 		/* copy the priv structure of dev[0] */
 		privN = (DGRS_PRIV *)devN->priv;
@@ -1316,123 +1311,212 @@
 		devN->irq = 0;
 			/* ... and base MAC address off address of 1st port */
 		devN->dev_addr[5] += i;
-			/* ... choose a new name */
-		strncpy(devN->name, "eth%d", IFNAMSIZ);
-		devN->init = dgrs_initclone;
+
+		ret = dgrs_initclone(devN);
+		if (ret)
+			goto fail;
+
 		SET_MODULE_OWNER(devN);
+		SET_NETDEV_DEV(dev, pdev);
 
-		ret = -EIO;
-		if (register_netdev(devN)) {
+		ret = register_netdev(devN);
+		if (ret) {
 			free_netdev(devN);
 			goto fail;
 		}
 		privN->chan = i+1;
 		priv->devtbl[i] = devN;
-		privN->next_dev = dgrs_root_dev;
-		dgrs_root_dev = devN;
 	}
-	return 0;
-fail:	aux = priv->next_dev;
-	while (dgrs_root_dev != aux) {
-		struct net_device *d = dgrs_root_dev;
-		
-		dgrs_root_dev = ((DGRS_PRIV *)d->priv)->next_dev;
+	return dev;
+
+ fail:	
+	while (i >= 0) {
+		struct net_device *d = priv->devtbl[i--];
 		unregister_netdev(d);
 		free_netdev(d);
 	}
-	return ret;
+
+ err2:
+	free_irq(dev->irq, dev);
+ err1:
+	free_netdev(dev);
+ err0:
+	return ERR_PTR(ret);
 }
 
-/*
- *	Scan for all boards
- */
-static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
+static void __devexit dgrs_remove(struct net_device *dev)
+{
+	DGRS_PRIV *priv = dev->priv;
+	int i;
+
+	unregister_netdev(dev);
+
+	for (i = 1; i < priv->nports; ++i) {
+		struct net_device *d = priv->devtbl[i];
+		if (d) {
+			unregister_netdev(d);
+			free_netdev(d);
+		}
+	}
+
+	proc_reset(priv->devtbl[0], 1);
 
-static int __init  dgrs_scan(void)
+	if (priv->vmem)
+		iounmap(priv->vmem);
+	if (priv->vplxdma)
+		iounmap((uchar *) priv->vplxdma);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
+	for (i = 1; i < priv->nports; ++i) {
+		if (priv->devtbl[i])
+			unregister_netdev(priv->devtbl[i]);
+	}
+}
+
+#ifdef CONFIG_PCI
+static int __init dgrs_pci_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
 {
-	int	cards_found = 0;
+	struct net_device *dev;
+	int err;
 	uint	io;
 	uint	mem;
 	uint	irq;
 	uint	plxreg;
 	uint	plxdma;
-	struct pci_dev *pdev = NULL;
 
 	/*
-	 *	First, check for PCI boards
-	 */
-	while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL)
-	{
-		/*
-		 * Get and check the bus-master and latency values.
-		 * Some PCI BIOSes fail to set the master-enable bit,
-		 * and the latency timer must be set to the maximum
-		 * value to avoid data corruption that occurs when the
-		 * timer expires during a transfer.  Yes, it's a bug.
-		 */
-		if (pci_enable_device(pdev))
-			continue;
-		pci_set_master(pdev);
-
-		plxreg = pci_resource_start (pdev, 0);
-		io = pci_resource_start (pdev, 1);
-		mem = pci_resource_start (pdev, 2);
-		pci_read_config_dword(pdev, 0x30, &plxdma);
-		irq = pdev->irq;
-		plxdma &= ~15;
+	 * Get and check the bus-master and latency values.
+	 * Some PCI BIOSes fail to set the master-enable bit,
+	 * and the latency timer must be set to the maximum
+	 * value to avoid data corruption that occurs when the
+	 * timer expires during a transfer.  Yes, it's a bug.
+	 */
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+	err = pci_request_regions(pdev, "RightSwitch");
+	if (err)
+		return err;
+
+	pci_set_master(pdev);
+
+	plxreg = pci_resource_start (pdev, 0);
+	io = pci_resource_start (pdev, 1);
+	mem = pci_resource_start (pdev, 2);
+	pci_read_config_dword(pdev, 0x30, &plxdma);
+	irq = pdev->irq;
+	plxdma &= ~15;
+
+	/*
+	 * On some BIOSES, the PLX "expansion rom" (used for DMA)
+	 * address comes up as "0".  This is probably because
+	 * the BIOS doesn't see a valid 55 AA ROM signature at
+	 * the "ROM" start and zeroes the address.  To get
+	 * around this problem the SE-6 is configured to ask
+	 * for 4 MB of space for the dual port memory.  We then
+	 * must set its range back to 2 MB, and use the upper
+	 * half for DMA register access
+	 */
+	OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
+	if (plxdma == 0)
+		plxdma = mem + (2048L * 1024L);
+	pci_write_config_dword(pdev, 0x30, plxdma + 1);
+	pci_read_config_dword(pdev, 0x30, &plxdma);
+	plxdma &= ~15;
+
+	dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev);
+	if (IS_ERR(dev)) {
+		pci_release_regions(pdev);
+		return PTR_ERR(dev);
+	}
 
-		/*
-		 * On some BIOSES, the PLX "expansion rom" (used for DMA)
-		 * address comes up as "0".  This is probably because
-		 * the BIOS doesn't see a valid 55 AA ROM signature at
-		 * the "ROM" start and zeroes the address.  To get
-		 * around this problem the SE-6 is configured to ask
-		 * for 4 MB of space for the dual port memory.  We then
-		 * must set its range back to 2 MB, and use the upper
-		 * half for DMA register access
-		 */
-		OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
-		if (plxdma == 0)
-			plxdma = mem + (2048L * 1024L);
-		pci_write_config_dword(pdev, 0x30, plxdma + 1);
-		pci_read_config_dword(pdev, 0x30, &plxdma);
-		plxdma &= ~15;
+	pci_set_drvdata(pdev, dev);
+	return 0;
+}
 
-		dgrs_found_device(io, mem, irq, plxreg, plxdma);
+static void __devexit dgrs_pci_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
 
-		cards_found++;
-	}
+	dgrs_remove(dev);
+	pci_release_regions(pdev);
+	free_netdev(dev);
+}
 
-	/*
-	 *	Second, check for EISA boards
-	 */
-	if (EISA_bus)
-	{
-		for (io = 0x1000; io < 0x9000; io += 0x1000)
-		{
-			if (inb(io+ES4H_MANUFmsb) != 0x10
-				|| inb(io+ES4H_MANUFlsb) != 0x49
-				|| inb(io+ES4H_PRODUCT) != ES4H_PRODUCT_CODE)
-				continue;
+static struct pci_driver dgrs_pci_driver = {
+	.name = "dgrs",
+	.id_table = dgrs_pci_tbl,
+	.probe = dgrs_pci_probe,
+	.remove = __devexit_p(dgrs_pci_remove),
+};
+#endif
+
+
+#ifdef CONFIG_EISA
+static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
 
-			if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
-				continue; /* Not EISA configured */
+static int __init dgrs_eisa_probe (struct device *gendev)
+{
+	struct net_device *dev;
+	struct eisa_device *edev = to_eisa_device(gendev);
+	uint	io = edev->base_addr;
+	uint	mem;
+	uint	irq;
+	int 	rc = -ENODEV; /* Not EISA configured */
+
+	if (!request_region(io, 256, "RightSwitch")) {
+		printk(KERN_ERR "%s: io 0x%3lX, which is busy.\n", dev->name,
+				dev->base_addr);
+		return -EBUSY;
+	}
 
-			mem = (inb(io+ES4H_AS_31_24) << 24)
-				+ (inb(io+ES4H_AS_23_16) << 16);
+	if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) ) 
+		goto err_out;
 
-			irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
+	mem = (inb(io+ES4H_AS_31_24) << 24)
+		+ (inb(io+ES4H_AS_23_16) << 16);
 
-			dgrs_found_device(io, mem, irq, 0L, 0L);
+	irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
 
-			++cards_found;
-		}
+	dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev);
+	if (IS_ERR(dev)) {
+		rc = PTR_ERR(dev);
+		goto err_out;
 	}
 
-	return cards_found;
+	gendev->driver_data = dev;
+	return 0;
+ err_out:
+	release_region(io, 256);
+	return rc;
+}
+
+static int __devexit dgrs_eisa_remove(struct device *gendev)
+{
+	struct net_device *dev = gendev->driver_data;
+	
+	dgrs_remove(dev);
+
+	release_region(dev->base_addr, 256);
+		
+	free_netdev(dev);
+	return 0;
 }
 
 
+static struct eisa_driver dgrs_eisa_driver = {
+	.id_table = dgrs_eisa_tbl,
+	.driver = {
+		.name = "dgrs",
+		.probe = dgrs_eisa_probe,
+		.remove = __devexit_p(dgrs_eisa_remove),
+	}
+};
+#endif
+
 /*
  *	Variables that can be overriden from module command line
  */
@@ -1459,8 +1543,8 @@
 
 static int __init dgrs_init_module (void)
 {
-	int	cards_found;
 	int	i;
+	int eisacount = 0, pcicount = 0;
 
 	/*
 	 *	Command line variable overrides
@@ -1501,38 +1585,27 @@
 	/*
 	 *	Find and configure all the cards
 	 */
-	dgrs_root_dev = NULL;
-	cards_found = dgrs_scan();
-
-	return cards_found ? 0 : -ENODEV;
+#ifdef CONFIG_EISA
+	eisacount = eisa_driver_register(&dgrs_eisa_driver);
+	if (eisacount < 0)
+		return eisacount;
+#endif
+#ifdef CONFIG_PCI
+	pcicount = pci_register_driver(&dgrs_pci_driver);
+	if (pcicount < 0)
+		return pcicount;
+#endif
+	return (eisacount + pcicount) == 0 ? -ENODEV : 0;
 }
 
 static void __exit dgrs_cleanup_module (void)
 {
-        while (dgrs_root_dev)
-	{
-		struct net_device	*next_dev;
-		DGRS_PRIV	*priv;
-
-		priv = (DGRS_PRIV *) dgrs_root_dev->priv;
-                next_dev = priv->next_dev;
-                unregister_netdev(dgrs_root_dev);
-
-		proc_reset(priv->devtbl[0], 1);
-
-		if (priv->vmem)
-			iounmap(priv->vmem);
-		if (priv->vplxdma)
-			iounmap((uchar *) priv->vplxdma);
-
-		release_region(dgrs_root_dev->base_addr, 256);
-
-		if (dgrs_root_dev->irq)
-			free_irq(dgrs_root_dev->irq, dgrs_root_dev);
-
-                free_netdev(dgrs_root_dev);
-                dgrs_root_dev = next_dev;
-        }
+#ifdef CONFIG_EISA
+	eisa_driver_unregister (&dgrs_eisa_driver);
+#endif
+#ifdef CONFIG_PCI
+	pci_unregister_driver (&dgrs_pci_driver);
+#endif
 }
 
 module_init(dgrs_init_module);
--- diff/drivers/net/e2100.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/e2100.c	2004-02-18 09:04:00.000000000 +0000
@@ -269,6 +269,9 @@
 	ei_status.get_8390_hdr = &e21_get_8390_hdr;
 	dev->open = &e21_open;
 	dev->stop = &e21_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/eepro100.c	2003-10-09 09:47:16.000000000 +0100
+++ source/drivers/net/eepro100.c	2004-02-18 09:04:00.000000000 +0000
@@ -654,6 +654,23 @@
 	return -ENODEV;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void poll_speedo (struct net_device *dev)
+{
+	/* disable_irq is not very nice, but with the funny lockless design
+	   we have no other choice. */
+	disable_irq(dev->irq);
+	speedo_interrupt (dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static int __devinit speedo_found1(struct pci_dev *pdev,
 		long ioaddr, int card_idx, int acpi_idle_state)
 {
@@ -885,6 +902,9 @@
 	dev->get_stats = &speedo_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &poll_speedo;
+#endif
 
 	if (register_netdevice(dev))
 		goto err_free_unlock;
--- diff/drivers/net/es3210.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/es3210.c	2004-02-18 09:04:00.000000000 +0000
@@ -298,6 +298,9 @@
 
 	dev->open = &es_open;
 	dev->stop = &es_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out1:
--- diff/drivers/net/fc/iph5526.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/fc/iph5526.c	2004-02-18 09:04:00.000000000 +0000
@@ -4501,7 +4501,7 @@
 		iph5526_probe_pci(dev);
 		err = register_netdev(dev);
 		if (err < 0) {
-			kfree(dev);
+			free_netdev(dev);
 			printk("iph5526.c: init_fcdev failed for card #%d\n", i+1);
 			break;
 		}
--- diff/drivers/net/fec.c	2003-06-09 14:18:19.000000000 +0100
+++ source/drivers/net/fec.c	2004-02-18 09:04:00.000000000 +0000
@@ -1638,9 +1638,12 @@
 
 /* Initialize the FEC Ethernet on 860T (or ColdFire 5272).
  */
+ /*
+  * XXX:  We need to clean up on failure exits here.
+  */
 int __init fec_enet_init(struct net_device *dev)
 {
-	struct fec_enet_private *fep;
+	struct fec_enet_private *fep = dev->priv;
 	unsigned long	mem_addr;
 	volatile cbd_t	*bdp;
 	cbd_t		*cbd_base;
@@ -1651,13 +1654,6 @@
 	if (found)
 		return(-ENXIO);
 
-	/* Allocate some private information.
-	*/
-	fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL);
-	if (!fep)
-		return -ENOMEM;
-	memset(fep, 0, sizeof(*fep));
-
 	/* Create an Ethernet device instance.
 	*/
 	fecp = fec_hwp;
@@ -1694,6 +1690,7 @@
 	}
 	mem_addr = __get_free_page(GFP_KERNEL);
 	cbd_base = (cbd_t *)mem_addr;
+	/* XXX: missing check for allocation failure */
 
 	fec_uncache(mem_addr);
 
@@ -1715,6 +1712,7 @@
 		/* Allocate a page.
 		*/
 		mem_addr = __get_free_page(GFP_KERNEL);
+		/* XXX: missing check for allocation failure */
 
 		fec_uncache(mem_addr);
 
@@ -1761,9 +1759,6 @@
 	fec_request_intrs(dev, fecp);
 
 	dev->base_addr = (unsigned long)fecp;
-	dev->priv = fep;
-
-	ether_setup(dev);
 
 	/* The FEC Ethernet specific entries in the device structure. */
 	dev->open = fec_enet_open;
@@ -1949,14 +1944,28 @@
 	fecp->fec_mii_speed = fep->phy_speed;
 }
 
-static struct net_device fec_dev = {
-	.init = fec_enet_init,
-};
+static struct net_device *fec_dev;
 
 static int __init fec_enet_module_init(void)
 {
-	if (register_netdev(&fec_dev) != 0)
+	struct net_device *dev;
+	int err;
+
+	dev = alloc_etherdev(sizeof(struct fec_enet_private));
+	if (!dev)
+		return -ENOMEM;
+	err = fec_enet_init(dev);
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+
+	if (register_netdev(dev) != 0) {
+		/* XXX: missing cleanup here */
+		free_netdev(dev);
 		return -EIO;
+	}
+	fec_dev = dev;
 	return(0);
 }
 
--- diff/drivers/net/hp-plus.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hp-plus.c	2004-02-18 09:04:00.000000000 +0000
@@ -236,6 +236,9 @@
 
 	dev->open = &hpp_open;
 	dev->stop = &hpp_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	ei_status.name = name;
 	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
--- diff/drivers/net/hp.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hp.c	2004-02-18 09:04:00.000000000 +0000
@@ -207,6 +207,9 @@
 	dev->base_addr = ioaddr + NIC_OFFSET;
 	dev->open = &hp_open;
 	dev->stop = &hp_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	ei_status.name = name;
 	ei_status.word16 = wordmode;
--- diff/drivers/net/hydra.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/hydra.c	2004-02-18 09:04:00.000000000 +0000
@@ -138,6 +138,9 @@
     ei_status.reg_offset = hydra_offsets;
     dev->open = &hydra_open;
     dev->stop = &hydra_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
 #ifdef MODULE
     ei_status.priv = (unsigned long)root_hydra_dev;
     root_hydra_dev = dev;
--- diff/drivers/net/isa-skeleton.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/net/isa-skeleton.c	2004-02-18 09:04:00.000000000 +0000
@@ -104,8 +104,6 @@
 
 /* Index to functions, as function prototypes. */
 
-extern int netcard_probe(struct net_device *dev);
-
 static int	netcard_probe1(struct net_device *dev, int ioaddr);
 static int	net_open(struct net_device *dev);
 static int	net_send_packet(struct sk_buff *skb, struct net_device *dev);
@@ -129,11 +127,11 @@
  * If dev->base_addr == 2, allocate space for the device and return success
  * (detachable devices only).
  */
-int __init 
-netcard_probe(struct net_device *dev)
+static int __init do_netcard_probe(struct net_device *dev)
 {
 	int i;
 	int base_addr = dev->base_addr;
+	int irq = dev->irq;
 
 	SET_MODULE_OWNER(dev);
 
@@ -144,14 +142,49 @@
 
 	for (i = 0; netcard_portlist[i]; i++) {
 		int ioaddr = netcard_portlist[i];
-		if (check_region(ioaddr, NETCARD_IO_EXTENT))
-			continue;
 		if (netcard_probe1(dev, ioaddr) == 0)
 			return 0;
+		dev->irq = irq;
 	}
 
 	return -ENODEV;
 }
+ 
+static void cleanup_card(struct net_device *dev)
+{
+#ifdef jumpered_dma
+	free_dma(dev->dma);
+#endif
+#ifdef jumpered_interrupts
+	free_irq(dev->irq, dev);
+#endif
+	release_region(dev->base_addr, NETCARD_IO_EXTENT);
+}
+
+struct net_device * __init netcard_probe(int unit)
+{
+	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+	int err;
+
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	sprintf(dev->name, "eth%d", unit);
+	netdev_boot_setup_check(dev);
+
+	err = do_netcard_probe(dev);
+	if (err)
+		goto out;
+	err = register_netdev(dev);
+	if (err)
+		goto out1;
+	return dev;
+out1:
+	cleanup_card(dev);
+out:
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
 
 /*
  * This is the real probe routine. Linux has a history of friendly device
@@ -163,6 +196,11 @@
 	struct net_local *np;
 	static unsigned version_printed;
 	int i;
+	int err = -ENODEV;
+
+	/* Grab the region so that no one else tries to probe our ioports. */
+	if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
+		return -EBUSY;
 
 	/*
 	 * For ethernet adaptors the first three octets of the station address 
@@ -171,9 +209,8 @@
 	 */ 
 	if (inb(ioaddr + 0) != SA_ADDR0
 		||	 inb(ioaddr + 1) != SA_ADDR1
-		||	 inb(ioaddr + 2) != SA_ADDR2) {
-		return -ENODEV;
-	}
+		||	 inb(ioaddr + 2) != SA_ADDR2)
+		goto out;
 
 	if (net_debug  &&  version_printed++ == 0)
 		printk(KERN_DEBUG "%s", version);
@@ -187,6 +224,7 @@
 	for (i = 0; i < 6; i++)
 		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
+	err = -EAGAIN;
 #ifdef jumpered_interrupts
 	/*
 	 * If this board has jumpered interrupts, allocate the interrupt
@@ -217,7 +255,7 @@
 		if (irqval) {
 			printk("%s: unable to get IRQ %d (irqval=%d).\n",
 				   dev->name, dev->irq, irqval);
-			return -EAGAIN;
+			goto out;
 		}
 	}
 #endif	/* jumpered interrupt */
@@ -229,7 +267,7 @@
 	if (dev->dma == 0) {
 		if (request_dma(dev->dma, cardname)) {
 			printk("DMA %d allocation failed.\n", dev->dma);
-			return -EAGAIN;
+			goto out1;
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {
@@ -256,30 +294,18 @@
 			}
 		if (i <= 0) {
 			printk("DMA probe failed.\n");
-			return -EAGAIN;
+			goto out1;
 		} 
 		if (request_dma(dev->dma, cardname)) {
 			printk("probed DMA %d allocation failed.\n", dev->dma);
-			return -EAGAIN;
+			goto out1;
 		}
 	}
 #endif	/* jumpered DMA */
 
-	/* Initialize the device structure. */
-	if (dev->priv == NULL) {
-		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-		if (dev->priv == NULL)
-			return -ENOMEM;
-	}
-
-	memset(dev->priv, 0, sizeof(struct net_local));
-
 	np = (struct net_local *)dev->priv;
 	spin_lock_init(&np->lock);
 
-	/* Grab the region so that no one else tries to probe our ioports. */
-	request_region(ioaddr, NETCARD_IO_EXTENT, cardname);
-
 	dev->open		= net_open;
 	dev->stop		= net_close;
 	dev->hard_start_xmit	= net_send_packet;
@@ -288,11 +314,14 @@
 
         dev->tx_timeout		= &net_tx_timeout;
         dev->watchdog_timeo	= MY_TX_TIMEOUT; 
-
-	/* Fill in the fields of the device structure with ethernet values. */
-	ether_setup(dev);
-
 	return 0;
+out1:
+#ifdef jumpered_interrupts
+	free_irq(dev->irq, dev);
+#endif
+out:
+	release_region(base_addr, NETCARD_IO_EXTENT);
+	return err;
 }
 
 static void net_tx_timeout(struct net_device *dev)
@@ -635,7 +664,7 @@
 
 #ifdef MODULE
 
-static struct net_device this_device;
+static struct net_device *this_device;
 static int io = 0x300;
 static int irq;
 static int dma;
@@ -644,42 +673,38 @@
 
 int init_module(void)
 {
+	struct net_device *dev;
 	int result;
 
 	if (io == 0)
 		printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n",
 			   cardname);
+	dev = alloc_etherdev(sizeof(struct net_local));
+	if (!dev)
+		return -ENOMEM;
 
 	/* Copy the parameters from insmod into the device structure. */
-	this_device.base_addr = io;
-	this_device.irq       = irq;
-	this_device.dma       = dma;
-	this_device.mem_start = mem;
-	this_device.init      = netcard_probe;
-
-	if ((result = register_netdev(&this_device)) != 0)
-		return result;
-
-	return 0;
+	dev->base_addr = io;
+	dev->irq       = irq;
+	dev->dma       = dma;
+	dev->mem_start = mem;
+	if (do_netcard_probe(dev) == 0) {
+		if (register_netdev(dev) == 0)
+			this_device = dev;
+			return 0;
+		}
+		cleanup_card(dev);
+	}
+	free_netdev(dev);
+	return -ENXIO;
 }
 
 void
 cleanup_module(void)
 {
-	unregister_netdev(&this_device);
-	/*
-	 * If we don't do this, we can't re-insmod it later.
-	 * Release irq/dma here, when you have jumpered versions and
-	 * allocate them in net_probe1().
-	 */
-	/*
-	   free_irq(this_device.irq, dev);
-	   free_dma(this_device.dma);
-	*/
-	release_region(this_device.base_addr, NETCARD_IO_EXTENT);
-
-	if (this_device.priv)
-		kfree(this_device.priv);
+	unregister_netdev(this_device);
+	cleanup_card(this_device);
+	free_netdev(this_device);
 }
 
 #endif /* MODULE */
--- diff/drivers/net/lne390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/lne390.c	2004-02-18 09:04:00.000000000 +0000
@@ -299,6 +299,9 @@
 
 	dev->open = &lne390_open;
 	dev->stop = &lne390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 cleanup:
--- diff/drivers/net/mac8390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/mac8390.c	2004-02-18 09:04:00.000000000 +0000
@@ -442,6 +442,9 @@
 	/* Now fill in our stuff */
 	dev->open = &mac8390_open;
 	dev->stop = &mac8390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	/* GAR, ei_status is actually a macro even though it looks global */
 	ei_status.name = cardname[type];
--- diff/drivers/net/ne.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne.c	2004-02-18 09:04:00.000000000 +0000
@@ -496,6 +496,9 @@
 	ei_status.priv = 0;
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 
--- diff/drivers/net/ne2.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2.c	2004-02-18 09:04:00.000000000 +0000
@@ -509,6 +509,9 @@
 	
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 out:
--- diff/drivers/net/ne2k-pci.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2k-pci.c	2004-02-18 09:04:00.000000000 +0000
@@ -359,6 +359,9 @@
 	dev->open = &ne2k_pci_open;
 	dev->stop = &ne2k_pci_close;
 	dev->ethtool_ops = &ne2k_pci_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	i = register_netdev(dev);
--- diff/drivers/net/ne2k_cbus.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne2k_cbus.c	2004-02-18 09:04:00.000000000 +0000
@@ -534,6 +534,9 @@
 	ei_status.priv = 0;
 	dev->open = &ne_open;
 	dev->stop = &ne_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 	return 0;
 
--- diff/drivers/net/ne3210.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ne3210.c	2004-02-18 09:04:00.000000000 +0000
@@ -205,6 +205,9 @@
 
 	dev->open = &ne3210_open;
 	dev->stop = &ne3210_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	dev->if_port = ifmap_val[port_index];
 
 	if ((retval = register_netdev (dev)))
--- diff/drivers/net/oaknet.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/oaknet.c	2004-02-18 09:04:00.000000000 +0000
@@ -192,6 +192,9 @@
 
 	dev->open = oaknet_open;
 	dev->stop = oaknet_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	NS8390_init(dev, FALSE);
 	ret = register_netdev(dev);
--- diff/drivers/net/pcnet32.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pcnet32.c	2004-02-18 09:04:00.000000000 +0000
@@ -456,6 +456,14 @@
     .reset	= pcnet32_dwio_reset
 };
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void pcnet32_poll_controller(struct net_device *dev)
+{ 
+	disable_irq(dev->irq);
+	pcnet32_interrupt(0, dev, NULL);
+	enable_irq(dev->irq);
+} 
+#endif
 
 
 /* only probes for non-PCI devices, the rest are handled by 
@@ -806,6 +814,10 @@
     dev->tx_timeout = pcnet32_tx_timeout;
     dev->watchdog_timeo = (5*HZ);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = pcnet32_poll_controller;
+#endif    
+
     /* Fill in the generic fields of the device structure. */
     if (register_netdev(dev))
 	goto err_free_consistent;
@@ -1696,12 +1708,16 @@
 static void pcnet32_watchdog(struct net_device *dev)
 {
     struct pcnet32_private *lp = dev->priv;
+    unsigned long flags;
+
+    spin_lock_irqsave(&lp->lock, flags);
 
     /* Print the link status if it has changed */
     if (lp->mii)
 	mii_check_media (&lp->mii_if, 1, 0);
-
     mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+
+    spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 static struct pci_driver pcnet32_driver = {
--- diff/drivers/net/ppp_deflate.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ppp_deflate.c	2004-02-18 09:04:00.000000000 +0000
@@ -655,3 +655,5 @@
 module_init(deflate_init);
 module_exit(deflate_cleanup);
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
+MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));
--- diff/drivers/net/ppp_generic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/ppp_generic.c	2004-02-18 09:04:00.000000000 +0000
@@ -675,20 +675,25 @@
 
 		if (copy_from_user(&uprog, (void __user *) arg, sizeof(uprog)))
 			break;
-		err = -ENOMEM;
-		len = uprog.len * sizeof(struct sock_filter);
-		code = kmalloc(len, GFP_KERNEL);
-		if (code == 0)
-			break;
-		err = -EFAULT;
-		if (copy_from_user(code, (void __user *) uprog.filter, len)) {
-			kfree(code);
-			break;
-		}
-		err = sk_chk_filter(code, uprog.len);
-		if (err) {
-			kfree(code);
+		err = -EINVAL;
+		if (uprog.len > BPF_MAXINSNS)
 			break;
+		err = -ENOMEM;
+		if (uprog.len > 0) {
+			len = uprog.len * sizeof(struct sock_filter);
+			code = kmalloc(len, GFP_KERNEL);
+			if (code == NULL)
+				break;
+			err = -EFAULT;
+			if (copy_from_user(code, (void __user *) uprog.filter, len)) {
+				kfree(code);
+				break;
+			}
+			err = sk_chk_filter(code, uprog.len);
+			if (err) {
+				kfree(code);
+				break;
+			}
 		}
 		filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter;
 		ppp_lock(ppp);
@@ -2668,3 +2673,4 @@
 EXPORT_SYMBOL(all_channels); /* for debugging */
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(PPP_MAJOR);
+MODULE_ALIAS("/dev/ppp");
--- diff/drivers/net/pppoe.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/pppoe.c	2004-02-18 09:04:00.000000000 +0000
@@ -67,7 +67,6 @@
 #include <linux/ppp_channel.h>
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
-#include <linux/if_pppvar.h>
 #include <linux/notifier.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
--- diff/drivers/net/r8169.c	2003-12-19 09:51:11.000000000 +0000
+++ source/drivers/net/r8169.c	2004-02-18 09:04:00.000000000 +0000
@@ -56,9 +56,11 @@
 	        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
         	#expr,__FILE__,__FUNCTION__,__LINE__);		\
         }
+#define dprintk(fmt, args...)	do { printk(PFX fmt, ## args) } while (0)
 #else
 #define assert(expr) do {} while (0)
-#endif
+#define dprintk(fmt, args...)	do {} while (0)
+#endif /* RTL8169_DEBUG */
 
 /* media options */
 #define MAX_UNITS 8
@@ -89,9 +91,12 @@
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
 #define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
 #define RX_BUF_SIZE	1536	/* Rx Buffer size */
+#define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
 #define RTL_MIN_IO_SIZE 0x80
-#define TX_TIMEOUT  (6*HZ)
+#define RTL8169_TX_TIMEOUT	(6*HZ)
+#define RTL8169_PHY_TIMEOUT	(HZ) 
 
 /* write/read MMIO register */
 #define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
@@ -101,11 +106,35 @@
 #define RTL_R16(reg)		readw (ioaddr + (reg))
 #define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
 
-static struct {
+enum mac_version {
+	RTL_GIGA_MAC_VER_B = 0x00,
+	/* RTL_GIGA_MAC_VER_C = 0x03, */
+	RTL_GIGA_MAC_VER_D = 0x01,
+	RTL_GIGA_MAC_VER_E = 0x02
+};
+
+enum phy_version {
+	RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */
+	RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */
+	RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */
+};
+
+
+#define _R(NAME,MAC,MASK) \
+	{ .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+const static struct {
 	const char *name;
-} board_info[] __devinitdata = {
-	{
-"RealTek RTL8169 Gigabit Ethernet"},};
+	u8 mac_version;
+	u32 RxConfigMask;	/* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+	_R("RTL8169",		RTL_GIGA_MAC_VER_B, 0xff7e1880),
+	_R("RTL8169s/8110s",	RTL_GIGA_MAC_VER_D, 0xff7e1880),
+	_R("RTL8169s/8110s",	RTL_GIGA_MAC_VER_E, 0xff7e1880)
+};
+#undef _R
 
 static struct pci_device_id rtl8169_pci_tbl[] = {
 	{0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -114,6 +143,8 @@
 
 MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
 
+static int rx_copybreak = 200;
+
 enum RTL8169_registers {
 	MAC0 = 0,		/* Ethernet hardware address. */
 	MAR0 = 8,		/* Multicast filter. */
@@ -242,14 +273,6 @@
 	TBILinkOK = 0x02000000,
 };
 
-const static struct {
-	const char *name;
-	u8 version;		/* depend on RTL8169 docs */
-	u32 RxConfigMask;	/* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
-	{
-"RTL-8169", 0x00, 0xff7e1880,},};
-
 enum _DescStatusBit {
 	OWNbit = 0x80000000,
 	EORbit = 0x40000000,
@@ -257,6 +280,8 @@
 	LSbit = 0x10000000,
 };
 
+#define RsvdMask	0x3fffc000
+
 struct TxDesc {
 	u32 status;
 	u32 vlan_tag;
@@ -277,28 +302,33 @@
 	struct net_device_stats stats;	/* statistics of net device */
 	spinlock_t lock;	/* spin lock flag */
 	int chipset;
-	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
-	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
-	unsigned long dirty_tx;
-	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
-	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	int mac_version;
+	int phy_version;
+	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
+	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
+	u32 dirty_rx;
+	u32 dirty_tx;
 	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
 	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
-	unsigned char *RxBufferRings;	/* Index of Rx Buffer  */
-	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
+	dma_addr_t TxPhyAddr;
+	dma_addr_t RxPhyAddr;
+	struct sk_buff *Rx_skbuff[NUM_RX_DESC];	/* Rx data buffers */
 	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+	struct timer_list timer;
+	unsigned long phy_link_down_cnt;
 };
 
 MODULE_AUTHOR("Realtek");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
 MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(rx_copybreak, "i");
 MODULE_LICENSE("GPL");
 
 static int rtl8169_open(struct net_device *dev);
 static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance,
 			      struct pt_regs *regs);
-static void rtl8169_init_ring(struct net_device *dev);
+static int rtl8169_init_ring(struct net_device *dev);
 static void rtl8169_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
 static void rtl8169_set_rx_mode(struct net_device *dev);
@@ -306,11 +336,15 @@
 static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
 
 static const u16 rtl8169_intr_mask =
-    SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK |
-    RxErr | RxOK;
+    RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
 static const unsigned int rtl8169_rx_config =
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
+#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
+#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
+#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
+#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
+
 void
 mdio_write(void *ioaddr, int RegAddr, int value)
 {
@@ -342,13 +376,258 @@
 		if (RTL_R32(PHYAR) & 0x80000000) {
 			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
 			break;
-		} else {
-			udelay(100);
 		}
+		udelay(100);
 	}
 	return value;
 }
 
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum,
+				       int bitval)
+{
+	int val;
+
+	val = mdio_read(ioaddr, reg);
+	val = (bitval == 1) ?
+		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);
+	mdio_write(ioaddr, reg, val & 0xffff); 
+}
+
+static void rtl8169_get_mac_version(struct rtl8169_private *tp, void *ioaddr)
+{
+	const struct {
+		u32 mask;
+		int mac_version;
+	} mac_info[] = {
+		{ 0x1 << 26,	RTL_GIGA_MAC_VER_E },
+		{ 0x1 << 23,	RTL_GIGA_MAC_VER_D }, 
+		{ 0x00000000,	RTL_GIGA_MAC_VER_B } /* Catch-all */
+	}, *p = mac_info;
+	u32 reg;
+
+	reg = RTL_R32(TxConfig) & 0x7c800000;
+	while ((reg & p->mask) != p->mask)
+		p++;
+	tp->mac_version = p->mac_version;
+}
+
+static void rtl8169_print_mac_version(struct rtl8169_private *tp)
+{
+	struct {
+		int version;
+		char *msg;
+	} mac_print[] = {
+		{ RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" },
+		{ RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" },
+		{ RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" },
+		{ 0, NULL }
+	}, *p;
+
+	for (p = mac_print; p->msg; p++) {
+		if (tp->mac_version == p->version) {
+			dprintk("mac_version == %s (%04d)\n", p->msg,
+				  p->version);
+			return;
+		}
+	}
+	dprintk("mac_version == Unknown\n");
+}
+
+static void rtl8169_get_phy_version(struct rtl8169_private *tp, void *ioaddr)
+{
+	const struct {
+		u16 mask;
+		u16 set;
+		int phy_version;
+	} phy_info[] = {
+		{ 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
+		{ 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
+		{ 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
+		{ 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
+	}, *p = phy_info;
+	u16 reg;
+
+	reg = mdio_read(ioaddr, 3) & 0xffff;
+	while ((reg & p->mask) != p->set)
+		p++;
+	tp->phy_version = p->phy_version;
+}
+
+static void rtl8169_print_phy_version(struct rtl8169_private *tp)
+{
+	struct {
+		int version;
+		char *msg;
+		u32 reg;
+	} phy_print[] = {
+		{ RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
+		{ RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
+		{ RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
+		{ RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
+		{ 0, NULL, 0x0000 }
+	}, *p;
+
+	for (p = phy_print; p->msg; p++) {
+		if (tp->phy_version == p->version) {
+			dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
+			return;
+		}
+	}
+	dprintk("phy_version == Unknown\n");
+}
+
+static void rtl8169_hw_phy_config(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	struct {
+		u16 regs[5]; /* Beware of bit-sign propagation */
+	} phy_magic[5] = { {
+		{ 0x0000,	//w 4 15 12 0
+		  0x00a1,	//w 3 15 0 00a1
+		  0x0008,	//w 2 15 0 0008
+		  0x1020,	//w 1 15 0 1020
+		  0x1000 } },{	//w 0 15 0 1000
+		{ 0x7000,	//w 4 15 12 7
+		  0xff41,	//w 3 15 0 ff41
+		  0xde60,	//w 2 15 0 de60
+		  0x0140,	//w 1 15 0 0140
+		  0x0077 } },{	//w 0 15 0 0077
+		{ 0xa000,	//w 4 15 12 a
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xfa00 } },{	//w 0 15 0 fa00
+		{ 0xb000,	//w 4 15 12 b
+		  0xff41,	//w 3 15 0 ff41
+		  0xde20,	//w 2 15 0 de20
+		  0x0140,	//w 1 15 0 0140
+		  0x00bb } },{	//w 0 15 0 00bb
+		{ 0xf000,	//w 4 15 12 f
+		  0xdf01,	//w 3 15 0 df01
+		  0xdf20,	//w 2 15 0 df20
+		  0xff95,	//w 1 15 0 ff95
+		  0xbf00 }	//w 0 15 0 bf00
+		}
+	}, *p = phy_magic;
+	int i;
+
+	rtl8169_print_mac_version(tp);
+	rtl8169_print_phy_version(tp);
+
+	if (tp->mac_version <= RTL_GIGA_MAC_VER_B)
+		return;
+	if (tp->phy_version >= RTL_GIGA_PHY_VER_F) 
+		return;
+
+	dprintk("MAC version != 0 && PHY version == 0 or 1\n");
+	dprintk("Do final_reg2.cfg\n");
+
+	/* Shazam ! */
+
+	// phy config for RTL8169s mac_version C chip
+	mdio_write(ioaddr, 31, 0x0001);			//w 31 2 0 1
+	mdio_write(ioaddr, 21, 0x1000);			//w 21 15 0 1000
+	mdio_write(ioaddr, 24, 0x65c7);			//w 24 15 0 65c7
+	rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);	//w 4 11 11 0
+
+	for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
+		int val, pos = 4;
+
+		val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+		mdio_write(ioaddr, pos, val);
+		while (--pos >= 0)
+			mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
+	}
+	mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169_hw_phy_reset(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i, val;
+
+	printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name);
+
+	val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff;
+	mdio_write(ioaddr, 0, val);
+
+	for (i = 50; i >= 0; i--) {
+		if (!(mdio_read(ioaddr, 0) & 0x8000))
+			break;
+		udelay(100); /* Gross */
+	}
+
+	if (i < 0) {
+		printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n",
+		       dev->name);
+	}
+}
+
+static void rtl8169_phy_timer(unsigned long __opaque)
+{
+	struct net_device *dev = (struct net_device *)__opaque;
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+	void *ioaddr = tp->mmio_addr;
+
+	assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
+	assert(tp->phy_version < RTL_GIGA_PHY_VER_G);
+
+	if (RTL_R8(PHYstatus) & LinkStatus)
+		tp->phy_link_down_cnt = 0;
+	else {
+		tp->phy_link_down_cnt++;
+		if (tp->phy_link_down_cnt >= 12) {
+			int reg;
+
+			// If link on 1000, perform phy reset.
+			reg = mdio_read(ioaddr, PHY_1000_CTRL_REG);
+			if (reg & PHY_Cap_1000_Full) 
+				rtl8169_hw_phy_reset(dev);
+
+			tp->phy_link_down_cnt = 0;
+		}
+	}
+
+	mod_timer(timer, RTL8169_PHY_TIMEOUT);
+}
+
+static inline void rtl8169_delete_timer(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+
+	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
+		return;
+
+	del_timer_sync(timer);
+
+	tp->phy_link_down_cnt = 0;
+}
+
+static inline void rtl8169_request_timer(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	struct timer_list *timer = &tp->timer;
+
+	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
+		return;
+
+	tp->phy_link_down_cnt = 0;
+
+	init_timer(timer);
+	timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
+	timer->data = (unsigned long)(dev);
+	timer->function = rtl8169_phy_timer;
+	add_timer(timer);
+}
+
 static int __devinit
 rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 		   void **ioaddr_out)
@@ -356,9 +635,9 @@
 	void *ioaddr = NULL;
 	struct net_device *dev;
 	struct rtl8169_private *tp;
-	int rc, i;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
-	u32 tmp;
+	int rc, i, acpi_idle_state = 0, pm_cap;
+
 
 	assert(pdev != NULL);
 	assert(ioaddr_out != NULL);
@@ -379,8 +658,22 @@
 
 	// enable device (incl. PCI PM wakeup and hotplug setup)
 	rc = pci_enable_device(pdev);
-	if (rc)
+	if (rc) {
+		printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name);
 		goto err_out;
+	}
+
+	/* save power state before pci_enable_device overwrites it */
+	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm_cap) {
+		u16 pwr_command;
+
+		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
+		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	} else {
+		printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n");
+		goto err_out_free_res;
+	}
 
 	mmio_start = pci_resource_start(pdev, 1);
 	mmio_end = pci_resource_end(pdev, 1);
@@ -402,8 +695,10 @@
 	}
 
 	rc = pci_request_regions(pdev, dev->name);
-	if (rc)
+	if (rc) {
+		printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name);
 		goto err_out_disable;
+	}
 
 	// enable PCI bus-mastering
 	pci_set_master(pdev);
@@ -420,30 +715,32 @@
 	RTL_W8(ChipCmd, CmdReset);
 
 	// Check that the chip has finished the reset.
-	for (i = 1000; i > 0; i--)
+	for (i = 1000; i > 0; i--) {
 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
 			break;
-		else
-			udelay(10);
+		udelay(10);
+	}
 
-	// identify chip attached to board
-	tmp = RTL_R32(TxConfig);
-	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
-
-	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
-		if (tmp == rtl_chip_info[i].version) {
-			tp->chipset = i;
-			goto match;
-		}
-	//if unknown chip, assume array element #0, original RTL-8169 in this case
-	printk(KERN_DEBUG PFX
-	       "PCI device %s: unknown chip version, assuming RTL-8169\n",
-	       pci_name(pdev));
-	printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n",
-	       pci_name(pdev), (unsigned long) RTL_R32(TxConfig));
-	tp->chipset = 0;
+	// Identify chip attached to board
+	rtl8169_get_mac_version(tp, ioaddr);
+	rtl8169_get_phy_version(tp, ioaddr);
+
+	rtl8169_print_mac_version(tp);
+	rtl8169_print_phy_version(tp);
+
+	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+		if (tp->mac_version == rtl_chip_info[i].mac_version)
+			break;
+	}
+	if (i < 0) {
+		/* Unknown chip: assume array element #0, original RTL-8169 */
+		printk(KERN_DEBUG PFX
+		       "PCI device %s: unknown chip version, assuming %s\n",
+		       pci_name(pdev), rtl_chip_info[0].name);
+		i++;
+	}
+	tp->chipset = i;
 
-match:
 	*ioaddr_out = ioaddr;
 	*dev_out = dev;
 	return 0;
@@ -499,7 +796,7 @@
 	dev->stop = rtl8169_close;
 	dev->tx_timeout = rtl8169_tx_timeout;
 	dev->set_multicast_list = rtl8169_set_rx_mode;
-	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
 //      dev->do_ioctl           = mii_ioctl;
@@ -528,12 +825,29 @@
 	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
 	       "IRQ %d\n",
 	       dev->name,
-	       board_info[ent->driver_data].name,
+	       rtl_chip_info[ent->driver_data].name,
 	       dev->base_addr,
 	       dev->dev_addr[0], dev->dev_addr[1],
 	       dev->dev_addr[2], dev->dev_addr[3],
 	       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
 
+	rtl8169_hw_phy_config(dev);
+
+	dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+	RTL_W8(0x82, 0x01);
+
+	if (tp->mac_version < RTL_GIGA_MAC_VER_E) {
+		dprintk("Set PCI Latency=0x40\n");
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+	}
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
+		dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+		RTL_W8(0x82, 0x01);
+		dprintk("Set PHY Reg 0x0bh = 0x00h\n");
+		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+	}
+
 	// if TBI is not endbled
 	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
 		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
@@ -546,23 +860,23 @@
 			Cap10_100 = 0, Cap1000 = 0;
 			switch (option) {
 			case _10_Half:
-				Cap10_100 = PHY_Cap_10_Half;
+				Cap10_100 = PHY_Cap_10_Half_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _10_Full:
-				Cap10_100 = PHY_Cap_10_Full;
+				Cap10_100 = PHY_Cap_10_Full_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _100_Half:
-				Cap10_100 = PHY_Cap_100_Half;
+				Cap10_100 = PHY_Cap_100_Half_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _100_Full:
-				Cap10_100 = PHY_Cap_100_Full;
+				Cap10_100 = PHY_Cap_100_Full_Or_Less;
 				Cap1000 = PHY_Cap_Null;
 				break;
 			case _1000_Full:
-				Cap10_100 = PHY_Cap_Null;
+				Cap10_100 = PHY_Cap_100_Full_Or_Less;
 				Cap1000 = PHY_Cap_1000_Full;
 				break;
 			default:
@@ -576,9 +890,7 @@
 
 			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
 			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
-				   PHY_Cap_10_Half | PHY_Cap_10_Full |
-				   PHY_Cap_100_Half | PHY_Cap_100_Full | (val &
-									  0x1F));
+				   PHY_Cap_100_Full_Or_Less | (val & 0x1f));
 
 			// enable 1000 Full Mode
 			mdio_write(ioaddr, PHY_1000_CTRL_REG,
@@ -647,56 +959,96 @@
 	pci_set_drvdata(pdev, NULL);
 }
 
+#ifdef CONFIG_PM
+
+static int rtl8169_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	if (!netif_running(dev))
+		return 0;
+	
+	netif_device_detach(dev);
+	netif_stop_queue(dev);
+	spin_lock_irqsave(&tp->lock, flags);
+
+	/* Disable interrupts, stop Rx and Tx */
+	RTL_W16(IntrMask, 0);
+	RTL_W8(ChipCmd, 0);
+		
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+	RTL_W32(RxMissed, 0);
+	spin_unlock_irqrestore(&tp->lock, flags);
+	
+	return 0;
+}
+
+static int rtl8169_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (!netif_running(dev))
+	    return 0;
+
+	netif_device_attach(dev);
+	rtl8169_hw_start(dev);
+
+	return 0;
+}
+                                                                                
+#endif /* CONFIG_PM */
+
 static int
 rtl8169_open(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	struct pci_dev *pdev = tp->pci_dev;
 	int retval;
-	u8 diff;
-	u32 TxPhyAddr, RxPhyAddr;
 
 	retval =
 	    request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
-	if (retval) {
-		return retval;
-	}
+	if (retval < 0)
+		goto out;
 
-	tp->TxDescArrays =
-	    kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL);
-	// Tx Desscriptor needs 256 bytes alignment;
-	TxPhyAddr = virt_to_bus(tp->TxDescArrays);
-	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
-	TxPhyAddr += diff;
-	tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff);
-
-	tp->RxDescArrays =
-	    kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL);
-	// Rx Desscriptor needs 256 bytes alignment;
-	RxPhyAddr = virt_to_bus(tp->RxDescArrays);
-	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
-	RxPhyAddr += diff;
-	tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff);
+	retval = -ENOMEM;
 
-	if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) {
-		printk(KERN_INFO
-		       "Allocate RxDescArray or TxDescArray failed\n");
-		free_irq(dev->irq, dev);
-		if (tp->TxDescArrays)
-			kfree(tp->TxDescArrays);
-		if (tp->RxDescArrays)
-			kfree(tp->RxDescArrays);
-		return -ENOMEM;
-	}
-	tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
-	if (tp->RxBufferRings == NULL) {
-		printk(KERN_INFO "Allocate RxBufferRing failed\n");
-	}
+	/*
+	 * Rx and Tx desscriptors needs 256 bytes alignment.
+	 * pci_alloc_consistent provides more.
+	 */
+	tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
+					       &tp->TxPhyAddr);
+	if (!tp->TxDescArray)
+		goto err_free_irq;
+
+	tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
+					       &tp->RxPhyAddr);
+	if (!tp->RxDescArray)
+		goto err_free_tx;
+
+	retval = rtl8169_init_ring(dev);
+	if (retval < 0)
+		goto err_free_rx;
 
-	rtl8169_init_ring(dev);
 	rtl8169_hw_start(dev);
 
-	return 0;
-
+	rtl8169_request_timer(dev);
+out:
+	return retval;
+
+err_free_rx:
+	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
+			    tp->RxPhyAddr);
+err_free_tx:
+	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
+			    tp->TxPhyAddr);
+err_free_irq:
+	free_irq(dev->irq, dev);
+	goto out;
 }
 
 static void
@@ -733,11 +1085,17 @@
 	RTL_W32(TxConfig,
 		(TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
 						TxInterFrameGapShift));
+	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd));
+
+	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
+		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n");
+		RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3));
+	}
 
 	tp->cur_rx = 0;
 
-	RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray));
-	RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray));
+	RTL_W32(TxDescStartAddr, tp->TxPhyAddr);
+	RTL_W32(RxDescStartAddr, tp->RxPhyAddr);
 	RTL_W8(Cfg9346, Cfg9346_Lock);
 	udelay(10);
 
@@ -755,31 +1113,131 @@
 
 }
 
-static void
-rtl8169_init_ring(struct net_device *dev)
+static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
+{
+	desc->buf_addr = 0xdeadbeef;
+	desc->status &= ~cpu_to_le32(OWNbit | RsvdMask);
+}
+
+static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+				struct RxDesc *desc)
+{
+	pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE,
+			 PCI_DMA_FROMDEVICE);
+	dev_kfree_skb(*sk_buff);
+	*sk_buff = NULL;
+	rtl8169_make_unusable_by_asic(desc);
+}
+
+static inline void rtl8169_return_to_asic(struct RxDesc *desc)
+{
+	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+}
+
+static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping)
+{
+	desc->buf_addr = cpu_to_le32(mapping);
+	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+}
+
+static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev,
+				struct sk_buff **sk_buff, struct RxDesc *desc)
+{
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int ret = 0;
+
+	skb = dev_alloc_skb(RX_BUF_SIZE);
+	if (!skb)
+		goto err_out;
+
+	skb->dev = dev;
+	skb_reserve(skb, 2);
+	*sk_buff = skb;
+
+	mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE,
+				 PCI_DMA_FROMDEVICE);
+
+	rtl8169_give_to_asic(desc, mapping);
+
+out:
+	return ret;
+
+err_out:
+	ret = -ENOMEM;
+	rtl8169_make_unusable_by_asic(desc);
+	goto out;
+}
+
+static void rtl8169_rx_clear(struct rtl8169_private *tp)
 {
-	struct rtl8169_private *tp = dev->priv;
 	int i;
 
-	tp->cur_rx = 0;
-	tp->cur_tx = 0;
-	tp->dirty_tx = 0;
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (tp->Rx_skbuff[i]) {
+			rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+					    tp->RxDescArray + i);
+		}
+	}
+}
+
+static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
+			   u32 start, u32 end)
+{
+	u32 cur;
+	
+	for (cur = start; end - cur > 0; cur++) {
+		int ret, i = cur % NUM_RX_DESC;
+
+		if (tp->Rx_skbuff[i])
+			continue;
+			
+		ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i,
+					   tp->RxDescArray + i);
+		if (ret < 0)
+			break;
+	}
+	return cur - start;
+}
+
+static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
+{
+	desc->status |= cpu_to_le32(EORbit);
+}
+
+static int rtl8169_init_ring(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+
+	tp->cur_rx = tp->dirty_rx = 0;
+	tp->cur_tx = tp->dirty_tx = 0;
 	memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
 	memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
 
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		tp->Tx_skbuff[i] = NULL;
-	}
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		if (i == (NUM_RX_DESC - 1))
-			tp->RxDescArray[i].status =
-			    (OWNbit | EORbit) + RX_BUF_SIZE;
-		else
-			tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
+	memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *));
+	memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
 
-		tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]);
-		tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]);
-	}
+	if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
+		goto err_out;
+
+	rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
+
+	return 0;
+
+err_out:
+	rtl8169_rx_clear(tp);
+	return -ENOMEM;
+}
+
+static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+				 struct TxDesc *desc)
+{
+	u32 len = sk_buff[0]->len;
+
+	pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr),
+			 len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE);
+	desc->buf_addr = 0x00;
+	*sk_buff = NULL;
 }
 
 static void
@@ -789,9 +1247,12 @@
 
 	tp->cur_tx = 0;
 	for (i = 0; i < NUM_TX_DESC; i++) {
-		if (tp->Tx_skbuff[i] != NULL) {
-			dev_kfree_skb(tp->Tx_skbuff[i]);
-			tp->Tx_skbuff[i] = NULL;
+		struct sk_buff *skb = tp->Tx_skbuff[i];
+
+		if (skb) {
+			rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i,
+					     tp->TxDescArray + i);
+			dev_kfree_skb(skb);
 			tp->stats.tx_dropped++;
 		}
 	}
@@ -829,49 +1290,58 @@
 	struct rtl8169_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int entry = tp->cur_tx % NUM_TX_DESC;
+	u32 len = skb->len;
 
-	if (skb->len < ETH_ZLEN) {
+	if (unlikely(skb->len < ETH_ZLEN)) {
 		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
+		if (!skb)
+			goto err_update_stats;
+		len = ETH_ZLEN;
 	}
 	
 	spin_lock_irq(&tp->lock);
 
-	if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+	if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
+		dma_addr_t mapping;
+
+		mapping = pci_map_single(tp->pci_dev, skb->data, len,
+					 PCI_DMA_TODEVICE);
+
 		tp->Tx_skbuff[entry] = skb;
-		tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
-		if (entry != (NUM_TX_DESC - 1))
-			tp->TxDescArray[entry].status =
-			    (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ?
-							skb->len : ETH_ZLEN);
-		else
-			tp->TxDescArray[entry].status =
-			    (OWNbit | EORbit | FSbit | LSbit) |
-			    ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
+		tp->TxDescArray[entry].buf_addr = cpu_to_le32(mapping);
 
+		tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit |
+			LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC)));
+			
 		RTL_W8(TxPoll, 0x40);	//set polling bit
 
 		dev->trans_start = jiffies;
 
 		tp->cur_tx++;
-	}
+	} else
+		goto err_drop;
 
-	spin_unlock_irq(&tp->lock);
 
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
 		netif_stop_queue(dev);
 	}
+out:
+	spin_unlock_irq(&tp->lock);
 
 	return 0;
+
+err_drop:
+	dev_kfree_skb(skb);
+err_update_stats:
+	tp->stats.tx_dropped++;
+	goto out;
 }
 
 static void
 rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long dirty_tx, tx_left = 0;
-	int entry = tp->cur_tx % NUM_TX_DESC;
+	unsigned long dirty_tx, tx_left;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -881,14 +1351,21 @@
 	tx_left = tp->cur_tx - dirty_tx;
 
 	while (tx_left > 0) {
-		if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
-			dev_kfree_skb_irq(tp->
-					  Tx_skbuff[dirty_tx % NUM_TX_DESC]);
-			tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
+		int entry = dirty_tx % NUM_TX_DESC;
+
+		if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
+			struct sk_buff *skb = tp->Tx_skbuff[entry];
+
+			/* FIXME: is it really accurate for TxErr ? */
+			tp->stats.tx_bytes += skb->len >= ETH_ZLEN ?
+					      skb->len : ETH_ZLEN;
 			tp->stats.tx_packets++;
+			rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + entry,
+					     tp->TxDescArray + entry);
+			dev_kfree_skb_irq(skb);
+			tp->Tx_skbuff[entry] = NULL;
 			dirty_tx++;
 			tx_left--;
-			entry++;
 		}
 	}
 
@@ -899,70 +1376,102 @@
 	}
 }
 
+static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
+				      struct RxDesc *desc,
+				      struct net_device *dev)
+{
+	int ret = -1;
+
+	if (pkt_size < rx_copybreak) {
+		struct sk_buff *skb;
+
+		skb = dev_alloc_skb(pkt_size + 2);
+		if (skb) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);
+			eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
+			*sk_buff = skb;
+			rtl8169_return_to_asic(desc);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
 static void
 rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	int cur_rx;
-	struct sk_buff *skb;
-	int pkt_size = 0;
+	unsigned long cur_rx, rx_left;
+	int delta;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
 	assert(ioaddr != NULL);
 
 	cur_rx = tp->cur_rx;
+	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
 
-	while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
+	while (rx_left > 0) {
+		int entry = cur_rx % NUM_RX_DESC;
+		u32 status = le32_to_cpu(tp->RxDescArray[entry].status);
 
-		if (tp->RxDescArray[cur_rx].status & RxRES) {
+		if (status & OWNbit)
+			break;
+		if (status & RxRES) {
 			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
 			tp->stats.rx_errors++;
-			if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT))
+			if (status & (RxRWT | RxRUNT))
 				tp->stats.rx_length_errors++;
-			if (tp->RxDescArray[cur_rx].status & RxCRC)
+			if (status & RxCRC)
 				tp->stats.rx_crc_errors++;
 		} else {
-			pkt_size =
-			    (int) (tp->RxDescArray[cur_rx].
-				   status & 0x00001FFF) - 4;
-			skb = dev_alloc_skb(pkt_size + 2);
-			if (skb != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	// 16 byte align the IP fields. //
-				eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
-						 pkt_size, 0);
-				skb_put(skb, pkt_size);
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-
-				if (cur_rx == (NUM_RX_DESC - 1))
-					tp->RxDescArray[cur_rx].status =
-					    (OWNbit | EORbit) + RX_BUF_SIZE;
-				else
-					tp->RxDescArray[cur_rx].status =
-					    OWNbit + RX_BUF_SIZE;
-
-				tp->RxDescArray[cur_rx].buf_addr =
-				    virt_to_bus(tp->RxBufferRing[cur_rx]);
-				dev->last_rx = jiffies;
-				tp->stats.rx_bytes += pkt_size;
-				tp->stats.rx_packets++;
-			} else {
-				printk(KERN_WARNING
-				       "%s: Memory squeeze, deferring packet.\n",
-				       dev->name);
-				/* We should check that some rx space is free.
-				   If not, free one and mark stats->rx_dropped++. */
-				tp->stats.rx_dropped++;
+			struct RxDesc *desc = tp->RxDescArray + entry;
+			struct sk_buff *skb = tp->Rx_skbuff[entry];
+			int pkt_size = (status & 0x00001FFF) - 4;
+
+			pci_dma_sync_single(tp->pci_dev,
+					    le32_to_cpu(desc->buf_addr),
+					    RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+
+			if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) {
+				pci_unmap_single(tp->pci_dev,
+						 le32_to_cpu(desc->buf_addr),
+						 RX_BUF_SIZE,
+						 PCI_DMA_FROMDEVICE);
+				tp->Rx_skbuff[entry] = NULL;
 			}
-		}
-
-		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
 
+			skb_put(skb, pkt_size);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+
+			dev->last_rx = jiffies;
+			tp->stats.rx_bytes += pkt_size;
+			tp->stats.rx_packets++;
+		}
+		
+		cur_rx++;
+		rx_left--;
 	}
 
 	tp->cur_rx = cur_rx;
+
+	delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
+	if (delta > 0)
+		tp->dirty_rx += delta;
+	else if (delta < 0)
+		printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
+
+	/*
+	 * FIXME: until there is periodic timer to try and refill the ring,
+	 * a temporary shortage may definitely kill the Rx process.
+	 * - disable the asic to try and avoid an overflow and kick it again
+	 *   after refill ?
+	 * - how do others driver handle this condition (Uh oh...).
+	 */
+	if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
+		printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
@@ -991,9 +1500,7 @@
 		RTL_W16(IntrStatus,
 			(status & RxFIFOOver) ? (status | RxOverflow) : status);
 
-		if ((status &
-		     (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		      | TxErr | TxOK | RxErr | RxOK)) == 0)
+		if (!(status & rtl8169_intr_mask))
 			break;
 
 		// Rx interrupt 
@@ -1023,11 +1530,13 @@
 rtl8169_close(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	struct pci_dev *pdev = tp->pci_dev;
 	void *ioaddr = tp->mmio_addr;
-	int i;
 
 	netif_stop_queue(dev);
 
+	rtl8169_delete_timer(dev);
+
 	spin_lock_irq(&tp->lock);
 
 	/* Stop the chip's Tx and Rx DMA processes. */
@@ -1046,16 +1555,15 @@
 	free_irq(dev->irq, dev);
 
 	rtl8169_tx_clear(tp);
-	kfree(tp->TxDescArrays);
-	kfree(tp->RxDescArrays);
-	tp->TxDescArrays = NULL;
-	tp->RxDescArrays = NULL;
+
+	rtl8169_rx_clear(tp);
+
+	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
+			    tp->RxPhyAddr);
+	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
+			    tp->TxPhyAddr);
 	tp->TxDescArray = NULL;
 	tp->RxDescArray = NULL;
-	kfree(tp->RxBufferRings);
-	for (i = 0; i < NUM_RX_DESC; i++) {
-		tp->RxBufferRing[i] = NULL;
-	}
 
 	return 0;
 }
@@ -1109,11 +1617,26 @@
 	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
+/**
+ *  rtl8169_get_stats - Get rtl8169 read/write statistics
+ *  @dev: The Ethernet Device to get statistics for
+ *
+ *  Get TX/RX statistics for rtl8169
+ */
 struct net_device_stats *
 rtl8169_get_stats(struct net_device *dev)
 {
 	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
 
+	if (netif_running(dev)) {
+		spin_lock_irqsave(&tp->lock, flags);
+		tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+		RTL_W32(RxMissed, 0);
+		spin_unlock_irqrestore(&tp->lock, flags);
+	}
+		
 	return &tp->stats;
 }
 
@@ -1122,8 +1645,10 @@
 	.id_table	= rtl8169_pci_tbl,
 	.probe		= rtl8169_init_one,
 	.remove		= __devexit_p(rtl8169_remove_one),
-	.suspend	= NULL,
-	.resume		= NULL,
+#ifdef CONFIG_PM
+	.suspend	= rtl8169_suspend,
+	.resume		= rtl8169_resume,
+#endif
 };
 
 static int __init
--- diff/drivers/net/saa9730.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/saa9730.c	2004-02-18 09:04:00.000000000 +0000
@@ -1028,6 +1028,9 @@
 	 * Make certain the data structures used by the controller are aligned 
 	 * and DMAble. 
 	 */
+	/*
+	 *  XXX: that is obviously broken - kfree() won't be happy with us.
+	 */
 	lp = (struct lan_saa9730_private *) (((unsigned long)
 					      kmalloc(sizeof(*lp) + 7,
 						      GFP_DMA | GFP_KERNEL)
@@ -1095,7 +1098,6 @@
  out:
 	if (dev->priv)
 		kfree(dev->priv);
-	free_netdev(dev);
 	return ret;
 }
 
--- diff/drivers/net/shaper.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/shaper.c	2004-02-18 09:04:00.000000000 +0000
@@ -642,7 +642,6 @@
 
 	dev->open		= shaper_open;
 	dev->stop		= shaper_close;
-	dev->destructor 	= free_netdev;
 	dev->hard_start_xmit 	= shaper_start_xmit;
 	dev->get_stats 		= shaper_get_stats;
 	dev->set_multicast_list = NULL;
--- diff/drivers/net/smc-mca.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-mca.c	2004-02-18 09:04:00.000000000 +0000
@@ -324,6 +324,9 @@
 
 	dev->open = &ultramca_open;
 	dev->stop = &ultramca_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 
 	NS8390_init(dev, 0);
 
--- diff/drivers/net/smc-ultra.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-ultra.c	2004-02-18 09:04:00.000000000 +0000
@@ -121,6 +121,14 @@
 #define ULTRA_IO_EXTENT 32
 #define EN0_ERWCNT		0x08	/* Early receive warning count. */
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ultra_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	ei_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 /*	Probe for the Ultra.  This looks like a 8013 with the station
 	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
 	following.
@@ -134,6 +142,9 @@
 
 	SET_MODULE_OWNER(dev);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &ultra_poll;
+#endif
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return ultra_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
@@ -301,6 +312,9 @@
 	ei_status.reset_8390 = &ultra_reset_8390;
 	dev->open = &ultra_open;
 	dev->stop = &ultra_close_card;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/smc-ultra32.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/smc-ultra32.c	2004-02-18 09:04:00.000000000 +0000
@@ -268,6 +268,9 @@
 	ei_status.reset_8390 = &ultra32_reset_8390;
 	dev->open = &ultra32_open;
 	dev->stop = &ultra32_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 	return 0;
--- diff/drivers/net/stnic.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/stnic.c	2004-02-18 09:04:00.000000000 +0000
@@ -124,6 +124,9 @@
   dev->irq = IRQ_STNIC;
   dev->open = &stnic_open;
   dev->stop = &stnic_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+  dev->poll_controller = ei_poll;
+#endif
 
   /* Snarf the interrupt now.  There's no point in waiting since we cannot
      share and the board will usually be enabled. */
--- diff/drivers/net/tg3.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tg3.c	2004-02-18 09:04:00.000000000 +0000
@@ -2479,6 +2479,13 @@
 static int tg3_init_hw(struct tg3 *);
 static int tg3_halt(struct tg3 *);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tg3_poll_controller(struct net_device *dev)
+{
+	tg3_interrupt(dev->irq, dev, NULL);
+}
+#endif
+
 static void tg3_reset_task(void *_data)
 {
 	struct tg3 *tp = _data;
@@ -7696,6 +7703,9 @@
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = tg3_poll_controller;
+#endif
 
 	err = tg3_get_invariants(tp);
 	if (err) {
--- diff/drivers/net/tlan.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/net/tlan.c	2004-02-18 09:04:00.000000000 +0000
@@ -814,6 +814,14 @@
 
 } /* TLan_EisaProbe */
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void TLan_Poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	TLan_HandleInterrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 
 	
 
@@ -893,6 +901,9 @@
 	dev->get_stats = &TLan_GetStats;
 	dev->set_multicast_list = &TLan_SetMulticastList;
 	dev->do_ioctl = &TLan_ioctl;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &TLan_Poll;
+#endif
 	dev->tx_timeout = &TLan_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
--- diff/drivers/net/tokenring/3c359.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tokenring/3c359.c	2004-02-18 09:04:00.000000000 +0000
@@ -1129,7 +1129,7 @@
 				xl_freemem(dev) ; 
 				free_irq(dev->irq,dev); 
 				unregister_netdev(dev) ; 
-				kfree(dev) ;  
+				free_netdev(dev) ;  
 				xl_reset(dev) ; 
 				writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; 
 				spin_unlock(&xl_priv->xl_lock) ; 
--- diff/drivers/net/tulip/de4x5.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/net/tulip/de4x5.c	2004-02-18 09:04:00.000000000 +0000
@@ -5745,7 +5745,7 @@
 {
 	int err = 0;
 
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 	err = pci_module_init (&de4x5_pci_driver);
 #endif
 #ifdef CONFIG_EISA
@@ -5757,7 +5757,7 @@
 
 static void __exit de4x5_module_exit (void)
 {
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 	pci_unregister_driver (&de4x5_pci_driver);
 #endif
 #ifdef CONFIG_EISA
--- diff/drivers/net/tulip/interrupt.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/interrupt.c	2004-02-18 09:04:00.000000000 +0000
@@ -211,10 +211,10 @@
                                        if (tp->rx_buffers[entry].mapping !=
                                            le32_to_cpu(tp->rx_ring[entry].buffer1)) {
                                                printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-                                                      "do not match in tulip_rx: %08x vs. %08x %p / %p.\n",
+                                                      "do not match in tulip_rx: %08x vs. %llx %p / %p.\n",
                                                       dev->name,
                                                       le32_to_cpu(tp->rx_ring[entry].buffer1),
-                                                      tp->rx_buffers[entry].mapping,
+                                                      (unsigned long long)tp->rx_buffers[entry].mapping,
                                                       skb->head, temp);
                                        }
 #endif
--- diff/drivers/net/tulip/tulip_core.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tulip/tulip_core.c	2004-02-18 09:04:00.000000000 +0000
@@ -253,7 +253,7 @@
 static struct net_device_stats *tulip_get_stats(struct net_device *dev);
 static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
-
+static void poll_tulip(struct net_device *dev);
 
 
 static void tulip_set_power_state (struct tulip_private *tp,
@@ -1512,7 +1512,7 @@
 		}
 	}
 	/* Lite-On boards have the address byte-swapped. */
-	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02)
 		&&  dev->dev_addr[1] == 0x00)
 		for (i = 0; i < 6; i+=2) {
 			char tmp = dev->dev_addr[i];
@@ -1618,6 +1618,9 @@
 	dev->get_stats = tulip_get_stats;
 	dev->do_ioctl = private_ioctl;
 	dev->set_multicast_list = set_rx_mode;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &poll_tulip;
+#endif
 
 	if (register_netdev(dev))
 		goto err_out_free_ring;
@@ -1774,6 +1777,22 @@
 	/* pci_power_off (pdev, -1); */
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void poll_tulip (struct net_device *dev)
+{
+	/* disable_irq here is not very nice, but with the lockless
+	   interrupt handler we have no other choice. */
+	disable_irq(dev->irq);
+	tulip_interrupt (dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
 
 static struct pci_driver tulip_driver = {
 	.name		= DRV_NAME,
--- diff/drivers/net/tun.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/tun.c	2004-02-18 09:04:00.000000000 +0000
@@ -118,12 +118,10 @@
 }
 
 /* Initialize net device. */
-int tun_net_init(struct net_device *dev)
+static void tun_net_init(struct net_device *dev)
 {
 	struct tun_struct *tun = (struct tun_struct *)dev->priv;
    
-	DBG(KERN_INFO "%s: tun_net_init\n", tun->dev->name);
-
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case TUN_TUN_DEV:
 		/* Point-to-Point TUN Device */
@@ -147,9 +145,7 @@
 
 		ether_setup(dev);
 		break;
-	};
-
-	return 0;
+	}
 }
 
 /* Character device part */
@@ -351,7 +347,6 @@
 	init_waitqueue_head(&tun->read_wait);
 
 	tun->owner = -1;
-	dev->init = tun_net_init;
 
 	SET_MODULE_OWNER(dev);
 	dev->open = tun_net_open;
@@ -422,6 +417,8 @@
 		tun->dev = dev;
 		tun->flags = flags;
 
+		tun_net_init(dev);
+
 		if (strchr(dev->name, '%')) {
 			err = dev_alloc_name(dev, dev->name);
 			if (err < 0)
--- diff/drivers/net/via-rhine.c	2003-09-17 12:28:08.000000000 +0100
+++ source/drivers/net/via-rhine.c	2004-02-18 09:04:00.000000000 +0000
@@ -615,6 +615,15 @@
 			break;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void via_rhine_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	via_rhine_interrupt(dev->irq, (void *)dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
 {
@@ -784,6 +793,9 @@
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = via_rhine_poll;
+#endif
 	if (np->drv_flags & ReqTxAlign)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
--- diff/drivers/net/wan/Kconfig	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wan/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -434,8 +434,9 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called farsync.  If you want the module to be automatically loaded
 	  when the interface is referenced then you should add
-	  "alias hdlcX farsync" to /etc/modules.conf for each interface, where
-	  X is 0, 1, 2, ...
+	  "alias hdlcX farsync" to /etc/modprobe.conf for each interface, where
+	  X is 0, 1, 2, etc, or simply use "alias hdlc* farsync" to indicate
+	  all of them.
 
 config DLCI
 	tristate "Frame relay DLCI support"
--- diff/drivers/net/wan/c101.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/c101.c	2004-02-18 09:04:00.000000000 +0000
@@ -54,7 +54,7 @@
 
 
 typedef struct card_s {
-	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	struct net_device *dev;
 	spinlock_t lock;	/* TX lock */
 	u8 *win0base;		/* ISA window base address */
 	u32 phy_winbase;	/* ISA physical base address */
@@ -121,6 +121,7 @@
 
 static void sca_msci_intr(port_t *port)
 {
+	struct net_device *dev = port_to_dev(port);
 	card_t* card = port_to_card(port);
 	u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */
 
@@ -128,8 +129,9 @@
 	sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card);
 
 	if (stat & ST1_UDRN) {
-		port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
-		port->hdlc.stats.tx_fifo_errors++;
+		struct net_device_stats *stats = hdlc_stats(dev);
+		stats->tx_errors++; /* TX Underrun error detected */
+		stats->tx_fifo_errors++;
 	}
 
 	/* Reset MSCI CDCD status bit - uses ch#2 DCD input */
@@ -137,7 +139,7 @@
 
 	if (stat & ST1_CDCD)
 		hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
-				 &port->hdlc);
+				 dev);
 }
 
 
@@ -177,22 +179,21 @@
 
 static int c101_open(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	int result;
 
-	result = hdlc_open(hdlc);
+	result = hdlc_open(dev);
 	if (result)
 		return result;
 
 	writeb(1, port->win0base + C101_DTR);
 	sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
-	sca_open(hdlc);
+	sca_open(dev);
 	/* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */
 	sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port);
 	sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port);
 
-	hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc);
+	hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), dev);
 	printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port));
 
 	/* enable MSCI1 CDCD interrupt */
@@ -206,13 +207,12 @@
 
 static int c101_close(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
-	sca_close(hdlc);
+	sca_close(dev);
 	writeb(0, port->win0base + C101_DTR);
 	sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 	return 0;
 }
 
@@ -221,12 +221,11 @@
 {
 	const size_t size = sizeof(sync_serial_settings);
 	sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
 #ifdef DEBUG_RINGS
 	if (cmd == SIOCDEVPRIVATE) {
-		sca_dump_rings(hdlc);
+		sca_dump_rings(dev);
 		printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n",
 		       sca_in(MSCI1_OFFSET + ST0, port),
 		       sca_in(MSCI1_OFFSET + ST1, port),
@@ -288,6 +287,8 @@
 		release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE);
 	}
 
+	free_netdev(card->dev);
+
 	kfree(card);
 }
 
@@ -296,6 +297,7 @@
 static int __init c101_run(unsigned long irq, unsigned long winbase)
 {
 	struct net_device *dev;
+	hdlc_device *hdlc;
 	card_t *card;
 	int result;
 
@@ -316,6 +318,13 @@
 	}
 	memset(card, 0, sizeof(card_t));
 
+	card->dev = alloc_hdlcdev(card);
+	if (!card->dev) {
+		printk(KERN_ERR "c101: unable to allocate memory\n");
+		kfree(card);
+		return -ENOBUFS;
+	}
+
 	if (request_irq(irq, sca_intr, 0, devname, card)) {
 		printk(KERN_ERR "c101: could not allocate IRQ\n");
 		c101_destroy_card(card);
@@ -347,7 +356,8 @@
 
 	sca_init(card, 0);
 
-	dev = hdlc_to_dev(&card->hdlc);
+	dev = port_to_dev(card);
+	hdlc = dev_to_hdlc(dev);
 
 	spin_lock_init(&card->lock);
 	SET_MODULE_OWNER(dev);
@@ -358,24 +368,25 @@
 	dev->do_ioctl = c101_ioctl;
 	dev->open = c101_open;
 	dev->stop = c101_close;
-	card->hdlc.attach = sca_attach;
-	card->hdlc.xmit = sca_xmit;
+	hdlc->attach = sca_attach;
+	hdlc->xmit = sca_xmit;
 	card->settings.clock_type = CLOCK_EXT;
 
-	result = register_hdlc_device(&card->hdlc);
+	result = register_hdlc_device(dev);
 	if (result) {
 		printk(KERN_WARNING "c101: unable to register hdlc device\n");
 		c101_destroy_card(card);
 		return result;
 	}
 
+	/* XXX: are we OK with having that done when card is already up? */
+
 	sca_init_sync_port(card); /* Set up C101 memory */
-	hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
-			 &card->hdlc);
+	hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), dev);
 
 	printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
 	       " using %u TX + %u RX packets rings\n",
-	       hdlc_to_name(&card->hdlc), card->irq,
+	       dev->name, card->irq,
 	       card->tx_ring_buffers, card->rx_ring_buffers);
 
 	*new_card = card;
@@ -424,7 +435,7 @@
 	while (card) {
 		card_t *ptr = card;
 		card = card->next_card;
-		unregister_hdlc_device(&ptr->hdlc);
+		unregister_hdlc_device(port_to_dev(ptr));
 		c101_destroy_card(ptr);
 	}
 }
--- diff/drivers/net/wan/comx-hw-munich.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/comx-hw-munich.c	2004-02-18 09:04:00.000000000 +0000
@@ -2058,30 +2058,30 @@
     {
 	frs0 = readb(lbi + FRS0);
 	fmr2 = readb(lbi + FMR2);
-	len += snprintf(page + len, PAGE_SIZE - len, "Controller status:\n");
+	len += scnprintf(page + len, PAGE_SIZE - len, "Controller status:\n");
 	if (frs0 == 0)
-	    len += snprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n");
+	    len += scnprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n");
 	else
 	{
 	    if (frs0 & FRS0_LOS)
-	            len += snprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n");
+	            len += scnprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n");
 	    else
 	    {
 		if (frs0 & FRS0_AIS)
-		    len += snprintf(page + len, PAGE_SIZE - len,
+		    len += scnprintf(page + len, PAGE_SIZE - len,
 				 "\tAlarm Indication Signal\n");
 		else
 		{
 		    if (frs0 & FRS0_AUXP)
-			len += snprintf(page + len, PAGE_SIZE - len,
+			len += scnprintf(page + len, PAGE_SIZE - len,
 				     "\tAuxiliary Pattern Indication\n");
 		    if (frs0 & FRS0_LFA)
-			len += snprintf(page + len, PAGE_SIZE - len,
+			len += scnprintf(page + len, PAGE_SIZE - len,
 				     "\tLoss of Frame Alignment\n");
 		    else
 		    {
 			if (frs0 & FRS0_RRA)
-			    len += snprintf(page + len, PAGE_SIZE - len,
+			    len += scnprintf(page + len, PAGE_SIZE - len,
 					 "\tReceive Remote Alarm\n");
 
 			/* You can't set this framing with the /proc interface, but it  */
@@ -2089,11 +2089,11 @@
 
 			if ((board->framing == SLICECOM_FRAMING_CRC4) &&
 			    (frs0 & FRS0_LMFA))
-			    len += snprintf(page + len, PAGE_SIZE - len,
+			    len += scnprintf(page + len, PAGE_SIZE - len,
 					 "\tLoss of CRC4 Multiframe Alignment\n");
 
 			if (((fmr2 & 0xc0) == 0xc0) && (frs0 & FRS0_NMF))
-			    len += snprintf(page + len, PAGE_SIZE - len,
+			    len += scnprintf(page + len, PAGE_SIZE - len,
 				 "\tNo CRC4 Multiframe alignment Found after 400 msec\n");
 		    }
 		}
@@ -2102,27 +2102,27 @@
 
 	frs1 = readb(lbi + FRS1);
 	if (FRS1_XLS & frs1)
-	    len += snprintf(page + len, PAGE_SIZE - len,
+	    len += scnprintf(page + len, PAGE_SIZE - len,
 		 "\tTransmit Line Short\n");
 
 	/* debug Rx ring: DEL: - vagy meghagyni, de akkor legyen kicsit altalanosabb */
     }
 
-    len += snprintf(page + len, PAGE_SIZE - len, "Rx ring:\n");
-    len += snprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott);
-    len += snprintf(page + len, PAGE_SIZE - len,
+    len += scnprintf(page + len, PAGE_SIZE - len, "Rx ring:\n");
+    len += scnprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott);
+    len += scnprintf(page + len, PAGE_SIZE - len,
 		 "\tlastcheck: %ld, jiffies: %ld\n", board->lastcheck, jiffies);
-    len += snprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n",
+    len += scnprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n",
 	(u32) virt_to_phys(&hw->rx_desc[0]));
-    len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n",
+    len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n",
 		 hw->rx_desc_ptr);
-    len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n",
+    len += scnprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n",
 	(u32) virt_to_phys(&hw->rx_desc[hw->rx_desc_ptr]));
-    len += snprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n",
+    len += scnprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n",
 		 board->ccb->current_rx_desc[hw->channel]);
 
     for (i = 0; i < RX_DESC_MAX; i++)
-	len += snprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n",
+	len += scnprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n",
 		     *((u32 *) & hw->rx_desc[i] + 0),
 		     *((u32 *) & hw->rx_desc[i] + 1),
 		     *((u32 *) & hw->rx_desc[i] + 2),
@@ -2130,7 +2130,7 @@
 
     if (!board->isx21)
     {
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "Interfaces using this board: (channel-group, interface, timeslots)\n");
 	for (i = 0; i < 32; i++)
 	{
@@ -2141,26 +2141,26 @@
 		    ((struct slicecom_privdata *)((struct comx_channel *)devp->
 						  priv)->HW_privdata)->
 		    timeslots;
-		len += snprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i,
+		len += scnprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i,
 			     devp->name);
 		for (j = 0; j < 32; j++)
 		    if ((1 << j) & timeslots)
-			len += snprintf(page + len, PAGE_SIZE - len, "%d ", j);
-		len += snprintf(page + len, PAGE_SIZE - len, "\n");
+			len += scnprintf(page + len, PAGE_SIZE - len, "%d ", j);
+		len += scnprintf(page + len, PAGE_SIZE - len, "\n");
 	    }
 	}
     }
 
-    len += snprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n");
+    len += scnprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n");
     for (i = 0; i < MAX_WORK; i++)
-	len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
+	len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
 		     board->histogram[i], (i &&
 					   ((i + 1) % 4 == 0 ||
 					    i == MAX_WORK - 1)) ? '\n' : ' ');
 
-    len += snprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n");
+    len += scnprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n");
     for (i = 0; i < TX_DESC_MAX; i++)
-	len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
+	len += scnprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
 		     hw->tx_ring_hist[i], (i &&
 					   ((i + 1) % 4 == 0 ||
 					    i ==
@@ -2196,72 +2196,72 @@
 		sump[j] += p[j];
 	}
 
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "Data in current interval (%d seconds elapsed):\n",
 		     board->elapsed_seconds);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
 		     curr_int->line_code_violations,
 		     curr_int->path_code_violations, curr_int->e_bit_errors);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
 		     curr_int->slip_secs, curr_int->fr_loss_secs,
 		     curr_int->line_err_secs, curr_int->degraded_mins);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
 		     curr_int->errored_secs, curr_int->bursty_err_secs,
 		     curr_int->severely_err_secs, curr_int->unavail_secs);
 
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "Data in Interval 1 (15 minutes):\n");
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
 		     prev_int->line_code_violations,
 		     prev_int->path_code_violations, prev_int->e_bit_errors);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
 		     prev_int->slip_secs, prev_int->fr_loss_secs,
 		     prev_int->line_err_secs, prev_int->degraded_mins);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
 		     prev_int->errored_secs, prev_int->bursty_err_secs,
 		     prev_int->severely_err_secs, prev_int->unavail_secs);
 
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "Data in last 4 intervals (1 hour):\n");
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
 		     last4.line_code_violations, last4.path_code_violations,
 		     last4.e_bit_errors);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
 		     last4.slip_secs, last4.fr_loss_secs, last4.line_err_secs,
 		     last4.degraded_mins);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
 		     last4.errored_secs, last4.bursty_err_secs,
 		     last4.severely_err_secs, last4.unavail_secs);
 
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "Data in last 96 intervals (24 hours):\n");
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
 		     last96.line_code_violations, last96.path_code_violations,
 		     last96.e_bit_errors);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
 		     last96.slip_secs, last96.fr_loss_secs,
 		     last96.line_err_secs, last96.degraded_mins);
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "   %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
 		     last96.errored_secs, last96.bursty_err_secs,
 		     last96.severely_err_secs, last96.unavail_secs);
 
     }
 
-//      len +=snprintf( page + len, PAGE_SIZE - len, "Special events:\n" );
-//      len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed );
-//      len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed );
+//      len +=scnprintf( page + len, PAGE_SIZE - len, "Special events:\n" );
+//      len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed );
+//      len +=scnprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed );
     return len;
 }
 
@@ -2305,8 +2305,8 @@
     {
 	for (i = 0; i < 32; i++)
 	    if ((1 << i) & timeslots)
-		len += snprintf(page + len, PAGE_SIZE - len, "%d ", i);
-	len += snprintf(page + len, PAGE_SIZE - len, "\n");
+		len += scnprintf(page + len, PAGE_SIZE - len, "%d ", i);
+	len += scnprintf(page + len, PAGE_SIZE - len, "\n");
     }
     else if (!strcmp(file->name, FILENAME_FRAMING))
     {
@@ -2314,7 +2314,7 @@
 	while (slicecom_framings[i].value &&
 	       slicecom_framings[i].value != board->framing)
 	    i++;
-	len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
+	len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
 		     slicecom_framings[i].name);
     }
     else if (!strcmp(file->name, FILENAME_LINECODE))
@@ -2323,7 +2323,7 @@
 	while (slicecom_linecodes[i].value &&
 	       slicecom_linecodes[i].value != board->linecode)
 	    i++;
-	len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
+	len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
 		     slicecom_linecodes[i].name);
     }
     else if (!strcmp(file->name, FILENAME_CLOCK_SOURCE))
@@ -2333,7 +2333,7 @@
 	       slicecom_clock_sources[i].value != board->clock_source)
 	    i++;
 	len +=
-	    snprintf(page + len, PAGE_SIZE - len, "%s\n",
+	    scnprintf(page + len, PAGE_SIZE - len, "%s\n",
 		     slicecom_clock_sources[i].name);
     }
     else if (!strcmp(file->name, FILENAME_LOOPBACK))
@@ -2342,18 +2342,18 @@
 	while (slicecom_loopbacks[i].value &&
 	       slicecom_loopbacks[i].value != board->loopback)
 	    i++;
-	len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
+	len += scnprintf(page + len, PAGE_SIZE - len, "%s\n",
 		     slicecom_loopbacks[i].name);
     }
     /* We set permissions to write-only for REG and LBIREG, but root can read them anyway: */
     else if (!strcmp(file->name, FILENAME_REG))
     {
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "%s: " FILENAME_REG ": write-only file\n", dev->name);
     }
     else if (!strcmp(file->name, FILENAME_LBIREG))
     {
-	len += snprintf(page + len, PAGE_SIZE - len,
+	len += scnprintf(page + len, PAGE_SIZE - len,
 		     "%s: " FILENAME_LBIREG ": write-only file\n", dev->name);
     }
     else
--- diff/drivers/net/wan/comx-proto-lapb.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/comx-proto-lapb.c	2004-02-18 09:04:00.000000000 +0000
@@ -44,7 +44,7 @@
 	if (!dev || !dev->priv) {
 		dev_kfree_skb(skb);
 	} else {
-		lapb_data_received(dev->priv, skb);
+		lapb_data_received(dev, skb);
 	}
 }
 
@@ -82,7 +82,7 @@
 		return -ENODEV;
 	}
 
-	err = lapb_connect_request(ch);
+	err = lapb_connect_request(dev);
 
 	if (ch->debug_flags & DEBUG_COMX_LAPB) {
 		comx_debug(dev, "%s: lapb opened, error code: %d\n", 
@@ -108,7 +108,7 @@
 		comx_debug(dev, "%s: lapb closed\n", dev->name);
 	}
 
-	lapb_disconnect_request(ch);
+	lapb_disconnect_request(dev);
 
 	ch->init_status &= ~LINE_OPEN;
 	ch->line_status &= ~PROTO_UP;
@@ -130,11 +130,11 @@
 			case 0x00:	
 				break;	// transmit
 			case 0x01:	
-				lapb_connect_request(ch);
+				lapb_connect_request(dev);
 				kfree_skb(skb);
 				return 0;
 			case 0x02:	
-				lapb_disconnect_request(ch);
+				lapb_disconnect_request(dev);
 			default:
 				kfree_skb(skb);
 				return 0;
@@ -145,7 +145,7 @@
 	netif_stop_queue(dev);
 	
 	if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
-		lapb_data_request(ch, skb2);
+		lapb_data_request(dev, skb2);
 	}
 
 	return FRAME_ACCEPTED;
@@ -157,7 +157,7 @@
 	int len = 0;
 
 	len += sprintf(page + len, "Line status: ");
-	if (lapb_getparms(dev->priv, &parms) != LAPB_OK) {
+	if (lapb_getparms(dev, &parms) != LAPB_OK) {
 		len += sprintf(page + len, "not initialized\n");
 		return len;
 	}
@@ -178,7 +178,7 @@
 	struct lapb_parms_struct parms;
 	int len = 0;
 
-	if (lapb_getparms(dev->priv, &parms)) {
+	if (lapb_getparms(dev, &parms)) {
 		return -ENODEV;
 	}
 
@@ -223,7 +223,7 @@
 	unsigned long parm;
 	char *page;
 
-	if (lapb_getparms(dev->priv, &parms)) {
+	if (lapb_getparms(dev, &parms)) {
 		return -ENODEV;
 	}
 
@@ -243,23 +243,23 @@
 		parm=simple_strtoul(page,NULL,10);
 		if (parm > 0 && parm < 100) {
 			parms.t1=parm;
-			lapb_setparms(dev->priv, &parms);
+			lapb_setparms(dev, &parms);
 		}
 	} else if (strcmp(entry->name, FILENAME_T2) == 0) {
 		parm=simple_strtoul(page, NULL, 10);
 		if (parm > 0 && parm < 100) {
 			parms.t2=parm;
-			lapb_setparms(dev->priv, &parms);
+			lapb_setparms(dev, &parms);
 		}
 	} else if (strcmp(entry->name, FILENAME_N2) == 0) {
 		parm=simple_strtoul(page, NULL, 10);
 		if (parm > 0 && parm < 100) {
 			parms.n2=parm;
-			lapb_setparms(dev->priv, &parms);
+			lapb_setparms(dev, &parms);
 		}
 	} else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
 		parms.window = simple_strtoul(page, NULL, 10);
-		lapb_setparms(dev->priv, &parms);
+		lapb_setparms(dev, &parms);
 	} else if (strcmp(entry->name, FILENAME_MODE) == 0) {
 		if (comx_strcasecmp(page, "dte") == 0) {
 			parms.mode &= ~(LAPB_DCE | LAPB_DTE); 
@@ -276,7 +276,7 @@
 			parms.mode &= ~LAPB_STANDARD; 
 			parms.mode |= LAPB_EXTENDED;
 		}
-		lapb_setparms(dev->priv, &parms);
+		lapb_setparms(dev, &parms);
 	} else {
 		printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n", 
 			entry->name);
@@ -287,9 +287,9 @@
 	return count;
 }
 
-static void comxlapb_connected(void *token, int reason)
+static void comxlapb_connected(struct net_device *dev, int reason)
 {
-	struct comx_channel *ch = token; 
+	struct comx_channel *ch = dev->priv; 
 	struct proc_dir_entry *comxdir = ch->procdir->subdir;
 
 	if (ch->debug_flags & DEBUG_COMX_LAPB) {
@@ -327,9 +327,9 @@
 	comx_status(ch->dev, ch->line_status);
 }
 
-static void comxlapb_disconnected(void *token, int reason)
+static void comxlapb_disconnected(struct net_device *dev, int reason)
 {
-	struct comx_channel *ch = token; 
+	struct comx_channel *ch = dev->priv; 
 	struct proc_dir_entry *comxdir = ch->procdir->subdir;
 
 	if (ch->debug_flags & DEBUG_COMX_LAPB) {
@@ -366,9 +366,9 @@
 	comx_status(ch->dev, ch->line_status);
 }
 
-static int comxlapb_data_indication(void *token, struct sk_buff *skb)
+static int comxlapb_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
-	struct comx_channel *ch = token; 
+	struct comx_channel *ch = dev->priv; 
 
 	if (ch->dev->type == ARPHRD_X25) {
 		skb_push(skb, 1);
@@ -387,9 +387,9 @@
 	return comx_rx(ch->dev, skb);
 }
 
-static void comxlapb_data_transmit(void *token, struct sk_buff *skb)
+static void comxlapb_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
-	struct comx_channel *ch = token; 
+	struct comx_channel *ch = dev->priv; 
 
 	if (ch->HW_send_packet) {
 		ch->HW_send_packet(ch->dev, skb);
@@ -417,7 +417,7 @@
 	if (ch->debug_flags & DEBUG_COMX_LAPB) {
 		comx_debug(dev, "%s: unregistering lapb\n", dev->name);
 	}
-	lapb_unregister(dev->priv);
+	lapb_unregister(dev);
 
 	remove_proc_entry(FILENAME_T1, ch->procdir);
 	remove_proc_entry(FILENAME_T2, ch->procdir);
@@ -453,7 +453,7 @@
 	lapbreg.disconnect_indication = comxlapb_disconnected;
 	lapbreg.data_indication = comxlapb_data_indication;
 	lapbreg.data_transmit = comxlapb_data_transmit;
-	if (lapb_register(dev->priv, &lapbreg)) {
+	if (lapb_register(dev, &lapbreg)) {
 		return -ENOMEM;
 	}
 	if (ch->debug_flags & DEBUG_COMX_LAPB) {
--- diff/drivers/net/wan/dlci.c	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/net/wan/dlci.c	2004-02-18 09:04:00.000000000 +0000
@@ -414,7 +414,7 @@
 
  err2:
 	rtnl_unlock();
-	kfree(master);
+	free_netdev(master);
  err1:
 	dev_put(slave);
 	return(err);
--- diff/drivers/net/wan/dscc4.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/dscc4.c	2004-02-18 09:04:00.000000000 +0000
@@ -228,7 +228,7 @@
 
 	unsigned short encoding;
 	unsigned short parity;
-	hdlc_device hdlc;
+	struct net_device *dev;
 	sync_serial_settings settings;
 	u32 __pad __attribute__ ((aligned (4)));
 };
@@ -364,7 +364,7 @@
 static void dscc4_timer(unsigned long);
 static void dscc4_tx_timeout(struct net_device *);
 static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
-static int dscc4_hdlc_attach(hdlc_device *, unsigned short, unsigned short);
+static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short);
 static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);
 static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int);
 #ifdef DSCC4_POLLING
@@ -373,7 +373,12 @@
 
 static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev)
 {
-	return list_entry(dev, struct dscc4_dev_priv, hdlc.netdev);
+	return dev_to_hdlc(dev)->priv;
+}
+
+static inline struct net_device *dscc4_to_dev(struct dscc4_dev_priv *p)
+{
+	return p->dev;
 }
 
 static void scc_patchl(u32 mask, u32 value, struct dscc4_dev_priv *dpriv,
@@ -636,7 +641,7 @@
 				struct net_device *dev)
 {
 	struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE;
-	struct net_device_stats *stats = &dpriv->hdlc.stats;
+	struct net_device_stats *stats = hdlc_stats(dev);
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
 	struct sk_buff *skb;
 	int pkt_len;
@@ -689,10 +694,12 @@
 	root = ppriv->root;
 
 	for (i = 0; i < dev_per_card; i++)
-		unregister_hdlc_device(&root[i].hdlc);
+		unregister_hdlc_device(dscc4_to_dev(&root[i]));
 
 	pci_set_drvdata(pdev, NULL);
 
+	for (i = 0; i < dev_per_card; i++)
+		free_netdev(root[i].dev);
 	kfree(root);
 	kfree(ppriv);
 }
@@ -874,17 +881,31 @@
 	}
 	memset(root, 0, dev_per_card*sizeof(*root));
 
+	for (i = 0; i < dev_per_card; i++) {
+		root[i].dev = alloc_hdlcdev(root + i);
+		if (!root[i].dev) {
+			while (i--)
+				free_netdev(root[i].dev);
+			goto err_free_dev;
+		}
+	}
+
 	ppriv = (struct dscc4_pci_priv *) kmalloc(sizeof(*ppriv), GFP_KERNEL);
 	if (!ppriv) {
 		printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
-		goto err_free_dev;
+		goto err_free_dev2;
 	}
 	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
+	ret = dscc4_set_quartz(root, quartz);
+	if (ret < 0)
+		goto err_free_priv;
+	ppriv->root = root;
+	spin_lock_init(&ppriv->lock);
 
 	for (i = 0; i < dev_per_card; i++) {
 		struct dscc4_dev_priv *dpriv = root + i;
-		hdlc_device *hdlc = &dpriv->hdlc;
-		struct net_device *d = hdlc_to_dev(hdlc);
+		struct net_device *d = dscc4_to_dev(dpriv);
+		hdlc_device *hdlc = dev_to_hdlc(d);
 
 	        d->base_addr = ioaddr;
 		d->init = NULL;
@@ -905,36 +926,34 @@
 		hdlc->xmit = dscc4_start_xmit;
 		hdlc->attach = dscc4_hdlc_attach;
 
-		ret = register_hdlc_device(hdlc);
-		if (ret < 0) {
-			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
-			goto err_unregister;
-	        }
-
 		dscc4_init_registers(dpriv, d);
 		dpriv->parity = PARITY_CRC16_PR0_CCITT;
 		dpriv->encoding = ENCODING_NRZ;
-
+	
 		ret = dscc4_init_ring(d);
+		if (ret < 0)
+			goto err_unregister;
+
+		ret = register_hdlc_device(d);
 		if (ret < 0) {
-			unregister_hdlc_device(hdlc);
+			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
+			dscc4_release_ring(dpriv);
 			goto err_unregister;
-		}
+	        }
 	}
-	ret = dscc4_set_quartz(root, quartz);
-	if (ret < 0)
-		goto err_unregister;
-	ppriv->root = root;
-	spin_lock_init(&ppriv->lock);
 	pci_set_drvdata(pdev, ppriv);
 	return ret;
 
 err_unregister:
 	while (--i >= 0) {
 		dscc4_release_ring(root + i);
-		unregister_hdlc_device(&root[i].hdlc);
+		unregister_hdlc_device(dscc4_to_dev(&root[i]));
 	}
+err_free_priv:
 	kfree(ppriv);
+err_free_dev2:
+	for (i = 0; i < dev_per_card; i++)
+		free_netdev(root[i].dev);
 err_free_dev:
 	kfree(root);
 err_out:
@@ -964,7 +983,7 @@
 	sync_serial_settings *settings = &dpriv->settings;
 
 	if (settings->loopback && (settings->clock_type != CLOCK_INT)) {
-		struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
+		struct net_device *dev = dscc4_to_dev(dpriv);
 
 		printk(KERN_INFO "%s: loopback requires clock\n", dev->name);
 		return -1;
@@ -1015,14 +1034,13 @@
 static int dscc4_open(struct net_device *dev)
 {
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
-	hdlc_device *hdlc = &dpriv->hdlc;
 	struct dscc4_pci_priv *ppriv;
 	int ret = -EAGAIN;
 
 	if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit)
 		goto err;
 
-	if ((ret = hdlc_open(hdlc)))
+	if ((ret = hdlc_open(dev)))
 		goto err;
 
 	ppriv = dpriv->pci_priv;
@@ -1103,7 +1121,7 @@
 	scc_writel(0xffffffff, dpriv, dev, IMR);
 	scc_patchl(PowerUp | Vis, 0, dpriv, dev, CCR0);
 err_out:
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 err:
 	return ret;
 }
@@ -1155,7 +1173,6 @@
 static int dscc4_close(struct net_device *dev)
 {
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
-	hdlc_device *hdlc = dev_to_hdlc(dev);
 
 	del_timer_sync(&dpriv->timer);
 	netif_stop_queue(dev);
@@ -1166,7 +1183,7 @@
 
 	dpriv->flags |= FakeReset;
 
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 
 	return 0;
 }
@@ -1467,7 +1484,7 @@
 	int i, handled = 1;
 
 	priv = root->pci_priv;
-	dev = hdlc_to_dev(&root->hdlc);
+	dev = dscc4_to_dev(root);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -1518,7 +1535,7 @@
 static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
 				struct dscc4_dev_priv *dpriv)
 {
-	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
+	struct net_device *dev = dscc4_to_dev(dpriv);
 	u32 state;
 	int cur, loop = 0;
 
@@ -1549,7 +1566,7 @@
 
 	if (state & SccEvt) {
 		if (state & Alls) {
-			struct net_device_stats *stats = &dpriv->hdlc.stats;
+			struct net_device_stats *stats = hdlc_stats(dev);
 			struct sk_buff *skb;
 			struct TxFD *tx_fd;
 
@@ -1677,7 +1694,7 @@
 		}
 		if (state & Err) {
 			printk(KERN_INFO "%s: Tx ERR\n", dev->name);
-			dev_to_hdlc(dev)->stats.tx_errors++;
+			hdlc_stats(dev)->tx_errors++;
 			state &= ~Err;
 		}
 	}
@@ -1687,7 +1704,7 @@
 static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
 				    struct dscc4_dev_priv *dpriv)
 {
-	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
+	struct net_device *dev = dscc4_to_dev(dpriv);
 	u32 state;
 	int cur;
 
@@ -1813,7 +1830,7 @@
 				if (!(rx_fd->state2 & DataComplete))
 					break;
 				if (rx_fd->state2 & FrameAborted) {
-					dev_to_hdlc(dev)->stats.rx_over_errors++;
+					hdlc_stats(dev)->rx_over_errors++;
 					rx_fd->state1 |= Hold;
 					rx_fd->state2 = 0x00000000;
 					rx_fd->end = 0xbabeface;
@@ -1961,7 +1978,7 @@
 	ppriv = pci_get_drvdata(pdev);
 	root = ppriv->root;
 
-	ioaddr = hdlc_to_dev(&root->hdlc)->base_addr;
+	ioaddr = dscc4_to_dev(root)->base_addr;
 
 	dscc4_pci_reset(pdev, ioaddr);
 
@@ -1988,10 +2005,9 @@
 			   pci_resource_len(pdev, 0));
 }
 
-static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding,
+static int dscc4_hdlc_attach(struct net_device *dev, unsigned short encoding,
 	unsigned short parity)
 {
-	struct net_device *dev = hdlc_to_dev(hdlc);
 	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 
 	if (encoding != ENCODING_NRZ &&
--- diff/drivers/net/wan/farsync.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/net/wan/farsync.c	2004-02-18 09:04:00.000000000 +0000
@@ -328,7 +328,7 @@
 /*      Per port (line or channel) information
  */
 struct fst_port_info {
-        hdlc_device             hdlc;   /* HDLC device struct - must be first */
+        struct net_device      *dev;
         struct fst_card_info   *card;   /* Card we're associated with */
         int                     index;  /* Port index on the card */
         int                     hwif;   /* Line hardware (lineInterface copy) */
@@ -357,9 +357,8 @@
 };
 
 /* Convert an HDLC device pointer into a port info pointer and similar */
-#define hdlc_to_port(H) ((struct fst_port_info *)(H))
-#define dev_to_port(D)  hdlc_to_port(dev_to_hdlc(D))
-#define port_to_dev(P)  hdlc_to_dev(&(P)->hdlc)
+#define dev_to_port(D)  (dev_to_hdlc(D)->priv)
+#define port_to_dev(P)  ((P)->dev)
 
 
 /*
@@ -651,6 +650,8 @@
         int rxp;
         unsigned short len;
         struct sk_buff *skb;
+	struct net_device *dev = port_to_dev(port);
+	struct net_device_stats *stats = hdlc_stats(dev);
         int i;
 
 
@@ -678,24 +679,24 @@
                                         len );
         if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 )
         {
-                port->hdlc.stats.rx_errors++;
+                stats->rx_errors++;
 
                 /* Update error stats and discard buffer */
                 if ( dmabits & RX_OFLO )
                 {
-                        port->hdlc.stats.rx_fifo_errors++;
+                        stats->rx_fifo_errors++;
                 }
                 if ( dmabits & RX_CRC )
                 {
-                        port->hdlc.stats.rx_crc_errors++;
+                        stats->rx_crc_errors++;
                 }
                 if ( dmabits & RX_FRAM )
                 {
-                        port->hdlc.stats.rx_frame_errors++;
+                        stats->rx_frame_errors++;
                 }
                 if ( dmabits == ( RX_STP | RX_ENP ))
                 {
-                        port->hdlc.stats.rx_length_errors++;
+                        stats->rx_length_errors++;
                 }
 
                 /* Discard buffer descriptors until we see the end of packet
@@ -732,7 +733,7 @@
         {
                 dbg ( DBG_RX,"intr_rx: can't allocate buffer\n");
 
-                port->hdlc.stats.rx_dropped++;
+                stats->rx_dropped++;
 
                 /* Return descriptor to card */
                 FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
@@ -756,16 +757,16 @@
                 port->rxpos = rxp;
 
         /* Update stats */
-        port->hdlc.stats.rx_packets++;
-        port->hdlc.stats.rx_bytes += len;
+        stats->rx_packets++;
+        stats->rx_bytes += len;
 
         /* Push upstream */
         skb->mac.raw = skb->data;
-        skb->dev = hdlc_to_dev ( &port->hdlc );
+        skb->dev = dev;
         skb->protocol = hdlc_type_trans(skb, skb->dev);
         netif_rx ( skb );
 
-        port_to_dev ( port )->last_rx = jiffies;
+        dev->last_rx = jiffies;
 }
 
 
@@ -835,8 +836,8 @@
                          * always load up the entire packet for DMA.
                          */
                         dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 );
-                        port->hdlc.stats.tx_errors++;
-                        port->hdlc.stats.tx_fifo_errors++;
+                        hdlc_stats(port_to_dev(port))->tx_errors++;
+                        hdlc_stats(port_to_dev(port))->tx_fifo_errors++;
                         break;
 
                 case INIT_CPLT:
@@ -1309,7 +1310,7 @@
 {
         int err;
 
-        err = hdlc_open ( dev_to_hdlc ( dev ));
+        err = hdlc_open (dev);
         if ( err )
                 return err;
 
@@ -1323,12 +1324,12 @@
 {
         netif_stop_queue ( dev );
         fst_closeport ( dev_to_port ( dev ));
-        hdlc_close ( dev_to_hdlc  ( dev ));
+        hdlc_close ( dev );
         return 0;
 }
 
 static int
-fst_attach ( hdlc_device *hdlc, unsigned short encoding, unsigned short parity )
+fst_attach ( struct net_device *dev, unsigned short encoding, unsigned short parity )
 {
         /* Setting currently fixed in FarSync card so we check and forget */
         if ( encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT )
@@ -1341,13 +1342,14 @@
 fst_tx_timeout ( struct net_device *dev )
 {
         struct fst_port_info *port;
+	struct net_device_stats *stats = hdlc_stats(dev);
 
         dbg ( DBG_INTR | DBG_TX,"tx_timeout\n");
 
         port = dev_to_port ( dev );
 
-        port->hdlc.stats.tx_errors++;
-        port->hdlc.stats.tx_aborted_errors++;
+        stats->tx_errors++;
+        stats->tx_aborted_errors++;
 
         if ( port->txcnt > 0 )
                 fst_issue_cmd ( port, ABORTTX );
@@ -1360,6 +1362,7 @@
 static int
 fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
 {
+	struct net_device_stats *stats = hdlc_stats(dev);
         struct fst_card_info *card;
         struct fst_port_info *port;
         unsigned char dmabits;
@@ -1374,8 +1377,8 @@
         if ( ! netif_carrier_ok ( dev ))
         {
                 dev_kfree_skb ( skb );
-                port->hdlc.stats.tx_errors++;
-                port->hdlc.stats.tx_carrier_errors++;
+                stats->tx_errors++;
+                stats->tx_carrier_errors++;
                 return 0;
         }
 
@@ -1385,7 +1388,7 @@
                 dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len,
                                                 LEN_TX_BUFFER );
                 dev_kfree_skb ( skb );
-                port->hdlc.stats.tx_errors++;
+                stats->tx_errors++;
                 return 0;
         }
 
@@ -1399,7 +1402,7 @@
                 spin_unlock_irqrestore ( &card->card_lock, flags );
                 dbg ( DBG_TX,"Out of Tx buffers\n");
                 dev_kfree_skb ( skb );
-                port->hdlc.stats.tx_errors++;
+                stats->tx_errors++;
                 return 0;
         }
         if ( ++port->txpos >= NUM_TX_BUFFER )
@@ -1419,8 +1422,8 @@
         FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len ));
         FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP );
 
-        port->hdlc.stats.tx_packets++;
-        port->hdlc.stats.tx_bytes += skb->len;
+        stats->tx_packets++;
+        stats->tx_bytes += skb->len;
 
         dev_kfree_skb ( skb );
 
@@ -1447,55 +1450,29 @@
 {
         int i;
         int err;
-        struct net_device *dev;
 
         /* We're working on a number of ports based on the card ID. If the
          * firmware detects something different later (should never happen)
          * we'll have to revise it in some way then.
          */
-        for ( i = 0 ; i < card->nports ; i++ )
-        {
-                card->ports[i].card   = card;
-                card->ports[i].index  = i;
-                card->ports[i].run    = 0;
-
-                dev = hdlc_to_dev ( &card->ports[i].hdlc );
-
-                /* Fill in the net device info */
-                                /* Since this is a PCI setup this is purely
-                                 * informational. Give them the buffer addresses
-                                 * and basic card I/O.
-                                 */
-                dev->mem_start   = card->phys_mem
-                                 + BUF_OFFSET ( txBuffer[i][0][0]);
-                dev->mem_end     = card->phys_mem
-                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]);
-                dev->base_addr   = card->pci_conf;
-                dev->irq         = card->irq;
-
-                dev->tx_queue_len          = FST_TX_QUEUE_LEN;
-                dev->open                  = fst_open;
-                dev->stop                  = fst_close;
-                dev->do_ioctl              = fst_ioctl;
-                dev->watchdog_timeo        = FST_TX_TIMEOUT;
-                dev->tx_timeout            = fst_tx_timeout;
-                card->ports[i].hdlc.attach = fst_attach;
-                card->ports[i].hdlc.xmit   = fst_start_xmit;
-
-                if (( err = register_hdlc_device ( &card->ports[i].hdlc )) < 0 )
-                {
+        for ( i = 0 ; i < card->nports ; i++ ) {
+                err = register_hdlc_device(card->ports[i].dev);
+                if (err < 0) {
+			int j;
                         printk_err ("Cannot register HDLC device for port %d"
                                     " (errno %d)\n", i, -err );
+			for (j = i; j < card->nports; j++) {
+				free_netdev(card->ports[j].dev);
+				card->ports[j].dev = NULL;
+			}
                         card->nports = i;
                         break;
                 }
         }
 
-        spin_lock_init ( &card->card_lock );
-
         printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n",
-                        hdlc_to_dev(&card->ports[0].hdlc)->name,
-                        hdlc_to_dev(&card->ports[card->nports-1].hdlc)->name,
+                        port_to_dev(&card->ports[0])->name,
+                        port_to_dev(&card->ports[card->nports-1])->name,
                         type_strings[card->type], card->irq, card->nports );
 }
 
@@ -1510,6 +1487,7 @@
         static int firsttime_done = 0;
         struct fst_card_info *card;
         int err = 0;
+	int i;
 
         if ( ! firsttime_done )
         {
@@ -1546,6 +1524,46 @@
 
         card->state       = FST_UNINIT;
 
+        spin_lock_init ( &card->card_lock );
+
+        for ( i = 0 ; i < card->nports ; i++ ) {
+		struct net_device *dev = alloc_hdlcdev(&card->ports[i]);
+		hdlc_device *hdlc;
+		if (!dev) {
+			while (i--)
+				free_netdev(card->ports[i].dev);
+			printk_err ("FarSync: out of memory\n");
+			goto error_free_card;
+		}
+		card->ports[i].dev    = dev;
+                card->ports[i].card   = card;
+                card->ports[i].index  = i;
+                card->ports[i].run    = 0;
+
+		hdlc = dev_to_hdlc(dev);
+
+                /* Fill in the net device info */
+		/* Since this is a PCI setup this is purely
+		 * informational. Give them the buffer addresses
+		 * and basic card I/O.
+		 */
+                dev->mem_start   = card->phys_mem
+                                 + BUF_OFFSET ( txBuffer[i][0][0]);
+                dev->mem_end     = card->phys_mem
+                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]);
+                dev->base_addr   = card->pci_conf;
+                dev->irq         = card->irq;
+
+                dev->tx_queue_len          = FST_TX_QUEUE_LEN;
+                dev->open                  = fst_open;
+                dev->stop                  = fst_close;
+                dev->do_ioctl              = fst_ioctl;
+                dev->watchdog_timeo        = FST_TX_TIMEOUT;
+                dev->tx_timeout            = fst_tx_timeout;
+                hdlc->attach = fst_attach;
+                hdlc->xmit   = fst_start_xmit;
+	}
+
         dbg ( DBG_PCI,"type %d nports %d irq %d\n", card->type,
                         card->nports, card->irq );
         dbg ( DBG_PCI,"conf %04x mem %08x ctlmem %08x\n",
@@ -1557,7 +1575,7 @@
                 printk_err ("Unable to get config I/O @ 0x%04X\n",
                                                 card->pci_conf );
                 err = -ENODEV;
-                goto error_free_card;
+                goto error_free_ports;
         }
         if ( ! request_mem_region ( card->phys_mem, FST_MEMSIZE,"Shared RAM"))
         {
@@ -1628,6 +1646,9 @@
 error_release_io:
         release_region ( card->pci_conf, 0x80 );
 
+error_free_ports:
+	for (i = 0; i < card->nports; i++)
+		free_netdev(card->ports[i].dev);
 error_free_card:
         kfree ( card );
         return err;
@@ -1647,7 +1668,8 @@
 
         for ( i = 0 ; i < card->nports ; i++ )
         {
-                unregister_hdlc_device ( &card->ports[i].hdlc );
+		struct net_device *dev = port_to_dev(&card->ports[i]);
+                unregister_hdlc_device(dev);
         }
 
         fst_disable_intr ( card );
@@ -1660,6 +1682,9 @@
         release_mem_region ( card->phys_mem, FST_MEMSIZE );
         release_region ( card->pci_conf, 0x80 );
 
+	for (i = 0; i < card->nports; i++)
+		free_netdev(card->ports[i].dev);
+
         kfree ( card );
 }
 
--- diff/drivers/net/wan/hd6457x.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/hd6457x.c	2004-02-18 09:04:00.000000000 +0000
@@ -73,6 +73,11 @@
 #define writea(value, ptr)		writel(value, ptr)
 #endif
 
+static inline struct net_device *port_to_dev(port_t *port)
+{
+	return port->dev;
+}
+
 static inline int sca_intr_status(card_t *card)
 {
 	u8 result = 0;
@@ -110,22 +115,11 @@
 	return result;
 }
 
-
-
-static inline port_t* hdlc_to_port(hdlc_device *hdlc)
-{
-	return (port_t*)hdlc;
-}
-
-
-
 static inline port_t* dev_to_port(struct net_device *dev)
 {
-	return hdlc_to_port(dev_to_hdlc(dev));
+	return dev_to_hdlc(dev)->priv;
 }
 
-
-
 static inline u16 next_desc(port_t *port, u16 desc, int transmit)
 {
 	return (desc + 1) % (transmit ? port_to_card(port)->tx_ring_buffers
@@ -245,7 +239,7 @@
 	}
 
 	hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD),
-			 &port->hdlc);
+			 port_to_dev(port));
 }
 
 
@@ -262,13 +256,14 @@
 	sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card);
 
 	if (stat & ST1_UDRN) {
-		port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
-		port->hdlc.stats.tx_fifo_errors++;
+		struct net_device_stats *stats = hdlc_stats(port_to_dev(port));
+		stats->tx_errors++; /* TX Underrun error detected */
+		stats->tx_fifo_errors++;
 	}
 
 	if (stat & ST1_CDCD)
 		hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD),
-				 &port->hdlc);
+				 port_to_dev(port));
 }
 #endif
 
@@ -276,6 +271,8 @@
 
 static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin)
 {
+	struct net_device *dev = port_to_dev(port);
+	struct net_device_stats *stats = hdlc_stats(dev);
 	struct sk_buff *skb;
 	u16 len;
 	u32 buff;
@@ -287,7 +284,7 @@
 	len = readw(&desc->len);
 	skb = dev_alloc_skb(len);
 	if (!skb) {
-		port->hdlc.stats.rx_dropped++;
+		stats->rx_dropped++;
 		return;
 	}
 
@@ -313,15 +310,15 @@
 #endif
 	skb_put(skb, len);
 #ifdef DEBUG_PKT
-	printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
+	printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len);
 	debug_frame(skb);
 #endif
-	port->hdlc.stats.rx_packets++;
-	port->hdlc.stats.rx_bytes += skb->len;
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
 	skb->mac.raw = skb->data;
-	skb->dev = hdlc_to_dev(&port->hdlc);
+	skb->dev = dev;
 	skb->dev->last_rx = jiffies;
-	skb->protocol = hdlc_type_trans(skb, hdlc_to_dev(&port->hdlc));
+	skb->protocol = hdlc_type_trans(skb, dev);
 	netif_rx(skb);
 }
 
@@ -333,7 +330,7 @@
 	u16 dmac = get_dmac_rx(port);
 	card_t *card = port_to_card(port);
 	u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */
-	struct net_device_stats *stats = &port->hdlc.stats;
+	struct net_device_stats *stats = hdlc_stats(port_to_dev(port));
 
 	/* Reset DSR status bits */
 	sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
@@ -380,6 +377,8 @@
 /* Transmit DMA interrupt service */
 static inline void sca_tx_intr(port_t *port)
 {
+	struct net_device *dev = port_to_dev(port);
+	struct net_device_stats *stats = hdlc_stats(dev);
 	u16 dmac = get_dmac_tx(port);
 	card_t* card = port_to_card(port);
 	u8 stat;
@@ -401,13 +400,13 @@
 			break;	/* Transmitter is/will_be sending this frame */
 
 		desc = desc_address(port, port->txlast, 1);
-		port->hdlc.stats.tx_packets++;
-		port->hdlc.stats.tx_bytes += readw(&desc->len);
+		stats->tx_packets++;
+		stats->tx_bytes += readw(&desc->len);
 		writeb(0, &desc->stat);	/* Free descriptor */
 		port->txlast = next_desc(port, port->txlast, 1);
 	}
 
-	netif_wake_queue(hdlc_to_dev(&port->hdlc));
+	netif_wake_queue(dev);
 	spin_unlock(&port->lock);
 }
 
@@ -508,9 +507,9 @@
 
 
 
-static void sca_open(hdlc_device *hdlc)
+static void sca_open(struct net_device *dev)
 {
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	card_t* card = port_to_card(port);
 	u16 msci = get_msci(port);
 	u8 md0, md2;
@@ -569,7 +568,7 @@
    - all DMA interrupts
 */
 
-	hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc);
+	hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), dev);
 
 #ifdef __HD64570_H
 	/* MSCI TX INT and RX INT A IRQ enable */
@@ -600,18 +599,18 @@
 	sca_out(CMD_TX_ENABLE, msci + CMD, card);
 	sca_out(CMD_RX_ENABLE, msci + CMD, card);
 
-	netif_start_queue(hdlc_to_dev(hdlc));
+	netif_start_queue(dev);
 }
 
 
 
-static void sca_close(hdlc_device *hdlc)
+static void sca_close(struct net_device *dev)
 {
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	card_t* card = port_to_card(port);
 
 	/* reset channel */
-	netif_stop_queue(hdlc_to_dev(hdlc));
+	netif_stop_queue(dev);
 	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
 #ifdef __HD64570_H
 	/* disable MSCI interrupts */
@@ -629,7 +628,7 @@
 
 
 
-static int sca_attach(hdlc_device *hdlc, unsigned short encoding,
+static int sca_attach(struct net_device *dev, unsigned short encoding,
 		      unsigned short parity)
 {
 	if (encoding != ENCODING_NRZ &&
@@ -650,17 +649,17 @@
 	    parity != PARITY_CRC16_PR1_CCITT)
 		return -EINVAL;
 
-	hdlc_to_port(hdlc)->encoding = encoding;
-	hdlc_to_port(hdlc)->parity = parity;
+	dev_to_port(dev)->encoding = encoding;
+	dev_to_port(dev)->parity = parity;
 	return 0;
 }
 
 
 
 #ifdef DEBUG_RINGS
-static void sca_dump_rings(hdlc_device *hdlc)
+static void sca_dump_rings(struct net_device *dev)
 {
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	card_t *card = port_to_card(port);
 	u16 cnt;
 #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
@@ -729,8 +728,7 @@
 
 static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	card_t *card = port_to_card(port);
 	pkt_desc *desc;
 	u32 buff, len;
@@ -753,7 +751,7 @@
 	}
 
 #ifdef DEBUG_PKT
-	printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
+	printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
 	debug_frame(skb);
 #endif
 
@@ -790,7 +788,7 @@
 
 	desc = desc_address(port, port->txin + 1, 1);
 	if (readb(&desc->stat)) /* allow 1 packet gap */
-		netif_stop_queue(hdlc_to_dev(&port->hdlc));
+		netif_stop_queue(dev);
 
 	spin_unlock_irq(&port->lock);
 
--- diff/drivers/net/wan/hdlc_cisco.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/wan/hdlc_cisco.c	2004-02-18 09:04:00.000000000 +0000
@@ -57,7 +57,7 @@
 
 
 
-static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
+static void cisco_keepalive_send(struct net_device *dev, u32 type,
 				 u32 par1, u32 par2)
 {
 	struct sk_buff *skb;
@@ -67,12 +67,11 @@
 	if (!skb) {
 		printk(KERN_WARNING
 		       "%s: Memory squeeze on cisco_keepalive_send()\n",
-		       hdlc_to_name(hdlc));
+		       dev->name);
 		return;
 	}
 	skb_reserve(skb, 4);
-	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
-			  NULL, NULL, 0);
+	cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
 	data = (cisco_packet*)skb->tail;
 
 	data->type = htonl(type);
@@ -84,7 +83,7 @@
 
 	skb_put(skb, sizeof(cisco_packet));
 	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
+	skb->dev = dev;
 	skb->nh.raw = skb->data;
 
 	dev_queue_xmit(skb);
@@ -118,7 +117,8 @@
 
 static int cisco_rx(struct sk_buff *skb)
 {
-	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	struct net_device *dev = skb->dev;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	hdlc_header *data = (hdlc_header*)skb->data;
 	cisco_packet *cisco_data;
 	struct in_device *in_dev;
@@ -142,7 +142,7 @@
 		    skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
 			printk(KERN_INFO "%s: Invalid length of Cisco "
 			       "control packet (%d bytes)\n",
-			       hdlc_to_name(hdlc), skb->len);
+			       dev->name, skb->len);
 			goto rx_error;
 		}
 
@@ -150,7 +150,7 @@
 
 		switch(ntohl (cisco_data->type)) {
 		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
-			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
+			in_dev = dev->ip_ptr;
 			addr = 0;
 			mask = ~0; /* is the mask correct? */
 
@@ -158,7 +158,7 @@
 				struct in_ifaddr **ifap = &in_dev->ifa_list;
 
 				while (*ifap != NULL) {
-					if (strcmp(hdlc_to_name(hdlc),
+					if (strcmp(dev->name,
 						   (*ifap)->ifa_label) == 0) {
 						addr = (*ifap)->ifa_local;
 						mask = (*ifap)->ifa_mask;
@@ -167,7 +167,7 @@
 					ifap = &(*ifap)->ifa_next;
 				}
 
-				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
+				cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
 						     addr, mask);
 			}
 			dev_kfree_skb_any(skb);
@@ -175,7 +175,7 @@
 
 		case CISCO_ADDR_REPLY:
 			printk(KERN_INFO "%s: Unexpected Cisco IP address "
-			       "reply\n", hdlc_to_name(hdlc));
+			       "reply\n", dev->name);
 			goto rx_error;
 
 		case CISCO_KEEPALIVE_REQ:
@@ -190,7 +190,7 @@
 					days = hrs / 24; hrs -= days * 24;
 					printk(KERN_INFO "%s: Link up (peer "
 					       "uptime %ud%uh%um%us)\n",
-					       hdlc_to_name(hdlc), days, hrs,
+					       dev->name, days, hrs,
 					       min, sec);
 				}
 				hdlc->state.cisco.up = 1;
@@ -201,7 +201,7 @@
 		} /* switch(keepalive type) */
 	} /* switch(protocol) */
 
-	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
+	printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
 	       data->protocol);
 	dev_kfree_skb_any(skb);
 	return NET_RX_DROP;
@@ -216,17 +216,18 @@
 
 static void cisco_timer(unsigned long arg)
 {
-	hdlc_device *hdlc = (hdlc_device*)arg;
+	struct net_device *dev = (struct net_device *)arg;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 
 	if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >=
 	    hdlc->state.cisco.settings.timeout * HZ) {
 		hdlc->state.cisco.up = 0;
-		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
-		if (netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_off(&hdlc->netdev);
+		printk(KERN_INFO "%s: Link down\n", dev->name);
+		if (netif_carrier_ok(dev))
+			netif_carrier_off(dev);
 	}
 
-	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ,
+	cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
 			     ++hdlc->state.cisco.txseq,
 			     hdlc->state.cisco.rxseq);
 	hdlc->state.cisco.timer.expires = jiffies +
@@ -238,8 +239,9 @@
 
 
 
-static void cisco_start(hdlc_device *hdlc)
+static void cisco_start(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	hdlc->state.cisco.last_poll = 0;
 	hdlc->state.cisco.up = 0;
 	hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
@@ -247,27 +249,27 @@
 	init_timer(&hdlc->state.cisco.timer);
 	hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
 	hdlc->state.cisco.timer.function = cisco_timer;
-	hdlc->state.cisco.timer.data = (unsigned long)hdlc;
+	hdlc->state.cisco.timer.data = (unsigned long)dev;
 	add_timer(&hdlc->state.cisco.timer);
 }
 
 
 
-static void cisco_stop(hdlc_device *hdlc)
+static void cisco_stop(struct net_device *dev)
 {
-	del_timer_sync(&hdlc->state.cisco.timer);
-	if (netif_carrier_ok(&hdlc->netdev))
-		netif_carrier_off(&hdlc->netdev);
+	del_timer_sync(&dev_to_hdlc(dev)->state.cisco.timer);
+	if (netif_carrier_ok(dev))
+		netif_carrier_off(dev);
 }
 
 
 
-int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	cisco_proto *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
 	const size_t size = sizeof(cisco_proto);
 	cisco_proto new_settings;
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 
 	switch (ifr->ifr_settings.type) {
@@ -295,7 +297,7 @@
 		    new_settings.timeout < 2)
 			return -EINVAL;
 
-		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 
 		if (result)
 			return result;
--- diff/drivers/net/wan/hdlc_fr.c	2003-08-26 10:00:53.000000000 +0100
+++ source/drivers/net/wan/hdlc_fr.c	2004-02-18 09:04:00.000000000 +0000
@@ -146,8 +146,9 @@
 }
 
 
-static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci)
+static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
 
 	while (*pvc_p) {
@@ -164,7 +165,7 @@
 
 	memset(pvc, 0, sizeof(pvc_device));
 	pvc->dlci = dlci;
-	pvc->master = hdlc;
+	pvc->master = dev;
 	pvc->next = *pvc_p;	/* Put it in the chain */
 	*pvc_p = pvc;
 	return pvc;
@@ -311,15 +312,16 @@
 {
 	pvc_device *pvc = dev_to_pvc(dev);
 
-	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
+	if ((pvc->master->flags & IFF_UP) == 0)
 		return -EIO;  /* Master must be UP in order to activate PVC */
 
 	if (pvc->open_count++ == 0) {
-		if (pvc->master->state.fr.settings.lmi == LMI_NONE)
-			pvc->state.active = pvc->master->carrier;
+		hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+		if (hdlc->state.fr.settings.lmi == LMI_NONE)
+			pvc->state.active = hdlc->carrier;
 
 		pvc_carrier(pvc->state.active, pvc);
-		pvc->master->state.fr.dce_changed = 1;
+		hdlc->state.fr.dce_changed = 1;
 	}
 	return 0;
 }
@@ -331,11 +333,12 @@
 	pvc_device *pvc = dev_to_pvc(dev);
 
 	if (--pvc->open_count == 0) {
-		if (pvc->master->state.fr.settings.lmi == LMI_NONE)
+		hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+		if (hdlc->state.fr.settings.lmi == LMI_NONE)
 			pvc->state.active = 0;
 
-		if (pvc->master->state.fr.settings.dce) {
-			pvc->master->state.fr.dce_changed = 1;
+		if (hdlc->state.fr.settings.dce) {
+			hdlc->state.fr.dce_changed = 1;
 			pvc->state.active = 0;
 		}
 	}
@@ -362,7 +365,7 @@
 		}
 
 		info.dlci = pvc->dlci;
-		memcpy(info.master, hdlc_to_name(pvc->master), IFNAMSIZ);
+		memcpy(info.master, pvc->master->name, IFNAMSIZ);
 		if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
 				 &info, sizeof(info)))
 			return -EFAULT;
@@ -375,8 +378,7 @@
 
 static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
 {
-	return (struct net_device_stats *)
-		((char *)dev + sizeof(struct net_device));
+	return netdev_priv(dev);
 }
 
 
@@ -408,7 +410,7 @@
 			stats->tx_packets++;
 			if (pvc->state.fecn) /* TX Congestion counter */
 				stats->tx_compressed++;
-			skb->dev = hdlc_to_dev(pvc->master);
+			skb->dev = pvc->master;
 			dev_queue_xmit(skb);
 			return 0;
 		}
@@ -434,7 +436,7 @@
 static inline void fr_log_dlci_active(pvc_device *pvc)
 {
 	printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
-	       hdlc_to_name(pvc->master),
+	       pvc->master->name,
 	       pvc->dlci,
 	       pvc->main ? pvc->main->name : "",
 	       pvc->main && pvc->ether ? " " : "",
@@ -454,8 +456,9 @@
 
 
 
-static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
+static void fr_lmi_send(struct net_device *dev, int fullrep)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	struct sk_buff *skb;
 	pvc_device *pvc = hdlc->state.fr.first_pvc;
 	int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
@@ -468,7 +471,7 @@
 		len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
 		if (len > HDLC_MAX_MRU) {
 			printk(KERN_WARNING "%s: Too many PVCs while sending "
-			       "LMI full report\n", hdlc_to_name(hdlc));
+			       "LMI full report\n", dev->name);
 			return;
 		}
 	}
@@ -476,7 +479,7 @@
 	skb = dev_alloc_skb(len);
 	if (!skb) {
 		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
-		       hdlc_to_name(hdlc));
+		       dev->name);
 		return;
 	}
 	memset(skb->data, 0, len);
@@ -529,7 +532,7 @@
 
 	skb_put(skb, i);
 	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
+	skb->dev = dev;
 	skb->nh.raw = skb->data;
 
 	dev_queue_xmit(skb);
@@ -537,14 +540,15 @@
 
 
 
-static void fr_set_link_state(int reliable, hdlc_device *hdlc)
+static void fr_set_link_state(int reliable, struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	pvc_device *pvc = hdlc->state.fr.first_pvc;
 
 	hdlc->state.fr.reliable = reliable;
 	if (reliable) {
-		if (!netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_on(&hdlc->netdev);
+		if (!netif_carrier_ok(dev))
+			netif_carrier_on(dev);
 
 		hdlc->state.fr.n391cnt = 0; /* Request full status */
 		hdlc->state.fr.dce_changed = 1;
@@ -558,8 +562,8 @@
 			}
 		}
 	} else {
-		if (netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_off(&hdlc->netdev);
+		if (netif_carrier_ok(dev))
+			netif_carrier_off(dev);
 
 		while (pvc) {		/* Deactivate all PVCs */
 			pvc_carrier(0, pvc);
@@ -574,7 +578,8 @@
 
 static void fr_timer(unsigned long arg)
 {
-	hdlc_device *hdlc = (hdlc_device*)arg;
+	struct net_device *dev = (struct net_device *)arg;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int i, cnt = 0, reliable;
 	u32 list;
 
@@ -586,7 +591,7 @@
 		if (hdlc->state.fr.request) {
 			if (hdlc->state.fr.reliable)
 				printk(KERN_INFO "%s: No LMI status reply "
-				       "received\n", hdlc_to_name(hdlc));
+				       "received\n", dev->name);
 			hdlc->state.fr.last_errors |= 1;
 		}
 
@@ -598,9 +603,9 @@
 	}
 
 	if (hdlc->state.fr.reliable != reliable) {
-		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
+		printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
 		       reliable ? "" : "un");
-		fr_set_link_state(reliable, hdlc);
+		fr_set_link_state(reliable, dev);
 	}
 
 	if (hdlc->state.fr.settings.dce)
@@ -610,7 +615,7 @@
 		if (hdlc->state.fr.n391cnt)
 			hdlc->state.fr.n391cnt--;
 
-		fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0);
+		fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
 
 		hdlc->state.fr.request = 1;
 		hdlc->state.fr.timer.expires = jiffies +
@@ -624,8 +629,9 @@
 
 
 
-static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
+static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int stat_len;
 	pvc_device *pvc;
 	int reptype = -1, error, no_ram;
@@ -634,14 +640,14 @@
 
 	if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
 			? LMI_ANSI_LENGTH : LMI_LENGTH)) {
-		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
+		printk(KERN_INFO "%s: Short LMI frame\n", dev->name);
 		return 1;
 	}
 
 	if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
 			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
 		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
-		       hdlc_to_name(hdlc), skb->data[2],
+		       dev->name, skb->data[2],
 		       hdlc->state.fr.settings.dce ? "enquiry" : "reply");
 		return 1;
 	}
@@ -652,7 +658,7 @@
 	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 	     ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
 		printk(KERN_INFO "%s: Not a report type=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
+		       dev->name, skb->data[i]);
 		return 1;
 	}
 	i++;
@@ -665,7 +671,7 @@
 	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 	     ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
 		printk(KERN_INFO "%s: Unsupported status element=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
+		       dev->name, skb->data[i]);
 		return 1;
 	}
 	i++;
@@ -680,7 +686,7 @@
 	if (hdlc->state.fr.settings.dce) {
 		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
 			printk(KERN_INFO "%s: Unsupported report type=%x\n",
-			       hdlc_to_name(hdlc), reptype);
+			       dev->name, reptype);
 			return 1;
 		}
 	}
@@ -716,7 +722,7 @@
 			hdlc->state.fr.dce_changed = 0;
 		}
 
-		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
+		fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
 		return 0;
 	}
 
@@ -741,26 +747,26 @@
 		if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 				     ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
 			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
+			       dev->name, skb->data[i]);
 			return 1;
 		}
 		i++;
 
 		if (skb->data[i] != stat_len) {
 			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
+			       dev->name, skb->data[i]);
 			return 1;
 		}
 		i++;
 
 		dlci = status_to_dlci(skb->data + i, &active, &new);
 
-		pvc = add_pvc(hdlc, dlci);
+		pvc = add_pvc(dev, dlci);
 
 		if (!pvc && !no_ram) {
 			printk(KERN_WARNING
 			       "%s: Memory squeeze on fr_lmi_recv()\n",
-			       hdlc_to_name(hdlc));
+			       dev->name);
 			no_ram = 1;
 		}
 
@@ -802,7 +808,8 @@
 
 static int fr_rx(struct sk_buff *skb)
 {
-	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	struct net_device *ndev = skb->dev;
+	hdlc_device *hdlc = dev_to_hdlc(ndev);
 	fr_hdr *fh = (fr_hdr*)skb->data;
 	u8 *data = skb->data;
 	u16 dlci;
@@ -819,7 +826,7 @@
 			goto rx_error; /* LMI packet with no LMI? */
 
 		if (data[3] == LMI_PROTO) {
-			if (fr_lmi_recv(hdlc, skb))
+			if (fr_lmi_recv(ndev, skb))
 				goto rx_error;
 			else {
 				/* No request pending */
@@ -831,7 +838,7 @@
 		}
 
 		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
-		       hdlc_to_name(hdlc));
+		       ndev->name);
 		goto rx_error;
 	}
 
@@ -839,7 +846,7 @@
 	if (!pvc) {
 #ifdef DEBUG_PKT
 		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
-		       hdlc_to_name(hdlc), dlci);
+		       ndev->name, dlci);
 #endif
 		dev_kfree_skb_any(skb);
 		return NET_RX_DROP;
@@ -847,7 +854,7 @@
 
 	if (pvc->state.fecn != fh->fecn) {
 #ifdef DEBUG_ECN
-		printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc),
+		printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
 		       dlci, fh->fecn ? "N" : "FF");
 #endif
 		pvc->state.fecn ^= 1;
@@ -855,7 +862,7 @@
 
 	if (pvc->state.becn != fh->becn) {
 #ifdef DEBUG_ECN
-		printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc),
+		printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
 		       dlci, fh->becn ? "N" : "FF");
 #endif
 		pvc->state.becn ^= 1;
@@ -899,13 +906,13 @@
 
 		default:
 			printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
-			       "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
+			       "PID=%x\n", ndev->name, oui, pid);
 			dev_kfree_skb_any(skb);
 			return NET_RX_DROP;
 		}
 	} else {
 		printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
-		       "length = %i\n", hdlc_to_name(hdlc), data[3], skb->len);
+		       "length = %i\n", ndev->name, data[3], skb->len);
 		dev_kfree_skb_any(skb);
 		return NET_RX_DROP;
 	}
@@ -932,14 +939,15 @@
 
 
 
-static void fr_start(hdlc_device *hdlc)
+static void fr_start(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 #ifdef DEBUG_LINK
 	printk(KERN_DEBUG "fr_start\n");
 #endif
 	if (hdlc->state.fr.settings.lmi != LMI_NONE) {
-		if (netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_off(&hdlc->netdev);
+		if (netif_carrier_ok(dev))
+			netif_carrier_off(dev);
 		hdlc->state.fr.last_poll = 0;
 		hdlc->state.fr.reliable = 0;
 		hdlc->state.fr.dce_changed = 1;
@@ -953,28 +961,30 @@
 		/* First poll after 1 s */
 		hdlc->state.fr.timer.expires = jiffies + HZ;
 		hdlc->state.fr.timer.function = fr_timer;
-		hdlc->state.fr.timer.data = (unsigned long)hdlc;
+		hdlc->state.fr.timer.data = (unsigned long)dev;
 		add_timer(&hdlc->state.fr.timer);
 	} else
-		fr_set_link_state(1, hdlc);
+		fr_set_link_state(1, dev);
 }
 
 
 
-static void fr_stop(hdlc_device *hdlc)
+static void fr_stop(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 #ifdef DEBUG_LINK
 	printk(KERN_DEBUG "fr_stop\n");
 #endif
 	if (hdlc->state.fr.settings.lmi != LMI_NONE)
 		del_timer_sync(&hdlc->state.fr.timer);
-	fr_set_link_state(0, hdlc);
+	fr_set_link_state(0, dev);
 }
 
 
 
-static void fr_close(hdlc_device *hdlc)
+static void fr_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	pvc_device *pvc = hdlc->state.fr.first_pvc;
 
 	while (pvc) {		/* Shutdown all PVCs for this FRAD */
@@ -986,10 +996,17 @@
 	}
 }
 
+static void dlci_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_DLCI;
+	dev->flags = IFF_POINTOPOINT;
+	dev->hard_header_len = 10;
+	dev->addr_len = 2;
+}
 
-
-static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
+static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
 {
+	hdlc_device *hdlc = dev_to_hdlc(master);
 	pvc_device *pvc = NULL;
 	struct net_device *dev;
 	int result, used;
@@ -998,9 +1015,9 @@
 	if (type == ARPHRD_ETHER)
 		prefix = "pvceth%d";
 
-	if ((pvc = add_pvc(hdlc, dlci)) == NULL) {
+	if ((pvc = add_pvc(master, dlci)) == NULL) {
 		printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
-		       hdlc_to_name(hdlc));
+		       master->name);
 		return -ENOBUFS;
 	}
 
@@ -1009,26 +1026,24 @@
 
 	used = pvc_is_used(pvc);
 
-	dev = kmalloc(sizeof(struct net_device) +
-		      sizeof(struct net_device_stats), GFP_KERNEL);
+	if (type == ARPHRD_ETHER)
+		dev = alloc_netdev(sizeof(struct net_device_stats),
+				   "pvceth%d", ether_setup);
+	else
+		dev = alloc_netdev(sizeof(struct net_device_stats),
+				   "pvc%d", dlci_setup);
+
 	if (!dev) {
 		printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
-		       hdlc_to_name(hdlc));
+		       master->name);
 		delete_unused_pvcs(hdlc);
 		return -ENOBUFS;
 	}
-	memset(dev, 0, sizeof(struct net_device) +
-	       sizeof(struct net_device_stats));
 
 	if (type == ARPHRD_ETHER) {
-		ether_setup(dev);
 		memcpy(dev->dev_addr, "\x00\x01", 2);
                 get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
 	} else {
-		dev->type = ARPHRD_DLCI;
-		dev->flags = IFF_POINTOPOINT;
-		dev->hard_header_len = 10;
-		dev->addr_len = 2;
 		*(u16*)dev->dev_addr = htons(dlci);
 		dlci_to_q922(dev->broadcast, dlci);
 	}
@@ -1042,15 +1057,15 @@
 	dev->tx_queue_len = 0;
 	dev->priv = pvc;
 
-	result = dev_alloc_name(dev, prefix);
+	result = dev_alloc_name(dev, dev->name);
 	if (result < 0) {
-		kfree(dev);
+		free_netdev(dev);
 		delete_unused_pvcs(hdlc);
 		return result;
 	}
 
 	if (register_netdevice(dev) != 0) {
-		kfree(dev);
+		free_netdev(dev);
 		delete_unused_pvcs(hdlc);
 		return -EIO;
 	}
@@ -1080,7 +1095,7 @@
 	if (dev->flags & IFF_UP)
 		return -EBUSY;		/* PVC in use */
 
-	unregister_netdevice(dev); /* the destructor will kfree(dev) */
+	unregister_netdevice(dev); /* the destructor will free_netdev(dev) */
 	*get_dev_p(pvc, type) = NULL;
 
 	if (!pvc_is_used(pvc)) {
@@ -1104,7 +1119,8 @@
 
 	while (pvc) {
 		pvc_device *next = pvc->next;
-		if (pvc->main)	/* the destructor will kfree(main + ether) */
+		/* destructors will free_netdev() main and ether */
+		if (pvc->main)
 			unregister_netdevice(pvc->main);
 
 		if (pvc->ether)
@@ -1117,12 +1133,12 @@
 
 
 
-int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	fr_proto *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
 	const size_t size = sizeof(fr_proto);
 	fr_proto new_settings;
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	fr_proto_pvc pvc;
 	int result;
 
@@ -1163,7 +1179,7 @@
 		     new_settings.dce != 1))
 			return -EINVAL;
 
-		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 		if (result)
 			return result;
 
@@ -1210,7 +1226,7 @@
 
 		if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC ||
 		    ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC)
-			return fr_add_pvc(hdlc, pvc.dlci, result);
+			return fr_add_pvc(dev, pvc.dlci, result);
 		else
 			return fr_del_pvc(hdlc, pvc.dlci, result);
 	}
--- diff/drivers/net/wan/hdlc_generic.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/hdlc_generic.c	2004-02-18 09:04:00.000000000 +0000
@@ -50,7 +50,7 @@
 
 static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
 {
-	return &dev_to_hdlc(dev)->stats;
+	return hdlc_stats(dev);
 }
 
 
@@ -69,8 +69,9 @@
 
 
 
-void hdlc_set_carrier(int on, hdlc_device *hdlc)
+void hdlc_set_carrier(int on, struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	on = on ? 1 : 0;
 
 #ifdef DEBUG_LINK
@@ -82,7 +83,7 @@
 	if (hdlc->carrier == on)
 		goto carrier_exit; /* no change in DCD line level */
 
-	printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc),
+	printk(KERN_INFO "%s: carrier %s\n", dev->name,
 	       on ? "ON" : "off");
 	hdlc->carrier = on;
 
@@ -91,15 +92,15 @@
 
 	if (hdlc->carrier) {
 		if (hdlc->proto.start)
-			hdlc->proto.start(hdlc);
-		else if (!netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_on(&hdlc->netdev);
+			hdlc->proto.start(dev);
+		else if (!netif_carrier_ok(dev))
+			netif_carrier_on(dev);
 
 	} else { /* no carrier */
 		if (hdlc->proto.stop)
-			hdlc->proto.stop(hdlc);
-		else if (netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_off(&hdlc->netdev);
+			hdlc->proto.stop(dev);
+		else if (netif_carrier_ok(dev))
+			netif_carrier_off(dev);
 	}
 
  carrier_exit:
@@ -108,8 +109,9 @@
 
 
 /* Must be called by hardware driver when HDLC device is being opened */
-int hdlc_open(hdlc_device *hdlc)
+int hdlc_open(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 #ifdef DEBUG_LINK
 	printk(KERN_DEBUG "hdlc_open carrier %i open %i\n",
 	       hdlc->carrier, hdlc->open);
@@ -119,7 +121,7 @@
 		return -ENOSYS;	/* no protocol attached */
 
 	if (hdlc->proto.open) {
-		int result = hdlc->proto.open(hdlc);
+		int result = hdlc->proto.open(dev);
 		if (result)
 			return result;
 	}
@@ -128,12 +130,12 @@
 
 	if (hdlc->carrier) {
 		if (hdlc->proto.start)
-			hdlc->proto.start(hdlc);
-		else if (!netif_carrier_ok(&hdlc->netdev))
-			netif_carrier_on(&hdlc->netdev);
+			hdlc->proto.start(dev);
+		else if (!netif_carrier_ok(dev))
+			netif_carrier_on(dev);
 
-	} else if (netif_carrier_ok(&hdlc->netdev))
-		netif_carrier_off(&hdlc->netdev);
+	} else if (netif_carrier_ok(dev))
+		netif_carrier_off(dev);
 
 	hdlc->open = 1;
 
@@ -144,8 +146,9 @@
 
 
 /* Must be called by hardware driver when HDLC device is being closed */
-void hdlc_close(hdlc_device *hdlc)
+void hdlc_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 #ifdef DEBUG_LINK
 	printk(KERN_DEBUG "hdlc_close carrier %i open %i\n",
 	       hdlc->carrier, hdlc->open);
@@ -155,38 +158,38 @@
 
 	hdlc->open = 0;
 	if (hdlc->carrier && hdlc->proto.stop)
-		hdlc->proto.stop(hdlc);
+		hdlc->proto.stop(dev);
 
 	spin_unlock_irq(&hdlc->state_lock);
 
 	if (hdlc->proto.close)
-		hdlc->proto.close(hdlc);
+		hdlc->proto.close(dev);
 }
 
 
 
 #ifndef CONFIG_HDLC_RAW
-#define hdlc_raw_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_raw_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 #ifndef CONFIG_HDLC_RAW_ETH
-#define hdlc_raw_eth_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_raw_eth_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 #ifndef CONFIG_HDLC_PPP
-#define hdlc_ppp_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_ppp_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 #ifndef CONFIG_HDLC_CISCO
-#define hdlc_cisco_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_cisco_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 #ifndef CONFIG_HDLC_FR
-#define hdlc_fr_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_fr_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 #ifndef CONFIG_HDLC_X25
-#define hdlc_x25_ioctl(hdlc, ifr)	-ENOSYS
+#define hdlc_x25_ioctl(dev, ifr)	-ENOSYS
 #endif
 
 
@@ -213,22 +216,49 @@
 	}
 
 	switch(proto) {
-	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(hdlc, ifr);
-	case IF_PROTO_HDLC_ETH:	return hdlc_raw_eth_ioctl(hdlc, ifr);
-	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(hdlc, ifr);
-	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(hdlc, ifr);
-	case IF_PROTO_FR:	return hdlc_fr_ioctl(hdlc, ifr);
-	case IF_PROTO_X25:	return hdlc_x25_ioctl(hdlc, ifr);
+	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(dev, ifr);
+	case IF_PROTO_HDLC_ETH:	return hdlc_raw_eth_ioctl(dev, ifr);
+	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(dev, ifr);
+	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(dev, ifr);
+	case IF_PROTO_FR:	return hdlc_fr_ioctl(dev, ifr);
+	case IF_PROTO_X25:	return hdlc_x25_ioctl(dev, ifr);
 	default:		return -EINVAL;
 	}
 }
 
+static void hdlc_setup(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+	dev->get_stats = hdlc_get_stats;
+	dev->change_mtu = hdlc_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+
+	dev->type = ARPHRD_RAWHDLC;
+	dev->hard_header_len = 16;
+
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+	hdlc->proto.id = -1;
+	hdlc->proto.detach = NULL;
+	hdlc->carrier = 1;
+	hdlc->open = 0;
+	spin_lock_init(&hdlc->state_lock);
+}
 
+struct net_device *alloc_hdlcdev(void *priv)
+{
+	struct net_device *dev;
+	dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+	if (dev)
+		dev_to_hdlc(dev)->priv = priv;
+	return dev;
+}
 
-int register_hdlc_device(hdlc_device *hdlc)
+int register_hdlc_device(struct net_device *dev)
 {
 	int result;
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 
 	dev->get_stats = hdlc_get_stats;
 	dev->change_mtu = hdlc_change_mtu;
@@ -258,11 +288,11 @@
 
 
 
-void unregister_hdlc_device(hdlc_device *hdlc)
+void unregister_hdlc_device(struct net_device *dev)
 {
 	rtnl_lock();
-	hdlc_proto_detach(hdlc);
-	unregister_netdevice(hdlc_to_dev(hdlc));
+	hdlc_proto_detach(dev_to_hdlc(dev));
+	unregister_netdevice(dev);
 	rtnl_unlock();
 }
 
@@ -276,6 +306,7 @@
 EXPORT_SYMBOL(hdlc_close);
 EXPORT_SYMBOL(hdlc_set_carrier);
 EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(alloc_hdlcdev);
 EXPORT_SYMBOL(register_hdlc_device);
 EXPORT_SYMBOL(unregister_hdlc_device);
 
--- diff/drivers/net/wan/hdlc_ppp.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/hdlc_ppp.c	2004-02-18 09:04:00.000000000 +0000
@@ -24,9 +24,9 @@
 #include <linux/hdlc.h>
 
 
-static int ppp_open(hdlc_device *hdlc)
+static int ppp_open(struct net_device *dev)
 {
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	void *old_ioctl;
 	int result;
 
@@ -52,9 +52,9 @@
 
 
 
-static void ppp_close(hdlc_device *hdlc)
+static void ppp_close(struct net_device *dev)
 {
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 
 	sppp_close(dev);
 	sppp_detach(dev);
@@ -74,9 +74,9 @@
 
 
 
-int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 
 	switch (ifr->ifr_settings.type) {
@@ -93,7 +93,7 @@
 
 		/* no settable parameters */
 
-		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 		if (result)
 			return result;
 
--- diff/drivers/net/wan/hdlc_raw.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/hdlc_raw.c	2004-02-18 09:04:00.000000000 +0000
@@ -32,12 +32,12 @@
 
 
 
-int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
 	const size_t size = sizeof(raw_hdlc_proto);
 	raw_hdlc_proto new_settings;
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 
 	switch (ifr->ifr_settings.type) {
@@ -67,7 +67,7 @@
 		if (new_settings.parity == PARITY_DEFAULT)
 			new_settings.parity = PARITY_CRC16_PR1_CCITT;
 
-		result = hdlc->attach(hdlc, new_settings.encoding,
+		result = hdlc->attach(dev, new_settings.encoding,
 				      new_settings.parity);
 		if (result)
 			return result;
--- diff/drivers/net/wan/hdlc_raw_eth.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/hdlc_raw_eth.c	2004-02-18 09:04:00.000000000 +0000
@@ -33,7 +33,7 @@
 		int len = skb->len;
 		if (skb_tailroom(skb) < pad)
 			if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) {
-				dev_to_hdlc(dev)->stats.tx_dropped++;
+				hdlc_stats(dev)->tx_dropped++;
 				dev_kfree_skb(skb);
 				return 0;
 			}
@@ -44,12 +44,12 @@
 }
 
 
-int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
 	const size_t size = sizeof(raw_hdlc_proto);
 	raw_hdlc_proto new_settings;
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 	void *old_ch_mtu;
 	int old_qlen;
@@ -81,7 +81,7 @@
 		if (new_settings.parity == PARITY_DEFAULT)
 			new_settings.parity = PARITY_CRC16_PR1_CCITT;
 
-		result = hdlc->attach(hdlc, new_settings.encoding,
+		result = hdlc->attach(dev, new_settings.encoding,
 				      new_settings.parity);
 		if (result)
 			return result;
--- diff/drivers/net/wan/hdlc_x25.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/hdlc_x25.c	2004-02-18 09:04:00.000000000 +0000
@@ -25,21 +25,20 @@
 
 /* These functions are callbacks called by LAPB layer */
 
-static void x25_connect_disconnect(void *token, int reason, int code)
+static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
 {
-	hdlc_device *hdlc = token;
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
 	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
+		printk(KERN_ERR "%s: out of memory\n", dev->name);
 		return;
 	}
 
 	ptr = skb_put(skb, 1);
 	*ptr = code;
 
-	skb->dev = hdlc_to_dev(hdlc);
+	skb->dev = dev;
 	skb->protocol = htons(ETH_P_X25);
 	skb->mac.raw = skb->data;
 	skb->pkt_type = PACKET_HOST;
@@ -49,23 +48,22 @@
 
 
 
-static void x25_connected(void *token, int reason)
+static void x25_connected(struct net_device *dev, int reason)
 {
-	x25_connect_disconnect(token, reason, 1);
+	x25_connect_disconnect(dev, reason, 1);
 }
 
 
 
-static void x25_disconnected(void *token, int reason)
+static void x25_disconnected(struct net_device *dev, int reason)
 {
-	x25_connect_disconnect(token, reason, 2);
+	x25_connect_disconnect(dev, reason, 2);
 }
 
 
 
-static int x25_data_indication(void *token, struct sk_buff *skb)
+static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
-	hdlc_device *hdlc = token;
 	unsigned char *ptr;
 
 	skb_push(skb, 1);
@@ -76,7 +74,7 @@
 	ptr  = skb->data;
 	*ptr = 0;
 
-	skb->dev = hdlc_to_dev(hdlc);
+	skb->dev = dev;
 	skb->protocol = htons(ETH_P_X25);
 	skb->mac.raw = skb->data;
 	skb->pkt_type = PACKET_HOST;
@@ -86,17 +84,16 @@
 
 
 
-static void x25_data_transmit(void *token, struct sk_buff *skb)
+static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
-	hdlc_device *hdlc = token;
-	hdlc->xmit(skb, hdlc_to_dev(hdlc)); /* Ignore return value :-( */
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	hdlc->xmit(skb, dev); /* Ignore return value :-( */
 }
 
 
 
 static int x25_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 
 
@@ -104,31 +101,31 @@
 	switch (skb->data[0]) {
 	case 0:		/* Data to be transmitted */
 		skb_pull(skb, 1);
-		if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
+		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
 			dev_kfree_skb(skb);
 		return 0;
 
 	case 1:
-		if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
+		if ((result = lapb_connect_request(dev))!= LAPB_OK) {
 			if (result == LAPB_CONNECTED)
 				/* Send connect confirm. msg to level 3 */
-				x25_connected(hdlc, 0);
+				x25_connected(dev, 0);
 			else
 				printk(KERN_ERR "%s: LAPB connect request "
 				       "failed, error code = %i\n",
-				       hdlc_to_name(hdlc), result);
+				       dev->name, result);
 		}
 		break;
 
 	case 2:
-		if ((result = lapb_disconnect_request(hdlc)) != LAPB_OK) {
+		if ((result = lapb_disconnect_request(dev)) != LAPB_OK) {
 			if (result == LAPB_NOTCONNECTED)
 				/* Send disconnect confirm. msg to level 3 */
-				x25_disconnected(hdlc, 0);
+				x25_disconnected(dev, 0);
 			else
 				printk(KERN_ERR "%s: LAPB disconnect request "
 				       "failed, error code = %i\n",
-				       hdlc_to_name(hdlc), result);
+				       dev->name, result);
 		}
 		break;
 
@@ -142,7 +139,7 @@
 
 
 
-static int x25_open(hdlc_device *hdlc)
+static int x25_open(struct net_device *dev)
 {
 	struct lapb_register_struct cb;
 	int result;
@@ -154,7 +151,7 @@
 	cb.data_indication = x25_data_indication;
 	cb.data_transmit = x25_data_transmit;
 
-	result = lapb_register(hdlc, &cb);
+	result = lapb_register(dev, &cb);
 	if (result != LAPB_OK)
 		return result;
 	return 0;
@@ -162,9 +159,9 @@
 
 
 
-static void x25_close(hdlc_device *hdlc)
+static void x25_close(struct net_device *dev)
 {
-	lapb_unregister(hdlc);
+	lapb_unregister(dev);
 }
 
 
@@ -178,7 +175,7 @@
 		return NET_RX_DROP;
 	}
 
-	if (lapb_data_received(hdlc, skb) == LAPB_OK)
+	if (lapb_data_received(skb->dev, skb) == LAPB_OK)
 		return NET_RX_SUCCESS;
 
 	hdlc->stats.rx_errors++;
@@ -188,9 +185,9 @@
 
 
 
-int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
-	struct net_device *dev = hdlc_to_dev(hdlc);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
 
 	switch (ifr->ifr_settings.type) {
@@ -205,7 +202,7 @@
 		if(dev->flags & IFF_UP)
 			return -EBUSY;
 
-		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 		if (result)
 			return result;
 
--- diff/drivers/net/wan/hostess_sv11.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/wan/hostess_sv11.c	2004-02-18 09:04:00.000000000 +0000
@@ -122,7 +122,6 @@
 	 */
 
 	netif_start_queue(d);
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -154,7 +153,6 @@
 			z8530_sync_txdma_close(d, &sv11->sync.chanA);
 			break;
 	}
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -203,6 +201,16 @@
 	return 0;
 }
 
+static void sv11_setup(struct net_device *dev)
+{	
+	dev->open = hostess_open;
+	dev->stop = hostess_close;
+	dev->hard_start_xmit = hostess_queue_xmit;
+	dev->get_stats = hostess_get_stats;
+	dev->do_ioctl = hostess_ioctl;
+	dev->neigh_setup = hostess_neigh_setup_dev;
+}
+
 /*
  *	Description block for a Comtrol Hostess SV11 card
  */
@@ -229,10 +237,12 @@
 	memset(sv, 0, sizeof(*sv));
 	sv->if_ptr=&sv->netdev;
 	
-	sv->netdev.dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup);
 	if(!sv->netdev.dev)
 		goto fail2;
 
+	SET_MODULE_OWNER(sv->netdev.dev);
+
 	dev=&sv->sync;
 	
 	/*
@@ -326,23 +336,14 @@
 		d->base_addr = iobase;
 		d->irq = irq;
 		d->priv = sv;
-		d->init = NULL;
-		
-		d->open = hostess_open;
-		d->stop = hostess_close;
-		d->hard_start_xmit = hostess_queue_xmit;
-		d->get_stats = hostess_get_stats;
-		d->set_multicast_list = NULL;
-		d->do_ioctl = hostess_ioctl;
-		d->neigh_setup = hostess_neigh_setup_dev;
-		d->set_mac_address = NULL;
 		
 		if(register_netdev(d))
 		{
 			printk(KERN_ERR "%s: unable to register device.\n",
 				d->name);
-			goto fail;
-		}				
+			sppp_detach(d);
+			goto dmafail2;
+		}
 
 		z8530_describe(dev, "I/O", iobase);
 		dev->active=1;
@@ -357,7 +358,7 @@
 fail:
 	free_irq(irq, dev);
 fail1:
-	kfree(sv->netdev.dev);
+	free_netdev(sv->netdev.dev);
 fail2:
 	kfree(sv);
 fail3:
@@ -368,8 +369,8 @@
 static void sv11_shutdown(struct sv11_device *dev)
 {
 	sppp_detach(dev->netdev.dev);
-	z8530_shutdown(&dev->sync);
 	unregister_netdev(dev->netdev.dev);
+	z8530_shutdown(&dev->sync);
 	free_irq(dev->sync.irq, dev);
 	if(dma)
 	{
@@ -378,6 +379,8 @@
 		free_dma(dev->sync.chanA.txdma);
 	}
 	release_region(dev->sync.chanA.ctrlio-1, 8);
+	free_netdev(dev->netdev.dev);
+	kfree(dev);
 }
 
 #ifdef MODULE
--- diff/drivers/net/wan/lapbether.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/net/wan/lapbether.c	2004-02-18 09:04:00.000000000 +0000
@@ -110,7 +110,7 @@
 	skb_pull(skb, 2);	/* Remove the length bytes */
 	skb_trim(skb, len);	/* Set the length of the data */
 
-	if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
+	if ((err = lapb_data_received(lapbeth->axdev, skb)) != LAPB_OK) {
 		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
 		goto drop_unlock;
 	}
@@ -125,9 +125,8 @@
 	return 0;
 }
 
-static int lapbeth_data_indication(void *token, struct sk_buff *skb)
+static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
 
 	skb_push(skb, 1);
@@ -138,7 +137,7 @@
 	ptr  = skb->data;
 	*ptr = 0x00;
 
-	skb->dev      = lapbeth->axdev;
+	skb->dev      = dev;
 	skb->protocol = htons(ETH_P_X25);
 	skb->mac.raw  = skb->data;
 	skb->pkt_type = PACKET_HOST;
@@ -152,7 +151,6 @@
  */
 static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
 	int err = -ENODEV;
 
 	/*
@@ -168,12 +166,12 @@
 		err = 0;
 		break;
 	case 0x01:
-		if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
+		if ((err = lapb_connect_request(dev)) != LAPB_OK)
 			printk(KERN_ERR "lapbeth: lapb_connect_request "
 			       "error: %d\n", err);
 		goto drop_ok;
 	case 0x02:
-		if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
+		if ((err = lapb_disconnect_request(dev)) != LAPB_OK)
 			printk(KERN_ERR "lapbeth: lapb_disconnect_request "
 			       "err: %d\n", err);
 		/* Fall thru */
@@ -183,7 +181,7 @@
 
 	skb_pull(skb, 1);
 
-	if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
+	if ((err = lapb_data_request(dev, skb)) != LAPB_OK) {
 		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
 		err = -ENOMEM;
 		goto drop;
@@ -198,9 +196,9 @@
 	goto out;
 }
 
-static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
+static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
+	struct lapbethdev *lapbeth = ndev->priv;
 	unsigned char *ptr;
 	struct net_device *dev;
 	int size = skb->len;
@@ -222,9 +220,8 @@
 	dev_queue_xmit(skb);
 }
 
-static void lapbeth_connected(void *token, int reason)
+static void lapbeth_connected(struct net_device *dev, int reason)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
 	struct sk_buff *skb = dev_alloc_skb(1);
 
@@ -236,7 +233,7 @@
 	ptr  = skb_put(skb, 1);
 	*ptr = 0x01;
 
-	skb->dev      = lapbeth->axdev;
+	skb->dev      = dev;
 	skb->protocol = htons(ETH_P_X25);
 	skb->mac.raw  = skb->data;
 	skb->pkt_type = PACKET_HOST;
@@ -245,9 +242,8 @@
 	netif_rx(skb);
 }
 
-static void lapbeth_disconnected(void *token, int reason)
+static void lapbeth_disconnected(struct net_device *dev, int reason)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
 	struct sk_buff *skb = dev_alloc_skb(1);
 
@@ -259,7 +255,7 @@
 	ptr  = skb_put(skb, 1);
 	*ptr = 0x02;
 
-	skb->dev      = lapbeth->axdev;
+	skb->dev      = dev;
 	skb->protocol = htons(ETH_P_X25);
 	skb->mac.raw  = skb->data;
 	skb->pkt_type = PACKET_HOST;
@@ -303,11 +299,9 @@
  */
 static int lapbeth_open(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth;
 	int err;
 
-	lapbeth = (struct lapbethdev *)dev->priv;
-	if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) {
+	if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) {
 		printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err);
 		return -ENODEV;
 	}
@@ -318,12 +312,11 @@
 
 static int lapbeth_close(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
 	int err;
 
 	netif_stop_queue(dev);
 
-	if ((err = lapb_unregister(lapbeth)) != LAPB_OK)
+	if ((err = lapb_unregister(dev)) != LAPB_OK)
 		printk(KERN_ERR "lapbeth: lapb_unregister error - %d\n", err);
 
 	return 0;
@@ -382,6 +375,7 @@
 	return rc;
 fail:
 	dev_put(dev);
+	free_netdev(ndev);
 	kfree(lapbeth);
 	goto out;
 }
--- diff/drivers/net/wan/n2.c	2003-08-20 14:16:10.000000000 +0100
+++ source/drivers/net/wan/n2.c	2004-02-18 09:04:00.000000000 +0000
@@ -92,7 +92,7 @@
 
 
 typedef struct port_s {
-	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	struct net_device *dev;
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
 	sync_serial_settings settings;
@@ -215,13 +215,12 @@
 
 static int n2_open(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	int io = port->card->io;
 	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0);
 	int result;
 
-	result = hdlc_open(hdlc);
+	result = hdlc_open(dev);
 	if (result)
 		return result;
 
@@ -230,7 +229,7 @@
 
 	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
 	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
-	sca_open(hdlc);
+	sca_open(dev);
 	n2_set_iface(port);
 	return 0;
 }
@@ -239,15 +238,14 @@
 
 static int n2_close(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	int io = port->card->io;
 	u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
 
-	sca_close(hdlc);
+	sca_close(dev);
 	mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
 	outb(mcr, io + N2_MCR);
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 	return 0;
 }
 
@@ -257,12 +255,11 @@
 {
 	const size_t size = sizeof(sync_serial_settings);
 	sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
 #ifdef DEBUG_RINGS
 	if (cmd == SIOCDEVPRIVATE) {
-		sca_dump_rings(hdlc);
+		sca_dump_rings(dev);
 		return 0;
 	}
 #endif
@@ -312,8 +309,10 @@
 	int cnt;
 
 	for (cnt = 0; cnt < 2; cnt++)
-		if (card->ports[cnt].card)
-			unregister_hdlc_device(&card->ports[cnt].hdlc);
+		if (card->ports[cnt].card) {
+			struct net_device *dev = port_to_dev(&card->ports[cnt]);
+			unregister_hdlc_device(dev);
+		}
 
 	if (card->irq)
 		free_irq(card->irq, card);
@@ -325,6 +324,10 @@
 
 	if (card->io)
 		release_region(card->io, N2_IOPORTS);
+	if (card->ports[0].dev)
+		free_netdev(card->ports[0].dev);
+	if (card->ports[1].dev)
+		free_netdev(card->ports[1].dev);
 	kfree(card);
 }
 
@@ -359,6 +362,14 @@
 	}
 	memset(card, 0, sizeof(card_t));
 
+	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
+	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
+	if (!card->ports[0].dev || !card->ports[1].dev) {
+		printk(KERN_ERR "n2: unable to allocate memory\n");
+		n2_destroy_card(card);
+		return -ENOMEM;
+	}
+
 	if (!request_region(io, N2_IOPORTS, devname)) {
 		printk(KERN_ERR "n2: I/O port region in use\n");
 		n2_destroy_card(card);
@@ -435,7 +446,8 @@
 	sca_init(card, 0);
 	for (cnt = 0; cnt < 2; cnt++) {
 		port_t *port = &card->ports[cnt];
-		struct net_device *dev = hdlc_to_dev(&port->hdlc);
+		struct net_device *dev = port_to_dev(port);
+		hdlc_device *hdlc = dev_to_hdlc(dev);
 
 		if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
 			continue;
@@ -455,21 +467,22 @@
 		dev->do_ioctl = n2_ioctl;
 		dev->open = n2_open;
 		dev->stop = n2_close;
-		port->hdlc.attach = sca_attach;
-		port->hdlc.xmit = sca_xmit;
+		hdlc->attach = sca_attach;
+		hdlc->xmit = sca_xmit;
 		port->settings.clock_type = CLOCK_EXT;
+		port->card = card;
 
-		if (register_hdlc_device(&port->hdlc)) {
+		if (register_hdlc_device(dev)) {
 			printk(KERN_WARNING "n2: unable to register hdlc "
 			       "device\n");
+			port->card = NULL;
 			n2_destroy_card(card);
 			return -ENOBUFS;
 		}
-		port->card = card;
 		sca_init_sync_port(port); /* Set up SCA memory */
 
 		printk(KERN_INFO "%s: RISCom/N2 node %d\n",
-		       hdlc_to_name(&port->hdlc), port->phy_node);
+		       dev->name, port->phy_node);
 	}
 
 	*new_card = card;
--- diff/drivers/net/wan/pc300.h	2002-10-16 04:27:49.000000000 +0100
+++ source/drivers/net/wan/pc300.h	2004-02-18 09:04:00.000000000 +0000
@@ -331,7 +331,7 @@
 	uclong line_off;
 #ifdef __KERNEL__
 	char name[16];
-	hdlc_device *hdlc;
+	struct net_device *dev;
 
 	void *private;
 	struct sk_buff *tx_skb;
@@ -483,7 +483,7 @@
 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_net_rx(struct net_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);
--- diff/drivers/net/wan/pc300_drv.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/net/wan/pc300_drv.c	2004-02-18 09:04:00.000000000 +0000
@@ -290,7 +290,7 @@
 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);
+static int cpc_attach(struct net_device *, unsigned short, unsigned short);
 
 #ifdef CONFIG_PC300_MLPPP
 void cpc_tty_init(pc300dev_t * dev);
@@ -1774,7 +1774,7 @@
 	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;
+	struct net_device_stats *stats = hdlc_stats(dev);
 	int ch = chan->channel;
 	uclong flags;
 	ucchar ilar;
@@ -1802,7 +1802,7 @@
 	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;
+	struct net_device_stats *stats = hdlc_stats(dev);
 	int ch = chan->channel;
 	uclong flags;
 #ifdef PC300_DEBUG_TX
@@ -1880,13 +1880,12 @@
 	return 0;
 }
 
-void cpc_net_rx(hdlc_device * hdlc)
+void cpc_net_rx(struct net_device *dev)
 {
-	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;
+	struct net_device_stats *stats = hdlc_stats(dev);
 	int ch = chan->channel;
 #ifdef PC300_DEBUG_RX
 	int i;
@@ -1975,7 +1974,7 @@
 	pc300_t *card = (pc300_t *)chan->card; 
 	int ch = chan->channel; 
 	volatile pcsca_bd_t * ptdescr; 
-	struct net_device_stats *stats = &dev->hdlc->stats; 
+	struct net_device_stats *stats = hdlc_stats(dev->dev);
 
     /* Clean up descriptors from previous transmission */
 	ptdescr = (pcsca_bd_t *)(card->hw.rambase +
@@ -1999,7 +1998,7 @@
 	} else {
 #endif
 	/* Tell the upper layer we are ready to transmit more packets */
-		netif_wake_queue((struct net_device*)dev->hdlc);
+		netif_wake_queue(dev->dev);
 #ifdef CONFIG_PC300_MLPPP
 	}
 #endif
@@ -2017,8 +2016,8 @@
 		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);
+			struct net_device *dev = d->dev;
+			hdlc_device *hdlc = dev_to_hdlc(dev);
 
 			spin_lock(&card->card_lock);
 
@@ -2049,7 +2048,7 @@
 							if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
 								rx_dma_stop(card, ch);
 							}
-							cpc_net_rx(hdlc);
+							cpc_net_rx(dev);
 							/* Discard invalid frames */
 							hdlc->stats.rx_errors++;
 							hdlc->stats.rx_over_errors++;
@@ -2073,10 +2072,10 @@
 							/* verify if driver is TTY */
 							cpc_tty_receive(d);
 						} else {
-							cpc_net_rx(hdlc);
+							cpc_net_rx(dev);
 						}
 #else
-						cpc_net_rx(hdlc);
+						cpc_net_rx(dev);
 #endif
 						if (card->hw.type == PC300_TE) {
 							cpc_writeb(card->hw.falcbase +
@@ -2829,12 +2828,7 @@
 
 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;
+	return hdlc_stats(dev);
 }
 
 static int clock_rate_calc(uclong rate, uclong clock, int *br_io)
@@ -3075,10 +3069,9 @@
 	return 0;
 }
 
-static int cpc_attach(hdlc_device * hdlc, unsigned short encoding,
+static int cpc_attach(struct net_device *dev, 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;
@@ -3168,7 +3161,7 @@
 		d->if_ptr = &hdlc->state.ppp.pppdev;
 	}
 
-	result = hdlc_open(hdlc);
+	result = hdlc_open(dev);
 	if (hdlc->proto.id == IF_PROTO_PPP) {
 		dev->priv = d;
 	}
@@ -3200,7 +3193,7 @@
 	cpc_closech(d);
 	CPC_UNLOCK(card, flags);
 
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 	if (hdlc->proto.id == IF_PROTO_PPP) {
 		d->if_ptr = NULL;
 	}
@@ -3369,17 +3362,14 @@
 		d->line_on = 0;
 		d->line_off = 0;
 
-		d->hdlc = (hdlc_device *) kmalloc(sizeof(hdlc_device), GFP_KERNEL);
-		if (d->hdlc == NULL)
+		dev = alloc_hdlcdev(NULL);
+		if (dev == NULL)
 			continue;
-		memset(d->hdlc, 0, sizeof(hdlc_device));
 
-		hdlc = d->hdlc;
+		hdlc = dev_to_hdlc(dev);
 		hdlc->xmit = cpc_queue_xmit;
 		hdlc->attach = cpc_attach;
-
-		dev = hdlc_to_dev(hdlc);
-
+		d->dev = dev;
 		dev->mem_start = card->hw.ramphys;
 		dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1;
 		dev->irq = card->hw.irq;
@@ -3397,7 +3387,7 @@
 		dev->change_mtu = cpc_change_mtu;
 		dev->do_ioctl = cpc_ioctl;
 
-		if (register_hdlc_device(hdlc) == 0) {
+		if (register_hdlc_device(dev) == 0) {
 			dev->priv = d;	/* We need 'priv', hdlc doesn't */
 			printk("%s: Cyclades-PC300/", dev->name);
 			switch (card->hw.type) {
@@ -3425,8 +3415,7 @@
 		} 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);
+			free_netdev(dev);
 			continue;
 		}
 	}
@@ -3658,7 +3647,7 @@
 			   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);
+			unregister_hdlc_device(card->chan[i].d.dev);
 		}
 		iounmap((void *) card->hw.plxbase);
 		iounmap((void *) card->hw.scabase);
@@ -3671,6 +3660,9 @@
 			iounmap((void *) card->hw.falcbase);
 			release_mem_region(card->hw.falcphys, card->hw.falcsize);
 		}
+		for (i = 0; i < card->hw.nchan; i++)
+			if (card->chan[i].d.dev);
+				free_netdev(card->chan[i].d.dev);
 		if (card->hw.irq)
 			free_irq(card->hw.irq, card);
 		kfree(card);
--- diff/drivers/net/wan/pc300_tty.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wan/pc300_tty.c	2004-02-18 09:04:00.000000000 +0000
@@ -155,7 +155,7 @@
 	unsigned long flags; 
 
 	CPC_TTY_DBG("%s-tty: Clear signal %x\n",
-		((struct net_device*)(pc300dev->hdlc))->name, signal);
+		pc300dev->dev->name, signal);
 	CPC_TTY_LOCK(card, flags); 
 	cpc_writeb(card->hw.scabase + M_REG(CTL,ch), 
 		cpc_readb(card->hw.scabase+M_REG(CTL,ch))& signal);
@@ -173,7 +173,7 @@
 	unsigned long flags; 
 
 	CPC_TTY_DBG("%s-tty: Set signal %x\n",
-		((struct net_device*)(pc300dev->hdlc))->name, signal);
+		pc300dev->dev->name, signal);
 	CPC_TTY_LOCK(card, flags); 
 	cpc_writeb(card->hw.scabase + M_REG(CTL,ch), 
 		cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~signal);
@@ -196,17 +196,17 @@
 	st_cpc_tty_area * cpc_tty;
 
 	/* hdlcX - X=interface number */
-	port = ((struct net_device*)(pc300dev->hdlc))->name[4] - '0';
+	port = pc300dev->dev->name[4] - '0';
 	if (port >= CPC_TTY_NPORTS) {
 		printk("%s-tty: invalid interface selected (0-%i): %i", 
-			((struct net_device*)(pc300dev->hdlc))->name,
+			pc300dev->dev->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,
+			pc300dev->dev->name,
 			CPC_TTY_MAJOR, CPC_TTY_MINOR_START,
 			CPC_TTY_MINOR_START+CPC_TTY_NPORTS);
 		/* initialize tty driver struct */
@@ -239,7 +239,7 @@
 		/* register the TTY driver */
 		if (tty_register_driver(&serial_drv)) { 
 			printk("%s-tty: Failed to register serial driver! ",
-				((struct net_device*)(pc300dev->hdlc))->name);
+				pc300dev->dev->name);
 		   	return;
 		} 
 
@@ -251,7 +251,7 @@
 	
 	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);
+				pc300dev->dev->name, port);
 		return;
 	}
 
@@ -268,11 +268,11 @@
 
 	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);
+	aux = strlen(pc300dev->dev->name);
+	memcpy(cpc_tty->name, pc300dev->dev->name, aux);
 	memcpy(&cpc_tty->name[aux], "-tty", 5);
 	
-	cpc_open((struct net_device *)pc300dev->hdlc);
+	cpc_open(pc300dev->dev);
 	cpc_tty_signal_off(pc300dev, CTL_DTR);
 
 	CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n",
@@ -457,7 +457,7 @@
 		(from_user)?"from user" : "from kernel",count);
 	
 	pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; 
-	stats = &((pc300dev_t*)cpc_tty->pc300dev)->hdlc->stats;
+	stats = hdlc_stats(((pc300dev_t*)cpc_tty->pc300dev)->dev);
 	card = (pc300_t *) pc300chan->card;
 	ch = pc300chan->channel; 
 
@@ -756,7 +756,7 @@
 	pc300_t *card = (pc300_t *)pc300chan->card; 
 	int ch = pc300chan->channel; 
 	volatile pcsca_bd_t * ptdescr; 
-	struct net_device_stats *stats = &pc300dev->hdlc->stats; 
+	struct net_device_stats *stats = hdlc_stats(pc300dev->dev);
 	int rx_len, rx_aux; 
 	volatile unsigned char status; 
 	unsigned short first_bd = pc300chan->rx_first_bd;
@@ -932,7 +932,7 @@
 	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; 
+	struct net_device_stats *stats = hdlc_stats(dev->dev);
 	unsigned long flags; 
 	volatile pcsca_bd_t * ptdescr; 
 	int i, nchar;
@@ -1016,19 +1016,18 @@
 
 	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);
+		CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name);
 		return; 
 	}
 
 	skb_put (skb, 10 + len); 
-	skb->dev = (struct net_device *) dev->hdlc; 
+	skb->dev = dev->dev; 
 	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);
+	memcpy(skb->data,dev->dev->name,5);
 	skb->data[5] = '['; 
 	skb->data[6] = rxtx; 
 	skb->data[7] = ']'; 
@@ -1050,15 +1049,14 @@
 	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);
+		CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->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);
+		pc300dev->dev->name, cpc_tty->name);
 		return; 
 	}
 
--- diff/drivers/net/wan/pci200syn.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/net/wan/pci200syn.c	2004-02-18 09:04:00.000000000 +0000
@@ -73,7 +73,7 @@
 
 
 typedef struct port_s {
-	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	struct net_device *dev;
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
 	sync_serial_settings settings;
@@ -177,14 +177,13 @@
 
 static int pci200_open(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
-	int result = hdlc_open(hdlc);
+	int result = hdlc_open(dev);
 	if (result)
 		return result;
 
-	sca_open(hdlc);
+	sca_open(dev);
 	pci200_set_iface(port);
 	sca_flush(port_to_card(port));
 	return 0;
@@ -194,10 +193,9 @@
 
 static int pci200_close(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	sca_close(hdlc);
+	sca_close(dev);
 	sca_flush(port_to_card(dev_to_port(dev)));
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 	return 0;
 }
 
@@ -207,12 +205,11 @@
 {
 	const size_t size = sizeof(sync_serial_settings);
 	sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
 #ifdef DEBUG_RINGS
 	if (cmd == SIOCDEVPRIVATE) {
-		sca_dump_rings(hdlc);
+		sca_dump_rings(dev);
 		return 0;
 	}
 #endif
@@ -265,8 +262,10 @@
 	card_t *card = pci_get_drvdata(pdev);
 
 	for(i = 0; i < 2; i++)
-		if (card->ports[i].card)
-			unregister_hdlc_device(&card->ports[i].hdlc);
+		if (card->ports[i].card) {
+			struct net_device *dev = port_to_dev(&card->ports[i]);
+			unregister_hdlc_device(dev);
+		}
 
 	if (card->irq)
 		free_irq(card->irq, card);
@@ -281,6 +280,10 @@
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
+	if (card->ports[0].dev)
+		free_netdev(card->ports[0].dev);
+	if (card->ports[1].dev)
+		free_netdev(card->ports[1].dev);
 	kfree(card);
 }
 
@@ -323,6 +326,13 @@
 	}
 	memset(card, 0, sizeof(card_t));
 	pci_set_drvdata(pdev, card);
+	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
+	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
+	if (!card->ports[0].dev || !card->ports[1].dev) {
+		printk(KERN_ERR "pci200syn: unable to allocate memory\n");
+		pci200_pci_remove_one(pdev);
+		return -ENOMEM;
+	}
 
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
 	if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE ||
@@ -397,7 +407,8 @@
 
 	for(i = 0; i < 2; i++) {
 		port_t *port = &card->ports[i];
-		struct net_device *dev = hdlc_to_dev(&port->hdlc);
+		struct net_device *dev = port_to_dev(port);
+		hdlc_device *hdlc = dev_to_hdlc(dev);
 		port->phy_node = i;
 
 		spin_lock_init(&port->lock);
@@ -409,20 +420,21 @@
 		dev->do_ioctl = pci200_ioctl;
 		dev->open = pci200_open;
 		dev->stop = pci200_close;
-		port->hdlc.attach = sca_attach;
-		port->hdlc.xmit = sca_xmit;
+		hdlc->attach = sca_attach;
+		hdlc->xmit = sca_xmit;
 		port->settings.clock_type = CLOCK_EXT;
-		if(register_hdlc_device(&port->hdlc)) {
+		port->card = card;
+		if(register_hdlc_device(dev)) {
 			printk(KERN_ERR "pci200syn: unable to register hdlc "
 			       "device\n");
+			port->card = NULL;
 			pci200_pci_remove_one(pdev);
 			return -ENOBUFS;
 		}
-		port->card = card;
 		sca_init_sync_port(port);	/* Set up SCA memory */
 
 		printk(KERN_INFO "%s: PCI200SYN node %d\n",
-		       hdlc_to_name(&port->hdlc), port->phy_node);
+		       dev->name, port->phy_node);
 	}
 
 	sca_flush(card);
--- diff/drivers/net/wan/sbni.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/net/wan/sbni.c	2004-02-18 09:04:00.000000000 +0000
@@ -210,7 +210,6 @@
 static void __init sbni_devsetup(struct net_device *dev)
 {
 	ether_setup( dev );
-	dev->init 		= &sbni_init;
 	dev->open		= &sbni_open;
 	dev->stop		= &sbni_close;
 	dev->hard_start_xmit	= &sbni_start_xmit;
@@ -234,8 +233,15 @@
 	sprintf(dev->name, "sbni%d", unit);
 	netdev_boot_setup_check(dev);
 
+	err = sbni_init(dev);
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+
 	err = register_netdev(dev);
 	if (err) {
+		release_region( dev->base_addr, SBNI_IO_EXTENT );
 		free_netdev(dev);
 		return err;
 	}
@@ -304,8 +310,13 @@
 		/* Avoid already found cards from previous calls */
 		if( !request_region( pci_ioaddr, SBNI_IO_EXTENT, dev->name ) ) {
 			pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys );
-			if( subsys != 2  ||	/* Dual adapter is present */
-			    check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) )
+
+			if (subsys != 2)
+				continue;
+
+			/* Dual adapter is present */
+			if (!request_region(pci_ioaddr += 4, SBNI_IO_EXTENT,
+							dev->name ) )
 				continue;
 		}
 
@@ -318,8 +329,10 @@
 				pci_irq_line );
 
 		/* avoiding re-enable dual adapters */
-		if( (pci_ioaddr & 7) == 0  &&  pci_enable_device( pdev ) )
+		if( (pci_ioaddr & 7) == 0  &&  pci_enable_device( pdev ) ) {
+			release_region( pci_ioaddr, SBNI_IO_EXTENT );
 			return  -EIO;
+		}
 		if( sbni_probe1( dev, pci_ioaddr, pci_irq_line ) )
 			return  0;
 	}
@@ -1482,19 +1495,25 @@
 init_module( void )
 {
 	struct net_device  *dev;
+	int err;
 
 	while( num < SBNI_MAX_NUM_CARDS ) {
 		dev = alloc_netdev(sizeof(struct net_local), 
 				   "sbni%d", sbni_devsetup);
-		if( !dev) {
-			printk( KERN_ERR "sbni: unable to allocate device!\n" );
-			return  -ENOMEM;
-		}
+		if( !dev)
+			break;
 
 		sprintf( dev->name, "sbni%d", num );
 
+		err = sbni_init(dev);
+		if (err) {
+			free_netdev(dev);
+			break;
+		}
+
 		if( register_netdev( dev ) ) {
-			kfree( dev );
+			release_region( dev->base_addr, SBNI_IO_EXTENT );
+			free_netdev( dev );
 			break;
 		}
 	}
--- diff/drivers/net/wan/sdla.c	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/net/wan/sdla.c	2004-02-18 09:04:00.000000000 +0000
@@ -1339,6 +1339,8 @@
 	struct frad_local *flp;
 	int               i;
 	char              byte;
+	unsigned base;
+	int err = -EINVAL;
 
 	flp = dev->priv;
 
@@ -1352,108 +1354,90 @@
 	if (i == sizeof(valid_port) / sizeof(int))
 		return(-EINVAL);
 
-	dev->base_addr = map->base_addr;
-	if (!request_region(dev->base_addr, SDLA_IO_EXTENTS, dev->name)){
+	if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
 		printk(KERN_WARNING "SDLA: io-port 0x%04lx in use \n", dev->base_addr);
 		return(-EINVAL);
 	}
+	base = map->base_addr;
+
 	/* test for card types, S502A, S502E, S507, S508                 */
 	/* these tests shut down the card completely, so clear the state */
 	flp->type = SDLA_UNKNOWN;
 	flp->state = 0;
    
 	for(i=1;i<SDLA_IO_EXTENTS;i++)
-		if (inb(dev->base_addr + i) != 0xFF)
+		if (inb(base + i) != 0xFF)
 			break;
 
-	if (i == SDLA_IO_EXTENTS)
-	{   
-		outb(SDLA_HALT, dev->base_addr + SDLA_REG_Z80_CONTROL);
-		if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x08)
-		{
-			outb(SDLA_S502E_INTACK, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x0F) == 0x0C)
-			{
-				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
+	if (i == SDLA_IO_EXTENTS) {   
+		outb(SDLA_HALT, base + SDLA_REG_Z80_CONTROL);
+		if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x08) {
+			outb(SDLA_S502E_INTACK, base + SDLA_REG_CONTROL);
+			if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x0C) {
+				outb(SDLA_HALT, base + SDLA_REG_CONTROL);
 				flp->type = SDLA_S502E;
+				goto got_type;
 			}
 		}
 	}
 
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		for(byte=inb(dev->base_addr),i=0;i<SDLA_IO_EXTENTS;i++)
-			if (inb(dev->base_addr + i) != byte)
-				break;
+	for(byte=inb(base),i=0;i<SDLA_IO_EXTENTS;i++)
+		if (inb(base + i) != byte)
+			break;
 
-		if (i == SDLA_IO_EXTENTS)
-		{
-			outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x30)
-			{
-				outb(SDLA_S507_ENABLE, dev->base_addr + SDLA_REG_CONTROL);
-				if ((inb(dev->base_addr + SDLA_S502_STS) & 0x7E) == 0x32)
-				{
-					outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-					flp->type = SDLA_S507;
-				}
+	if (i == SDLA_IO_EXTENTS) {
+		outb(SDLA_HALT, base + SDLA_REG_CONTROL);
+		if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x30) {
+			outb(SDLA_S507_ENABLE, base + SDLA_REG_CONTROL);
+			if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x32) {
+				outb(SDLA_HALT, base + SDLA_REG_CONTROL);
+				flp->type = SDLA_S507;
+				goto got_type;
 			}
 		}
 	}
 
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-		if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x00)
-		{
-			outb(SDLA_S508_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-			if ((inb(dev->base_addr + SDLA_S508_STS) & 0x3F) == 0x10)
-			{
-				outb(SDLA_HALT, dev->base_addr + SDLA_REG_CONTROL);
-				flp->type = SDLA_S508;
-			}
+	outb(SDLA_HALT, base + SDLA_REG_CONTROL);
+	if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x00) {
+		outb(SDLA_S508_INTEN, base + SDLA_REG_CONTROL);
+		if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x10) {
+			outb(SDLA_HALT, base + SDLA_REG_CONTROL);
+			flp->type = SDLA_S508;
+			goto got_type;
 		}
 	}
 
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		outb(SDLA_S502A_HALT, dev->base_addr + SDLA_REG_CONTROL);
-		if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-		{
-			outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-			if (inb(dev->base_addr + SDLA_S502_STS) == 0x40)
-			{
-				outb(SDLA_S502A_INTEN, dev->base_addr + SDLA_REG_CONTROL);
-				if (inb(dev->base_addr + SDLA_S502_STS) == 0x44)
-				{
-					outb(SDLA_S502A_START, dev->base_addr + SDLA_REG_CONTROL);
-					flp->type = SDLA_S502A;
-				}
+	outb(SDLA_S502A_HALT, base + SDLA_REG_CONTROL);
+	if (inb(base + SDLA_S502_STS) == 0x40) {
+		outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
+		if (inb(base + SDLA_S502_STS) == 0x40) {
+			outb(SDLA_S502A_INTEN, base + SDLA_REG_CONTROL);
+			if (inb(base + SDLA_S502_STS) == 0x44) {
+				outb(SDLA_S502A_START, base + SDLA_REG_CONTROL);
+				flp->type = SDLA_S502A;
+				goto got_type;
 			}
 		}
 	}
 
-	if (flp->type == SDLA_UNKNOWN)
-	{
-		printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
-		return(-ENODEV);
-	}
+	printk(KERN_NOTICE "%s: Unknown card type\n", dev->name);
+	err = -ENODEV;
+	goto fail;
 
-	switch(dev->base_addr)
-	{
+got_type:
+	switch(base) {
 		case 0x270:
 		case 0x280:
 		case 0x380: 
 		case 0x390:
-			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-				return(-EINVAL);
+			if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
+				goto fail;
 	}
 
-	switch (map->irq)
-	{
+	switch (map->irq) {
 		case 2:
 			if (flp->type != SDLA_S502E)
-				return(-EINVAL);
+				goto fail;
 			break;
 
 		case 10:
@@ -1461,28 +1445,26 @@
 		case 12:
 		case 15:
 		case 4:
-			if ((flp->type != SDLA_S508) && (flp->type != SDLA_S507))
-				return(-EINVAL);
-
+			if (flp->type != SDLA_S508 && flp->type != SDLA_S507)
+				goto fail;
+			break;
 		case 3:
 		case 5:
 		case 7:
 			if (flp->type == SDLA_S502A)
-				return(-EINVAL);
+				goto fail;
 			break;
 
 		default:
-			return(-EINVAL);
+			goto fail;
 	}
-	dev->irq = map->irq;
 
+	err = -EAGAIN;
 	if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) 
-		return(-EAGAIN);
+		goto fail;
 
-	if (flp->type == SDLA_S507)
-	{
-		switch(dev->irq)
-		{
+	if (flp->type == SDLA_S507) {
+		switch(dev->irq) {
 			case 3:
 				flp->state = SDLA_S507_IRQ3;
 				break;
@@ -1514,35 +1496,25 @@
 		if (valid_mem[i] == map->mem_start)
 			break;   
 
+	err = -EINVAL;
 	if (i == sizeof(valid_mem) / sizeof(int))
-	/*
-	 *	FIXME:
-	 *	BUG BUG BUG: MUST RELEASE THE IRQ WE ALLOCATED IN
-	 *	ALL THESE CASES
-	 *
-	 */
-		return(-EINVAL);
+		goto fail2;
 
-	if ((flp->type == SDLA_S502A) && (((map->mem_start & 0xF000) >> 12) == 0x0E))
-		return(-EINVAL);
-
-	if ((flp->type != SDLA_S507) && ((map->mem_start >> 16) == 0x0B))
-		return(-EINVAL);
+	if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
+		goto fail2;
 
-	if ((flp->type == SDLA_S507) && ((map->mem_start >> 16) == 0x0D))
-		return(-EINVAL);
+	if (flp->type != SDLA_S507 && map->mem_start >> 16 == 0x0B)
+		goto fail2;
 
-	dev->mem_start = map->mem_start;
-	dev->mem_end = dev->mem_start + 0x2000;
+	if (flp->type == SDLA_S507 && map->mem_start >> 16 == 0x0D)
+		goto fail2;
 
 	byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0;
 	byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0));
-	switch(flp->type)
-	{
+	switch(flp->type) {
 		case SDLA_S502A:
 		case SDLA_S502E:
-			switch (map->mem_start >> 16)
-			{
+			switch (map->mem_start >> 16) {
 				case 0x0A:
 					byte |= SDLA_S502_SEG_A;
 					break;
@@ -1558,8 +1530,7 @@
 			}
 			break;
 		case SDLA_S507:
-			switch (map->mem_start >> 16)
-			{
+			switch (map->mem_start >> 16) {
 				case 0x0A:
 					byte |= SDLA_S507_SEG_A;
 					break;
@@ -1575,8 +1546,7 @@
 			}
 			break;
 		case SDLA_S508:
-			switch (map->mem_start >> 16)
-			{
+			switch (map->mem_start >> 16) {
 				case 0x0A:
 					byte |= SDLA_S508_SEG_A;
 					break;
@@ -1594,7 +1564,7 @@
 	}
 
 	/* set the memory bits, and enable access */
-	outb(byte, dev->base_addr + SDLA_REG_PC_WINDOW);
+	outb(byte, base + SDLA_REG_PC_WINDOW);
 
 	switch(flp->type)
 	{
@@ -1608,10 +1578,20 @@
 			flp->state = SDLA_MEMEN;
 			break;
 	}
-	outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
+	outb(flp->state, base + SDLA_REG_CONTROL);
 
+	dev->irq = map->irq;
+	dev->base_addr = base;
+	dev->mem_start = map->mem_start;
+	dev->mem_end = dev->mem_start + 0x2000;
 	flp->initialized = 1;
-	return(0);
+	return 0;
+
+fail2:
+	free_irq(map->irq, dev);
+fail:
+	release_region(base, SDLA_IO_EXTENTS);
+	return err;
 }
  
 static struct net_device_stats *sdla_stats(struct net_device *dev)
@@ -1676,13 +1656,13 @@
 
 static void __exit exit_sdla(void)
 {
-	struct frad_local *flp;
+	struct frad_local *flp = sdla->priv;
 
 	unregister_netdev(sdla);
-	if (sdla->irq)
+	if (flp->initialized) {
 		free_irq(sdla->irq, sdla);
-
-	flp = sdla->priv;
+		release_region(sdla->base_addr, SDLA_IO_EXTENTS);
+	}
 	del_timer_sync(&flp->timer);
 	free_netdev(sdla);
 }
--- diff/drivers/net/wan/sealevel.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/net/wan/sealevel.c	2004-02-18 09:04:00.000000000 +0000
@@ -420,6 +420,7 @@
 	/* DMA off on the card, drop DTR */
 	outb(0, b->iobase);
 	release_region(b->iobase, 8);
+	kfree(b);
 }
 
 
--- diff/drivers/net/wan/wanxl.c	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/net/wan/wanxl.c	2004-02-18 09:04:00.000000000 +0000
@@ -51,7 +51,7 @@
 
 
 typedef struct {
-	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	struct net_device *dev;
 	struct card_t *card;
 	spinlock_t lock;	/* for wanxl_xmit */
         int node;		/* physical port #0 - 3 */
@@ -78,31 +78,26 @@
 	struct sk_buff *rx_skbs[RX_QUEUE_LENGTH];
 	card_status_t *status;	/* shared between host and card */
 	dma_addr_t status_address;
+	port_t __ports[0];
 }card_t;
 
 
 
-static inline port_t* hdlc_to_port(hdlc_device *hdlc)
-{
-        return (port_t*)hdlc;
-}
-
-
 static inline port_t* dev_to_port(struct net_device *dev)
 {
-        return hdlc_to_port(dev_to_hdlc(dev));
+        return (port_t *)dev_to_hdlc(dev)->priv;
 }
 
 
 static inline struct net_device *port_to_dev(port_t* port)
 {
-        return hdlc_to_dev(&port->hdlc);
+        return port->dev;
 }
 
 
 static inline const char* port_name(port_t *port)
 {
-	return hdlc_to_name((hdlc_device*)port);
+	return port_to_dev(port)->name;
 }
 
 
@@ -172,7 +167,7 @@
 	printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n",
 	       port_name(port), pm, dte, cable, dsr, dcd);
 
-	hdlc_set_carrier(value & STATUS_CABLE_DCD, &port->hdlc);
+	hdlc_set_carrier(value & STATUS_CABLE_DCD, port_to_dev(port));
 }
 
 
@@ -180,6 +175,8 @@
 /* Transmit complete interrupt service */
 static inline void wanxl_tx_intr(port_t *port)
 {
+	struct net_device *dev = port_to_dev(port);
+	struct net_device_stats *stats = hdlc_stats(dev);
 	while (1) {
                 desc_t *desc = &get_status(port)->tx_descs[port->tx_in];
 		struct sk_buff *skb = port->tx_skbs[port->tx_in];
@@ -187,17 +184,17 @@
 		switch (desc->stat) {
 		case PACKET_FULL:
 		case PACKET_EMPTY:
-			netif_wake_queue(port_to_dev(port));
+			netif_wake_queue(dev);
 			return;
 
 		case PACKET_UNDERRUN:
-			port->hdlc.stats.tx_errors++;
-			port->hdlc.stats.tx_fifo_errors++;
+			stats->tx_errors++;
+			stats->tx_fifo_errors++;
 			break;
 
 		default:
-			port->hdlc.stats.tx_packets++;
-			port->hdlc.stats.tx_bytes += skb->len;
+			stats->tx_packets++;
+			stats->tx_bytes += skb->len;
 		}
                 desc->stat = PACKET_EMPTY; /* Free descriptor */
 		pci_unmap_single(port->card->pdev, desc->address, skb->len,
@@ -218,13 +215,14 @@
 		struct sk_buff *skb = card->rx_skbs[card->rx_in];
 		port_t *port = card->ports[desc->stat & PACKET_PORT_MASK];
 		struct net_device *dev = port_to_dev(port);
+		struct net_device_stats *stats = hdlc_stats(dev);
 
 		if ((desc->stat & PACKET_PORT_MASK) > card->n_ports)
 			printk(KERN_CRIT "wanXL %s: received packet for"
 			       " nonexistent port\n", card_name(card->pdev));
 
 		else if (!skb)
-			port->hdlc.stats.rx_dropped++;
+			stats->rx_dropped++;
 
 		else {
 			pci_unmap_single(card->pdev, desc->address,
@@ -236,8 +234,8 @@
 			       skb->len);
 			debug_frame(skb);
 #endif
-			port->hdlc.stats.rx_packets++;
-			port->hdlc.stats.rx_bytes += skb->len;
+			stats->rx_packets++;
+			stats->rx_bytes += skb->len;
 			skb->mac.raw = skb->data;
 			skb->dev = dev;
 			dev->last_rx = jiffies;
@@ -290,8 +288,7 @@
 
 static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-        port_t *port = hdlc_to_port(hdlc);
+        port_t *port = dev_to_port(dev);
 	desc_t *desc;
 
         spin_lock(&port->lock);
@@ -338,10 +335,10 @@
 
 
 
-static int wanxl_attach(hdlc_device *hdlc, unsigned short encoding,
+static int wanxl_attach(struct net_device *dev, unsigned short encoding,
 			unsigned short parity)
 {
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
 	if (encoding != ENCODING_NRZ &&
 	    encoding != ENCODING_NRZI)
@@ -365,8 +362,7 @@
 {
 	const size_t size = sizeof(sync_serial_settings);
 	sync_serial_settings line;
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 
 	if (cmd != SIOCWANDEV)
 		return hdlc_ioctl(dev, ifr, cmd);
@@ -415,8 +411,7 @@
 
 static int wanxl_open(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	u8 *dbr = port->card->plx + PLX_DOORBELL_TO_CARD;
 	unsigned long timeout;
 	int i;
@@ -425,7 +420,7 @@
 		printk(KERN_ERR "%s: port already open\n", port_name(port));
 		return -EIO;
 	}
-	if ((i = hdlc_open(hdlc)) != 0)
+	if ((i = hdlc_open(dev)) != 0)
 		return i;
 
 	port->tx_in = port->tx_out = 0;
@@ -450,12 +445,11 @@
 
 static int wanxl_close(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	port_t *port = dev_to_port(dev);
 	unsigned long timeout;
 	int i;
 
-	hdlc_close(hdlc);
+	hdlc_close(dev);
 	/* signal the card */
 	writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node),
 	       port->card->plx + PLX_DOORBELL_TO_CARD);
@@ -487,14 +481,13 @@
 
 static struct net_device_stats *wanxl_get_stats(struct net_device *dev)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	port_t *port = hdlc_to_port(hdlc);
+	struct net_device_stats *stats = hdlc_stats(dev);
+	port_t *port = dev_to_port(dev);
 
-	hdlc->stats.rx_over_errors = get_status(port)->rx_overruns;
-	hdlc->stats.rx_frame_errors = get_status(port)->rx_frame_errors;
-	hdlc->stats.rx_errors = hdlc->stats.rx_over_errors +
-		hdlc->stats.rx_frame_errors;
-        return &hdlc->stats;
+	stats->rx_over_errors = get_status(port)->rx_overruns;
+	stats->rx_frame_errors = get_status(port)->rx_frame_errors;
+	stats->rx_errors = stats->rx_over_errors + stats->rx_frame_errors;
+        return stats;
 }
 
 
@@ -535,14 +528,16 @@
 	card_t *card = pci_get_drvdata(pdev);
 	int i;
 
+	for (i = 0; i < 4; i++)
+		if (card->ports[i]) {
+			struct net_device *dev = port_to_dev(card->ports[i]);
+			unregister_hdlc_device(dev);
+		}
+
 	/* unregister and free all host resources */
 	if (card->irq)
 		free_irq(card->irq, card);
 
-	for (i = 0; i < 4; i++)
-		if (card->ports[i])
-			unregister_hdlc_device(&card->ports[i]->hdlc);
-
 	wanxl_reset(card);
 
 	for (i = 0; i < RX_QUEUE_LENGTH; i++)
@@ -560,6 +555,10 @@
 		pci_free_consistent(pdev, sizeof(card_status_t),
 				    card->status, card->status_address);
 
+	for (i = 0; i < card->n_ports; i++)
+		if (card->__ports[i].dev)
+			free_netdev(card->__ports[i].dev);
+
 	pci_set_drvdata(pdev, NULL);
 	kfree(card);
 	pci_release_regions(pdev);
@@ -628,6 +627,16 @@
 	card->pdev = pdev;
 	card->n_ports = ports;
 
+	for (i = 0; i < ports; i++) {
+		card->__ports[i].dev = alloc_hdlcdev(&card->__ports[i]);
+		if (!card->__ports[i].dev) {
+			printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
+			       card_name(pdev));
+			wanxl_pci_remove_one(pdev);
+			return -ENOMEM;
+		}
+	}
+
 	card->status = pci_alloc_consistent(pdev, sizeof(card_status_t),
 					    &card->status_address);
 	if (card->status == NULL) {
@@ -708,31 +717,6 @@
 		return -ENODEV;
 	}
 
-	for (i = 0; i < ports; i++) {
-		port_t *port = (void *)card + sizeof(card_t) +
-			i * sizeof(port_t);
-		struct net_device *dev = hdlc_to_dev(&port->hdlc);
-		spin_lock_init(&port->lock);
-		SET_MODULE_OWNER(dev);
-		dev->tx_queue_len = 50;
-		dev->do_ioctl = wanxl_ioctl;
-		dev->open = wanxl_open;
-		dev->stop = wanxl_close;
-		port->hdlc.attach = wanxl_attach;
-		port->hdlc.xmit = wanxl_xmit;
-		if(register_hdlc_device(&port->hdlc)) {
-			printk(KERN_ERR "wanXL %s: unable to register hdlc"
-			       " device\n", card_name(pdev));
-			wanxl_pci_remove_one(pdev);
-			return -ENOBUFS;
-		}
-		card->ports[i] = port;
-		dev->get_stats = wanxl_get_stats;
-		port->card = card;
-		port->node = i;
-		get_status(port)->clocking = CLOCK_EXT;
-	}
-
 	for (i = 0; i < RX_QUEUE_LENGTH; i++) {
 		struct sk_buff *skb = dev_alloc_skb(BUFFER_LENGTH);
 		card->rx_skbs[i] = skb;
@@ -801,6 +785,32 @@
 	}
 	card->irq = pdev->irq;
 
+	for (i = 0; i < ports; i++) {
+		port_t *port = &card->__ports[i];
+		struct net_device *dev = port_to_dev(port);
+		hdlc_device *hdlc = dev_to_hdlc(dev);
+		spin_lock_init(&port->lock);
+		SET_MODULE_OWNER(dev);
+		dev->tx_queue_len = 50;
+		dev->do_ioctl = wanxl_ioctl;
+		dev->open = wanxl_open;
+		dev->stop = wanxl_close;
+		hdlc->attach = wanxl_attach;
+		hdlc->xmit = wanxl_xmit;
+		card->ports[i] = port;
+		dev->get_stats = wanxl_get_stats;
+		port->card = card;
+		port->node = i;
+		get_status(port)->clocking = CLOCK_EXT;
+		if (register_hdlc_device(dev)) {
+			printk(KERN_ERR "wanXL %s: unable to register hdlc"
+			       " device\n", card_name(pdev));
+			card->ports[i] = NULL;
+			wanxl_pci_remove_one(pdev);
+			return -ENOBUFS;
+		}
+	}
+
 	return 0;
 }
 
--- diff/drivers/net/wan/x25_asy.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wan/x25_asy.c	2004-02-18 09:04:00.000000000 +0000
@@ -213,7 +213,7 @@
 	memcpy(skb_put(skb,count), sl->rbuff, count);
 	skb->mac.raw=skb->data;
 	skb->protocol=htons(ETH_P_X25);
-	if((err=lapb_data_received(sl,skb))!=LAPB_OK)
+	if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK)
 	{
 		kfree_skb(skb);
 		printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
@@ -324,12 +324,12 @@
 	{
 		case 0x00:break;
 		case 0x01: /* Connection request .. do nothing */
-			if((err=lapb_connect_request(sl))!=LAPB_OK)
+			if((err=lapb_connect_request(dev))!=LAPB_OK)
 				printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
 			kfree_skb(skb);
 			return 0;
 		case 0x02: /* Disconnect request .. do nothing - hang up ?? */
-			if((err=lapb_disconnect_request(sl))!=LAPB_OK)
+			if((err=lapb_disconnect_request(dev))!=LAPB_OK)
 				printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
 		default:
 			kfree_skb(skb);
@@ -347,7 +347,7 @@
 	 *        14 Oct 1994  Dmitry Gorodchanin.
 	 */
 	
-	if((err=lapb_data_request(sl,skb))!=LAPB_OK)
+	if((err=lapb_data_request(dev,skb))!=LAPB_OK)
 	{
 		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
 		kfree_skb(skb);
@@ -366,7 +366,7 @@
  *	at the net layer.
  */
   
-static int x25_asy_data_indication(void *token, struct sk_buff *skb)
+static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
 	skb->dev->last_rx = jiffies;
 	return netif_rx(skb);
@@ -378,9 +378,9 @@
  *	perhaps lapb should allow us to bounce this ?
  */
  
-static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
+static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
-	struct x25_asy *sl=token;
+	struct x25_asy *sl=dev->priv;
 	
 	spin_lock(&sl->lock);
 	if (netif_queue_stopped(sl->dev) || sl->tty == NULL)
@@ -405,9 +405,9 @@
  *	LAPB connection establish/down information.
  */
  
-static void x25_asy_connected(void *token, int reason)
+static void x25_asy_connected(struct net_device *dev, int reason)
 {
-	struct x25_asy *sl = token;
+	struct x25_asy *sl = dev->priv;
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
@@ -428,9 +428,9 @@
 	sl->dev->last_rx = jiffies;
 }
 
-static void x25_asy_disconnected(void *token, int reason)
+static void x25_asy_disconnected(struct net_device *dev, int reason)
 {
-	struct x25_asy *sl = token;
+	struct x25_asy *sl = dev->priv;
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
@@ -500,7 +500,7 @@
 	/*
 	 *	Now attach LAPB
 	 */
-	if((err=lapb_register(sl, &x25_asy_callbacks))==LAPB_OK)
+	if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK)
 		return 0;
 
 	/* Cleanup */
@@ -525,7 +525,7 @@
 	netif_stop_queue(dev);
 	sl->rcount = 0;
 	sl->xleft  = 0;
-	if((err=lapb_unregister(sl))!=LAPB_OK)
+	if((err=lapb_unregister(dev))!=LAPB_OK)
 		printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
 	spin_unlock(&sl->lock);
 	return 0;
--- diff/drivers/net/wd.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wd.c	2004-02-18 09:04:00.000000000 +0000
@@ -333,6 +333,9 @@
 	ei_status.get_8390_hdr = &wd_get_8390_hdr;
 	dev->open = &wd_open;
 	dev->stop = &wd_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ei_poll;
+#endif
 	NS8390_init(dev, 0);
 
 #if 1
--- diff/drivers/net/wireless/airo.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wireless/airo.c	2004-02-18 09:04:00.000000000 +0000
@@ -2599,10 +2599,8 @@
 	return rc;
 }
 
-static void wifi_setup(struct net_device *dev, struct net_device *ethdev)
+static void wifi_setup(struct net_device *dev)
 {
-	struct airo_info *ai = ethdev->priv;
-	dev->priv = ai;
 	dev->hard_header        = 0;
 	dev->rebuild_header     = 0;
 	dev->hard_header_cache  = 0;
@@ -2620,14 +2618,11 @@
 	dev->change_mtu = &airo_change_mtu;
 	dev->open = &airo_open;
 	dev->stop = &airo_close;
-	dev->irq = ethdev->irq;
-	dev->base_addr = ethdev->base_addr;
 
 	dev->type               = ARPHRD_IEEE80211;
 	dev->hard_header_len    = ETH_HLEN;
 	dev->mtu                = 2312;
 	dev->addr_len           = ETH_ALEN;
-	memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
 	dev->tx_queue_len       = 100; 
 
 	memset(dev->broadcast,0xFF, ETH_ALEN);
@@ -2639,17 +2634,17 @@
 					struct net_device *ethdev)
 {
 	int err;
-	struct net_device *dev = (struct net_device*)kmalloc(sizeof *dev,GFP_KERNEL);
-	if (!dev) return 0;
-	memset(dev, 0, sizeof(*dev));
-
-	strcpy(dev->name, "wifi%d");
-	dev->priv = ai;
-	wifi_setup(dev, ethdev);
+	struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
+	if (!dev)
+		return NULL;
+	dev->priv = ethdev->priv;
+	dev->irq = ethdev->irq;
+	dev->base_addr = ethdev->base_addr;
+	memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
 	err = register_netdev(dev);
 	if (err<0) {
-		kfree(dev);
-		return 0;
+		free_netdev(dev);
+		return NULL;
 	}
 	return dev;
 }
@@ -2809,7 +2804,7 @@
 	kill_proc(ai->thr_pid, SIGTERM, 1);
 	wait_for_completion(&ai->thr_exited);
 err_out_free:
-	kfree(dev);
+	free_netdev(dev);
 	return NULL;
 }
 
--- diff/drivers/net/wireless/orinoco.c	2003-09-30 15:46:16.000000000 +0100
+++ source/drivers/net/wireless/orinoco.c	2004-02-18 09:04:00.000000000 +0000
@@ -4129,6 +4129,8 @@
 	struct orinoco_private *priv;
 
 	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
+	if (!dev)
+		return NULL;
 	priv = (struct orinoco_private *)dev->priv;
 	priv->ndev = dev;
 	if (sizeof_card)
--- diff/drivers/net/wireless/wl3501_cs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/wireless/wl3501_cs.c	2004-02-18 09:04:00.000000000 +0000
@@ -1580,7 +1580,7 @@
 	*linkp = link->next;
 
 	if (link->priv)
-		kfree(link->priv);
+		free_netdev(link->priv);
 	kfree(link);
 out:
 	return;
--- diff/drivers/net/zorro8390.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/zorro8390.c	2004-02-18 09:04:00.000000000 +0000
@@ -222,6 +222,9 @@
     ei_status.reg_offset = zorro8390_offsets;
     dev->open = &zorro8390_open;
     dev->stop = &zorro8390_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
 #ifdef MODULE
     ei_status.priv = (unsigned long)root_zorro8390_dev;
     root_zorro8390_dev = dev;
--- diff/drivers/oprofile/timer_int.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/oprofile/timer_int.c	2004-02-18 09:04:00.000000000 +0000
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/notifier.h>
 #include <linux/smp.h>
-#include <linux/irq.h>
 #include <linux/oprofile.h>
 #include <linux/profile.h>
 #include <linux/init.h>
--- diff/drivers/parisc/dino.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/parisc/dino.c	2004-02-18 09:04:00.000000000 +0000
@@ -475,7 +475,7 @@
 
 	res = &dino_dev->hba.lmmio_space;
 	res->flags = IORESOURCE_MEM;
-	size = snprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->bridge->bus_id);
+	size = scnprintf(name, sizeof(name), "Dino LMMIO (%s)", bus->bridge->bus_id);
 	res->name = kmalloc(size+1, GFP_KERNEL);
 	if(res->name)
 		strcpy((char *)res->name, name);
--- diff/drivers/pci/hotplug.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pci/hotplug.c	2004-02-18 09:04:00.000000000 +0000
@@ -29,7 +29,7 @@
 
 	/* stuff we want to pass to /sbin/hotplug */
 	envp[i++] = scratch;
-	length += snprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
+	length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
 			    pdev->class);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
@@ -37,7 +37,7 @@
 	scratch += length;
 
 	envp[i++] = scratch;
-	length += snprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
+	length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
 			    pdev->vendor, pdev->device);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
@@ -45,7 +45,7 @@
 	scratch += length;
 
 	envp[i++] = scratch;
-	length += snprintf (scratch, buffer_size - length,
+	length += scnprintf (scratch, buffer_size - length,
 			    "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
 			    pdev->subsystem_device);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
@@ -54,7 +54,7 @@
 	scratch += length;
 
 	envp[i++] = scratch;
-	length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
+	length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
 			    pci_name(pdev));
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
--- diff/drivers/pci/pci-sysfs.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pci/pci-sysfs.c	2004-02-18 09:04:00.000000000 +0000
@@ -71,7 +71,7 @@
 
 	/* Several chips lock up trying to read undefined config space */
 	if (capable(CAP_SYS_ADMIN)) {
-		size = 256;
+		size = dev->cfg_size;
 	} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 		size = 128;
 	}
@@ -123,10 +123,10 @@
 	unsigned int size = count;
 	loff_t init_off = off;
 
-	if (off > 256)
+	if (off > dev->cfg_size)
 		return 0;
-	if (off + count > 256) {
-		size = 256 - off;
+	if (off + count > dev->cfg_size) {
+		size = dev->cfg_size - off;
 		count = size;
 	}
 
@@ -167,6 +167,16 @@
 	.write = pci_write_config,
 };
 
+static struct bin_attribute pcie_config_attr = {
+	.attr =	{
+		.name = "config",
+		.mode = S_IRUGO | S_IWUSR,
+	},
+	.size = 4096,
+	.read = pci_read_config,
+	.write = pci_write_config,
+};
+
 void pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -179,7 +189,11 @@
 	device_create_file (dev, &dev_attr_class);
 	device_create_file (dev, &dev_attr_irq);
 	device_create_file (dev, &dev_attr_resource);
-	sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
+	if (pdev->cfg_size < 4096) {
+		sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
+	} else {
+		sysfs_create_bin_file(&dev->kobj, &pcie_config_attr);
+	}
 
 	/* add platform-specific attributes */
 	pcibios_add_platform_entries(pdev);
--- diff/drivers/pci/pci.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/pci/pci.c	2004-02-18 09:04:00.000000000 +0000
@@ -78,21 +78,15 @@
  * support it.  Possible values for @cap:
  *
  *  %PCI_CAP_ID_PM           Power Management 
- *
  *  %PCI_CAP_ID_AGP          Accelerated Graphics Port 
- *
  *  %PCI_CAP_ID_VPD          Vital Product Data 
- *
  *  %PCI_CAP_ID_SLOTID       Slot Identification 
- *
  *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
- *
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
- *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI Express
  */
-int
-pci_find_capability(struct pci_dev *dev, int cap)
+int pci_find_capability(struct pci_dev *dev, int cap)
 {
 	u16 status;
 	u8 pos, id;
@@ -171,6 +165,54 @@
 }
 
 /**
+ * pci_find_ext_capability - Find an extended capability
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Returns the address of the requested extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it.  Possible values for @cap:
+ *
+ *  %PCI_EXT_CAP_ID_ERR		Advanced Error Reporting
+ *  %PCI_EXT_CAP_ID_VC		Virtual Channel
+ *  %PCI_EXT_CAP_ID_DSN		Device Serial Number
+ *  %PCI_EXT_CAP_ID_PWR		Power Budgeting
+ */
+int pci_find_ext_capability(struct pci_dev *dev, int cap)
+{
+	u32 header;
+	int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
+	int pos = 0x100;
+
+	if (dev->cfg_size <= 256)
+		return 0;
+
+	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+		return 0;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((header & 0x000ffff) == cap)
+			return pos;
+
+		pos = (header >> 20) & ~3;
+		if (pos < 0x100)
+			break;
+
+		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+			break;
+	}
+
+	return 0;
+}
+
+/**
  * pci_find_parent_resource - return resource region of parent bus of given region
  * @dev: PCI device structure contains resources to be searched
  * @res: child resource record for which parent is sought
@@ -223,6 +265,8 @@
 	int pm;
 	u16 pmcsr;
 
+	might_sleep();
+
 	/* bound the state we're entering */
 	if (state > 3) state = 3;
 
--- diff/drivers/pci/probe.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/pci/probe.c	2004-02-18 09:04:00.000000000 +0000
@@ -18,6 +18,8 @@
 
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
 
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
@@ -55,7 +57,7 @@
 	cpumask_t cpumask = pcibus_to_cpumask((to_pci_bus(class_dev))->number);
 	int ret;
 
-	ret = cpumask_snprintf(buf, PAGE_SIZE, cpumask);
+	ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
 	if (ret < PAGE_SIZE)
 		buf[ret++] = '\n';
 	return ret;
@@ -526,6 +528,31 @@
 	kfree(pci_dev);
 }
 
+/**
+ * pci_cfg_space_size - get the configuration space size of the PCI device.
+ * Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
+ * have 4096 bytes.
+ */
+static int pci_cfg_space_size(struct pci_dev *dev)
+{
+	int pos;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (pos)
+		return PCI_CFG_SPACE_EXP_SIZE;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+	if (pos) {
+		u32 status;
+		pci_read_config_dword(dev, pos + PCI_X_STATUS, &status);
+
+		if (status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ))
+			return PCI_CFG_SPACE_EXP_SIZE;
+	}
+
+	return PCI_CFG_SPACE_SIZE;
+}
+
 /*
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
@@ -562,6 +589,7 @@
 	dev->multifunction = !!(hdr_type & 0x80);
 	dev->vendor = l & 0xffff;
 	dev->device = (l >> 16) & 0xffff;
+	dev->cfg_size = pci_cfg_space_size(dev);
 
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
--- diff/drivers/pci/proc.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/pci/proc.c	2004-02-18 09:04:00.000000000 +0000
@@ -16,16 +16,15 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
-#define PCI_CFG_SPACE_SIZE 256
-
 static int proc_initialized;	/* = 0 */
 
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
 	loff_t new = -1;
+	struct inode *inode = file->f_dentry->d_inode;
 
-	down(&file->f_dentry->d_inode->i_sem);
+	down(&inode->i_sem);
 	switch (whence) {
 	case 0:
 		new = off;
@@ -34,14 +33,14 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
-		new = PCI_CFG_SPACE_SIZE + off;
+		new = inode->i_size + off;
 		break;
 	}
-	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
+	if (new < 0 || new > inode->i_size)
 		new = -EINVAL;
 	else
 		file->f_pos = new;
-	up(&file->f_dentry->d_inode->i_sem);
+	up(&inode->i_sem);
 	return new;
 }
 
@@ -61,7 +60,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+		size = dev->cfg_size;
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -134,14 +133,15 @@
 	const struct proc_dir_entry *dp = PDE(ino);
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
+	int size = dev->cfg_size;
 	int cnt;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -403,7 +403,7 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+	e->size = dev->cfg_size;
 
 	return 0;
 }
--- diff/drivers/s390/char/tape_core.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/char/tape_core.c	2004-02-18 09:04:00.000000000 +0000
@@ -81,7 +81,7 @@
 	struct tape_device *tdev;
 
 	tdev = (struct tape_device *) dev->driver_data;
-	return snprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state);
+	return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state);
 }
 
 static
@@ -93,7 +93,7 @@
 	struct tape_device *tdev;
 
 	tdev = (struct tape_device *) dev->driver_data;
-	return snprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor);
+	return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor);
 }
 
 static
@@ -105,7 +105,7 @@
 	struct tape_device *tdev;
 
 	tdev = (struct tape_device *) dev->driver_data;
-	return snprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ?
+	return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ?
 		"OFFLINE" : tape_state_verbose[tdev->tape_state]);
 }
 
@@ -120,17 +120,17 @@
 
 	tdev = (struct tape_device *) dev->driver_data;
 	if (tdev->first_minor < 0)
-		return snprintf(buf, PAGE_SIZE, "N/A\n");
+		return scnprintf(buf, PAGE_SIZE, "N/A\n");
 
 	spin_lock_irq(get_ccwdev_lock(tdev->cdev));
 	if (list_empty(&tdev->req_queue))
-		rc = snprintf(buf, PAGE_SIZE, "---\n");
+		rc = scnprintf(buf, PAGE_SIZE, "---\n");
 	else {
 		struct tape_request *req;
 
 		req = list_entry(tdev->req_queue.next, struct tape_request,
 			list);
-		rc = snprintf(buf, PAGE_SIZE, "%s\n", tape_op_verbose[req->op]);
+		rc = scnprintf(buf,PAGE_SIZE, "%s\n", tape_op_verbose[req->op]);
 	}
 	spin_unlock_irq(get_ccwdev_lock(tdev->cdev));
 	return rc;
@@ -146,7 +146,7 @@
 
 	tdev = (struct tape_device *) dev->driver_data;
 
-	return snprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size);
+	return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size);
 }
 
 static
--- diff/drivers/s390/cio/device.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/cio/device.c	2004-02-18 09:04:00.000000000 +0000
@@ -73,7 +73,7 @@
 	/* what we want to pass to /sbin/hotplug */
 
 	envp[i++] = buffer;
-	length += snprintf(buffer, buffer_size - length, "CU_TYPE=%04X",
+	length += scnprintf(buffer, buffer_size - length, "CU_TYPE=%04X",
 			   cdev->id.cu_type);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
@@ -81,7 +81,7 @@
 	buffer += length;
 
 	envp[i++] = buffer;
-	length += snprintf(buffer, buffer_size - length, "CU_MODEL=%02X",
+	length += scnprintf(buffer, buffer_size - length, "CU_MODEL=%02X",
 			   cdev->id.cu_model);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
@@ -90,7 +90,7 @@
 
 	/* The next two can be zero, that's ok for us */
 	envp[i++] = buffer;
-	length += snprintf(buffer, buffer_size - length, "DEV_TYPE=%04X",
+	length += scnprintf(buffer, buffer_size - length, "DEV_TYPE=%04X",
 			   cdev->id.dev_type);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
@@ -98,7 +98,7 @@
 	buffer += length;
 
 	envp[i++] = buffer;
-	length += snprintf(buffer, buffer_size - length, "DEV_MODEL=%02X",
+	length += scnprintf(buffer, buffer_size - length, "DEV_MODEL=%02X",
 			   cdev->id.dev_model);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
 		return -ENOMEM;
--- diff/drivers/s390/net/ctctty.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/net/ctctty.c	2004-02-18 09:04:00.000000000 +0000
@@ -655,14 +655,19 @@
 }
 
 
-static int
-ctc_tty_get_ctc_tty_info(ctc_tty_info * info, uint * value)
+static int ctc_tty_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 	u_char control,
 	 status;
 	uint result;
 	ulong flags;
 
+	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
 	control = info->mcr;
 	spin_lock_irqsave(&ctc_tty_lock, flags);
 	status = info->msr;
@@ -673,51 +678,31 @@
 	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
 	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
 	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	put_user(result, (uint *) value);
-	return 0;
+	return result;
 }
 
 static int
-ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
+ctc_tty_tiocmset(struct tty_struct *tty, struct file *file,
+		 unsigned int set, unsigned int clear)
 {
-	uint arg;
-	int old_mcr = info->mcr & (UART_MCR_RTS | UART_MCR_DTR);
+	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 
-	get_user(arg, (uint *) value);
-	switch (cmd) {
-		case TIOCMBIS:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			if (arg & TIOCM_RTS)
-				info->mcr |= UART_MCR_RTS;
-			if (arg & TIOCM_DTR)
-				info->mcr |= UART_MCR_DTR;
-			break;
-		case TIOCMBIC:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			if (arg & TIOCM_RTS)
-				info->mcr &= ~UART_MCR_RTS;
-			if (arg & TIOCM_DTR)
-				info->mcr &= ~UART_MCR_DTR;
-			break;
-		case TIOCMSET:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCMSET\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
-				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-			       | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-			break;
-		default:
-			return -EINVAL;
-	}
-	if ((info->mcr  & (UART_MCR_RTS | UART_MCR_DTR)) != old_mcr)
+	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+	if (set & TIOCM_RTS)
+		info->mcr |= UART_MCR_RTS;
+	if (set & TIOCM_DTR)
+		info->mcr |= UART_MCR_DTR;
+
+	if (clear & TIOCM_RTS)
+		info->mcr &= ~UART_MCR_RTS;
+	if (clear & TIOCM_DTR)
+		info->mcr &= ~UART_MCR_DTR;
+
+	if ((set | clear) & (TIOCM_RTS|TIOCM_DTR))
 		ctc_tty_transmit_status(info);
 	return 0;
 }
@@ -772,22 +757,6 @@
 			    ((tty->termios->c_cflag & ~CLOCAL) |
 			     (arg ? CLOCAL : 0));
 			return 0;
-		case TIOCMGET:
-#ifdef CTC_DEBUG_MODEM_IOCTL
-			printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME,
-			       info->line);
-#endif
-			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-			if (error)
-				return error;
-			return ctc_tty_get_ctc_tty_info(info, (uint *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
-			if (error)
-				return error;
-			return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg);
 		case TIOCSERGETLSR:	/* Get line status register */
 #ifdef CTC_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
@@ -1139,6 +1108,8 @@
 	.unthrottle = ctc_tty_unthrottle,
 	.set_termios = ctc_tty_set_termios,
 	.hangup = ctc_tty_hangup,
+	.tiocmget = ctc_tty_tiocmget,
+	.tiocmset = ctc_tty_tiocmset,
 };
 
 int
--- diff/drivers/s390/net/lcs.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/net/lcs.c	2004-02-18 09:04:00.000000000 +0000
@@ -360,7 +360,7 @@
 		kfree(ipm_list);
 	}
 #endif
-	kfree(card->dev);
+	free_netdev(card->dev);
 	/* Cleanup channels. */
 	lcs_cleanup_channel(&card->write);
 	lcs_cleanup_channel(&card->read);
@@ -1858,8 +1858,7 @@
 	lcs_stopcard(card);
 	return 0;
 out:
-	lcs_cleanup_channel(&card->read);
-	lcs_cleanup_channel(&card->write);
+	lcs_cleanup_card(card);
 	lcs_free_card(card);
 	return -ENODEV;
 }
--- diff/drivers/s390/net/netiucv.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/s390/net/netiucv.c	2004-02-18 09:04:00.000000000 +0000
@@ -1473,6 +1473,14 @@
 	sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
 }
 
+/*
+ * XXX: Don't use sysfs unless you know WTF you are doing.
+ * This particular turd registers sysfs objects embedded into netiucv_priv
+ * which is kfreed without any regard to possible sysfs references.
+ * As the result, the wanker who'd decided that sysfs exports were too hip and
+ * cute to resist had generated a set of user-exploitable holes in this driver.
+ */
+
 static int
 netiucv_register_device(struct net_device *ndev, int ifno)
 {
@@ -1592,6 +1600,22 @@
 	}
 }
 
+static void setup_netiucv(struct net_device *dev)
+{
+	dev->mtu	         = NETIUCV_MTU_DEFAULT;
+	dev->hard_start_xmit     = netiucv_tx;
+	dev->open	         = netiucv_open;
+	dev->stop	         = netiucv_close;
+	dev->get_stats	         = netiucv_stats;
+	dev->change_mtu          = netiucv_change_mtu;
+	dev->hard_header_len     = NETIUCV_HDRLEN;
+	dev->addr_len            = 0;
+	dev->type                = ARPHRD_SLIP;
+	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
+	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
+	SET_MODULE_OWNER(dev);
+}
+
 /**
  * Allocate and initialize everything of a net device.
  */
@@ -1601,16 +1625,15 @@
 	struct netiucv_priv *privptr;
 	int          priv_size;
 
-	struct net_device *dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	struct net_device *dev = alloc_netdev(0, "", setup_netiucv);
 	if (!dev)
 		return NULL;
-	memset(dev, 0, sizeof(struct net_device));
 	sprintf(dev->name, "iucv%d", ifno);
 
 	priv_size = sizeof(struct netiucv_priv);
 	dev->priv = kmalloc(priv_size, GFP_KERNEL);
 	if (dev->priv == NULL) {
-		kfree(dev);
+		free_netdev(dev);
 		return NULL;
 	}
         memset(dev->priv, 0, priv_size);
@@ -1620,30 +1643,18 @@
 				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
 	if (privptr->fsm == NULL) {
 		kfree(privptr);
-		kfree(dev);
+		free_netdev(dev);
 		return NULL;
 	}
 	privptr->conn = netiucv_new_connection(dev, username);
 	if (!privptr->conn) {
 		kfree_fsm(privptr->fsm);
 		kfree(privptr);
-		kfree(dev);
+		free_netdev(dev);
 		return NULL;
 	}
 
 	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-	dev->mtu	         = NETIUCV_MTU_DEFAULT;
-	dev->hard_start_xmit     = netiucv_tx;
-	dev->open	         = netiucv_open;
-	dev->stop	         = netiucv_close;
-	dev->get_stats	         = netiucv_stats;
-	dev->change_mtu          = netiucv_change_mtu;
-	dev->hard_header_len     = NETIUCV_HDRLEN;
-	dev->addr_len            = 0;
-	dev->type                = ARPHRD_SLIP;
-	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
-	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
-	SET_MODULE_OWNER(dev);
 	return dev;
 }
 
--- diff/drivers/s390/net/qeth.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/s390/net/qeth.c	2004-02-18 09:04:00.000000000 +0000
@@ -6707,15 +6707,6 @@
 }
 
 static void
-qeth_destructor(struct net_device *dev)
-{
-	struct qeth_card *card;
-
-	card = (struct qeth_card *) (dev->priv);
-	QETH_DBF_CARD2(0, trace, "dstr", card);
-}
-
-static void
 qeth_set_multicast_list(struct net_device *dev)
 {
 	struct qeth_card *card = dev->priv;
@@ -7655,28 +7646,11 @@
 
 	QETH_DBF_CARD3(0, trace, "inid", card);
 
-	dev->tx_timeout = &qeth_tx_timeout;
-	dev->watchdog_timeo = QETH_TX_TIMEOUT;
-	dev->open = qeth_open;
-	dev->stop = qeth_stop;
-	dev->set_config = qeth_set_config;
-	dev->hard_start_xmit = qeth_hard_start_xmit;
-	dev->do_ioctl = qeth_do_ioctl;
-	dev->get_stats = qeth_get_stats;
-	dev->change_mtu = qeth_change_mtu;
-#ifdef QETH_VLAN
-	dev->vlan_rx_register = qeth_vlan_rx_register;
-	dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
-#endif
 	dev->rebuild_header = __qeth_rebuild_header_func(card);
 	dev->hard_header = __qeth_hard_header_func(card);
 	dev->header_cache_update = __qeth_header_cache_update_func(card);
 	dev->hard_header_cache = __qeth_hard_header_cache_func(card);
 	dev->hard_header_parse = NULL;
-	dev->destructor = qeth_destructor;
-	dev->set_multicast_list = qeth_set_multicast_list;
-	dev->set_mac_address = qeth_set_mac_address;
-	dev->neigh_setup = qeth_neigh_setup;
 
 	dev->flags |= qeth_get_additional_dev_flags(card->type);
 
@@ -7694,8 +7668,6 @@
 	dev->tx_queue_len = qeth_get_device_tx_q_len(card->type);
 	dev->hard_header_len =
 		qeth_get_hlen(card->link_type) + card->options.add_hhlen;
-	dev->addr_len = OSA_ADDR_LEN;	/* is ok for eth, tr, atm lane */
-	SET_MODULE_OWNER(dev);
 	netif_start_queue(dev);
 
 	dev->mtu = card->initial_mtu;
@@ -8358,6 +8330,28 @@
 	card->options.fake_ll = DONT_FAKE_LL;
 }
 
+static void qeth_setup(struct net_device *dev)
+{
+	dev->tx_timeout = &qeth_tx_timeout;
+	dev->watchdog_timeo = QETH_TX_TIMEOUT;
+	dev->open = qeth_open;
+	dev->stop = qeth_stop;
+	dev->set_config = qeth_set_config;
+	dev->hard_start_xmit = qeth_hard_start_xmit;
+	dev->do_ioctl = qeth_do_ioctl;
+	dev->get_stats = qeth_get_stats;
+	dev->change_mtu = qeth_change_mtu;
+#ifdef QETH_VLAN
+	dev->vlan_rx_register = qeth_vlan_rx_register;
+	dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
+#endif
+	dev->set_multicast_list = qeth_set_multicast_list;
+	dev->set_mac_address = qeth_set_mac_address;
+	dev->neigh_setup = qeth_neigh_setup;
+	dev->addr_len = OSA_ADDR_LEN;	/* is ok for eth, tr, atm lane */
+	SET_MODULE_OWNER(dev);
+}
+
 static int
 qeth_alloc_card_stuff(struct qeth_card *card)
 {
@@ -8385,11 +8379,9 @@
 		goto exit_dma2;
 	memset(card->dma_stuff->sendbuf, 0, QETH_BUFSIZE);
 
-	card->dev = (struct net_device *) kmalloc(sizeof (struct net_device),
-						  GFP_KERNEL);
+	card->dev = alloc_netdev(0, "", qeth_setup);
 	if (!card->dev)
 		goto exit_dev;
-	memset(card->dev, 0, sizeof (struct net_device));
 
 	card->stats =
 	    (struct net_device_stats *)
--- diff/drivers/sbus/char/aurora.c	2003-06-30 10:07:22.000000000 +0100
+++ source/drivers/sbus/char/aurora.c	2004-02-18 09:04:00.000000000 +0000
@@ -1752,8 +1752,9 @@
 #endif
 }
 
-static int aurora_get_modem_info(struct Aurora_port * port, unsigned int *value)
+static int aurora_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
 	struct Aurora_board * bp;
 	unsigned char status,chip;
 	unsigned int result;
@@ -1762,6 +1763,9 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_get_modem_info: start\n");
 #endif
+	if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
 	chip = AURORA_CD180(port_No(port));
 
 	bp = port_Board(port);
@@ -1782,16 +1786,16 @@
 		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
 		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
 
-	put_user(result,(unsigned long *) value);
 #ifdef AURORA_DEBUG
 	printk("aurora_get_modem_info: end\n");
 #endif
-	return 0;
+	return result;
 }
 
-static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
-				 unsigned int *value)
+static int aurora_tiocmset(struct tty_struct *tty, struct file *file,
+			   unsigned int set, unsigned int clear)
 {
+	struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
 	unsigned int arg;
 	unsigned long flags;
 	struct Aurora_board *bp = port_Board(port);
@@ -1800,33 +1804,20 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_set_modem_info: start\n");
 #endif
-	if (get_user(arg, value))
-		return -EFAULT;
+	if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
+		return -ENODEV;
+
 	chip = AURORA_CD180(port_No(port));
-	switch (cmd) {
-	 case TIOCMBIS: 
-		if (arg & TIOCM_RTS) 
-			port->MSVR |= bp->RTS;
-		if (arg & TIOCM_DTR)
-			port->MSVR |= bp->DTR;
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			port->MSVR &= ~bp->RTS;
-		if (arg & TIOCM_DTR)
-			port->MSVR &= ~bp->DTR;
-		break;
-	case TIOCMSET:
-		port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | bp->RTS) : 
-					         (port->MSVR & ~bp->RTS);
-		port->MSVR = (arg & TIOCM_DTR) ? (port->MSVR | bp->RTS) :
-						 (port->MSVR & ~bp->RTS);
-		break;
-	 default:
-		return -EINVAL;
-	};
 
 	save_flags(flags); cli();
+	if (set & TIOCM_RTS)
+		port->MSVR |= bp->RTS;
+	if (set & TIOCM_DTR)
+		port->MSVR |= bp->DTR;
+	if (clear & TIOCM_RTS)
+		port->MSVR &= ~bp->RTS;
+	if (clear & TIOCM_DTR)
+		port->MSVR &= ~bp->DTR;
 
 	sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
 	udelay(1);
@@ -1993,16 +1984,6 @@
 			((tty->termios->c_cflag & ~CLOCAL) |
 			 (arg ? CLOCAL : 0));
 		return 0;
-	case TIOCMGET:
-		retval = verify_area(VERIFY_WRITE, (void *) arg,
-				    sizeof(unsigned int));
-		if (retval)
-			return retval;
-		return aurora_get_modem_info(port, (unsigned int *) arg);
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return aurora_set_modem_info(port, cmd, (unsigned int *) arg);
 	case TIOCGSERIAL:	
 		return aurora_get_serial_info(port, (struct serial_struct *) arg);
 	case TIOCSSERIAL:	
@@ -2268,6 +2249,8 @@
 	.stop = aurora_stop,
 	.start = aurora_start,
 	.hangup = aurora_hangup,
+	.tiocmget = aurora_tiocmget,
+	.tiocmset = aurora_tiocmset,
 };
 
 static int aurora_init_drivers(void)
--- diff/drivers/scsi/Kconfig	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/Kconfig	2004-02-18 09:04:00.000000000 +0000
@@ -55,6 +55,14 @@
 	  In this case, do not compile the driver for your SCSI host adapter
 	  (below) as a module either.
 
+config MAX_SD_DISKS
+	int "Maximum number of SCSI disks to support (256-8192)"
+	depends on BLK_DEV_SD
+	default "256"
+	help
+	The maximum number SCSI disks to support. Default is 256.
+	Change this value if you want kernel to support lots of SCSI devices.
+
 config CHR_DEV_ST
 	tristate "SCSI tape support"
 	depends on SCSI
--- diff/drivers/scsi/aacraid/Makefile	2002-12-16 09:26:06.000000000 +0000
+++ source/drivers/scsi/aacraid/Makefile	2004-02-18 09:04:00.000000000 +0000
@@ -3,6 +3,6 @@
 obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
 
 aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
-		   dpcsup.o rx.o sa.o
+		   dpcsup.o rx.o sa.o rkt.o
 
 EXTRA_CFLAGS	:= -Idrivers/scsi
--- diff/drivers/scsi/aacraid/aacraid.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/aacraid/aacraid.h	2004-02-18 09:04:00.000000000 +0000
@@ -713,6 +713,24 @@
 #define rx_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rx->CSR))
 #define rx_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rx->CSR))
 
+/*
+ *	Rkt Message Unit Registers (same as Rx, except a larger reserve region)
+ */
+
+#define rkt_mu_registers rx_mu_registers
+#define rkt_inbound rx_inbound
+
+struct rkt_registers {
+	struct rkt_mu_registers		MUnit;		 /* 1300h - 1334h */
+	u32				reserved1[1010]; /* 1338h - 22fch */
+	struct rkt_inbound		IndexRegs;	 /* 2300h - */
+};
+
+#define rkt_readb(AEP, CSR)		readb(&((AEP)->regs.rkt->CSR))
+#define rkt_readl(AEP, CSR)		readl(&((AEP)->regs.rkt->CSR))
+#define rkt_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rkt->CSR))
+#define rkt_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rkt->CSR))
+
 struct fib;
 
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
@@ -889,7 +907,9 @@
 	{
 		struct sa_registers *sa;
 		struct rx_registers *rx;
+		struct rkt_registers *rkt;
 	} regs;
+	u32			OIMR; /* Mask Register Cache */
 	/*
 	 *	The following is the number of the individual adapter
 	 */
@@ -1492,6 +1512,7 @@
 int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg);
 int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg);
 int aac_rx_init(struct aac_dev *dev, unsigned long devNumber);
+int aac_rkt_init(struct aac_dev *dev, unsigned long devNumber);
 int aac_sa_init(struct aac_dev *dev, unsigned long devNumber);
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
--- diff/drivers/scsi/aacraid/linit.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/aacraid/linit.c	2004-02-18 09:04:00.000000000 +0000
@@ -101,14 +101,20 @@
 	{ 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/
 	{ 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/
-	{ 0x9005, 0x0250, 0x1014, 0x0279, 0, 0, 21 }, /* (Marco)*/
-	{ 0x9005, 0x0250, 0x1014, 0x028c, 0, 0, 22 }, /* (Sebring)*/
 
-	{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 23 }, /* Perc 320/DC*/
-	{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 24 }, /* Adaptec 5400S (Mustang)*/
-	{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 25 }, /* Adaptec 5400S (Mustang)*/
-	{ 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 26 }, /* Dell PERC2 "Quad Channel" */
-	{ 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 27 }, /* HP NetRAID-4M */
+	{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/
+	{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 22 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 23 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 24 }, /* Dell PERC2 "Quad Channel" */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 25 }, /* HP NetRAID-4M */
+
+	{ 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 26 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 27 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 28 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 29 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */
+
+	{ 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
 	{ 0,}
 };
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -141,14 +147,20 @@
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, /* (Marco)*/
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, /* (Sebring)*/
 
 	{ aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/
 	{ aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_31BIT }, /* Dell PERC2 "Quad Channel" */
-	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 }  /* HP NetRAID-4M */
+	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 },  /* HP NetRAID-4M */
+
+	{ aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "SO-DIMM SATA ZCR", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "SATA 6Channel   ", 1 }, /* SATA 6Ch (Bearcat) */
+
+	{ aac_rkt_init,"aacraid",  "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
 };
 
 /**
--- diff/drivers/scsi/aacraid/rx.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/aacraid/rx.c	2004-02-18 09:04:00.000000000 +0000
@@ -56,7 +56,7 @@
 	 *	This allows us to only service interrupts that have 
 	 *	been enabled.
 	 */
-	mask = ~(rx_readb(dev, MUnit.OIMR));
+	mask = ~(dev->OIMR);
 	/* Check to see if this is our interrupt.  If it isn't just return */
 	if (intstat & mask) 
 	{
@@ -179,7 +179,7 @@
 	/*
 	 *	Disable doorbell interrupts
 	 */
-	rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04);
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR |= 0x04);
 	/*
 	 *	Force the completion of the mask register write before issuing
 	 *	the interrupt.
@@ -220,7 +220,7 @@
 		/*
 		 *	Restore interrupt mask even though we timed out
 		 */
-		rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
+		rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
 		return -ETIMEDOUT;
 	}
 	/*
@@ -234,7 +234,7 @@
 	/*
 	 *	Restore interrupt mask
 	 */
-	rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
 	return 0;
 
 }
@@ -318,7 +318,7 @@
 	rx_writeb(dev, MUnit.OIMR, 0xff);
 	rx_writel(dev, MUnit.ODR, 0xffffffff);
 //	rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
-	rx_writeb(dev, MUnit.OIMR, 0xfb);
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
 
 	// We can only use a 32 bit address here
 	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
--- diff/drivers/scsi/aic7xxx/aic79xx_osm.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/aic7xxx/aic79xx_osm.c	2004-02-18 09:04:00.000000000 +0000
@@ -452,14 +452,14 @@
 "	seltime:<int>		Selection Timeout:\n"
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "\n"
-"	Sample /etc/modules.conf line:\n"
+"	Sample /etc/modprobe.conf line:\n"
 "		Enable verbose logging\n"
 "		Set tag depth on Controller 2/Target 2 to 10 tags\n"
 "		Shorten the selection timeout to 128ms\n"
 "\n"
 "	options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
 "\n"
-"	Sample /etc/modules.conf line:\n"
+"	Sample /etc/modprobe.conf line:\n"
 "		Change Read Streaming for Controller's 2 and 3\n"
 "\n"
 "	options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'");
--- diff/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-02-18 09:04:00.000000000 +0000
@@ -472,7 +472,7 @@
 "	seltime:<int>		Selection Timeout\n"
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "\n"
-"	Sample /etc/modules.conf line:\n"
+"	Sample /etc/modprobe.conf line:\n"
 "		Toggle EISA/VLB probing\n"
 "		Set tag depth on Controller 1/Target 1 to 10 tags\n"
 "		Shorten the selection timeout to 128ms\n"
@@ -3969,11 +3969,10 @@
 }
 
 static void
-ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct ahc_linux_target *targ;
 
-	del_timer_sync(&dev->timer);
 	targ = dev->target;
 	targ->devices[dev->lun] = NULL;
 	free(dev, M_DEVBUF);
@@ -3983,6 +3982,13 @@
 		ahc_linux_free_target(ahc, targ);
 }
 
+static void
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	del_timer_sync(&dev->timer);
+	__ahc_linux_free_device(ahc, dev);
+}
+
 void
 ahc_send_async(struct ahc_softc *ahc, char channel,
 	       u_int target, u_int lun, ac_code code, void *arg)
@@ -4693,7 +4699,7 @@
 		ahc_linux_run_device_queue(ahc, dev);
 	if (TAILQ_EMPTY(&dev->busyq)
 	 && dev->active == 0)
-		ahc_linux_free_device(ahc, dev);
+		__ahc_linux_free_device(ahc, dev);
 	ahc_unlock(ahc, &s);
 }
 
--- diff/drivers/scsi/qla1280.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/qla1280.c	2004-02-18 09:04:00.000000000 +0000
@@ -348,7 +348,6 @@
 #include <asm/system.h>
 
 #if LINUX_VERSION_CODE >= 0x020545
-#include <asm/cacheflush.h>	/* for flush_cache_all() */
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -2123,8 +2122,6 @@
 			((uint16_t *)ha->request_ring)[i] =
 				cpu_to_le16(risc_code_address[i]);
 
-		flush_cache_all();
-
 		mb[0] = MBC_LOAD_RAM;
 		mb[1] = risc_address;
 		mb[4] = cnt;
--- diff/drivers/scsi/qla2xxx/qla_os.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/qla2xxx/qla_os.c	2004-02-18 09:04:00.000000000 +0000
@@ -70,7 +70,7 @@
 int displayConfig;
 module_param(displayConfig, int, 0);
 MODULE_PARM_DESC(displayConfig,
-		"If 1 then display the configuration used in /etc/modules.conf.");
+		"If 1 then display the configuration used in /etc/modprobe.conf.");
 
 int ql2xplogiabsentdevice;
 module_param(ql2xplogiabsentdevice, int, 0);
--- diff/drivers/scsi/scsi.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/scsi/scsi.c	2004-02-18 09:04:00.000000000 +0000
@@ -22,7 +22,7 @@
  *  support added by Michael Neuffer <mike@i-connect.net>
  *
  *  Added request_module("scsi_hostadapter") for kerneld:
- *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/modules.conf)
+ *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/modprobe.conf)
  *  Bjorn Ekwall  <bj0rn@blox.se>
  *  (changed to kmod)
  *
@@ -53,6 +53,8 @@
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
 
 #include <scsi/scsi_host.h>
 #include "scsi.h"
@@ -1129,6 +1131,38 @@
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int scsi_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+
+	switch(action) {
+	case CPU_DEAD:
+		/* Drain scsi_done_q. */
+		local_irq_disable();
+		list_splice_init(&per_cpu(scsi_done_q, cpu),
+				 &__get_cpu_var(scsi_done_q));
+		raise_softirq_irqoff(SCSI_SOFTIRQ);
+		local_irq_enable();
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata scsi_cpu_nb = {
+	.notifier_call	= scsi_cpu_notify,
+};
+
+#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
+#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
+#else
+#define register_scsi_cpu()
+#define unregister_scsi_cpu()
+#endif /* CONFIG_HOTPLUG_CPU */
+
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
@@ -1163,6 +1197,7 @@
 
 	devfs_mk_dir("scsi");
 	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
+	register_scsi_cpu();
 	printk(KERN_NOTICE "SCSI subsystem initialized\n");
 	return 0;
 
@@ -1190,6 +1225,7 @@
 	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
+	unregister_scsi_cpu();
 }
 
 subsys_initcall(init_scsi);
--- diff/drivers/scsi/scsi_debug.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/scsi/scsi_debug.c	2004-02-18 09:04:00.000000000 +0000
@@ -557,8 +557,7 @@
 		
 		dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
 			     (devip->target * 1000) + devip->lun;
-		len = snprintf(dev_id_str, 6, "%d", dev_id_num);
-		len = (len > 6) ? 6 : len;
+		len = scnprintf(dev_id_str, 6, "%d", dev_id_num);
 		if (0 == cmd[2]) { /* supported vital product data pages */
 			arr[3] = 3;
 			arr[4] = 0x0; /* this page */
@@ -1309,7 +1308,7 @@
 
 static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
 }
 
 static ssize_t sdebug_delay_store(struct device_driver * ddp, 
@@ -1331,7 +1330,7 @@
 
 static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
+        return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
 }
 
 static ssize_t sdebug_opts_store(struct device_driver * ddp, 
@@ -1360,7 +1359,7 @@
 
 static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
 }
 static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 
 				     const char * buf, size_t count)
@@ -1378,13 +1377,13 @@
 
 static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
 }
 DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL) 
 
 static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
 }
 static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 
 				      const char * buf, size_t count)
@@ -1403,7 +1402,7 @@
 
 static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
 }
 static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 
 				     const char * buf, size_t count)
@@ -1421,13 +1420,13 @@
 
 static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
 }
 DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL) 
 
 static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 
 {
-        return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
 }
 
 static ssize_t sdebug_add_host_store(struct device_driver * ddp, 
--- diff/drivers/scsi/sd.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/scsi/sd.c	2004-02-18 09:04:01.000000000 +0000
@@ -62,6 +62,7 @@
  */
 #define SD_MAJORS	16
 #define SD_DISKS	(SD_MAJORS << 4)
+#define TOTAL_SD_DISKS	CONFIG_MAX_SD_DISKS
 
 /*
  * Time out in seconds for disks and Magneto-opticals (which are slower).
@@ -95,7 +96,7 @@
 };
 
 
-static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG];
+static unsigned long sd_index_bits[TOTAL_SD_DISKS / BITS_PER_LONG];
 static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
 
 static int sd_revalidate_disk(struct gendisk *disk);
@@ -130,6 +131,9 @@
 		return SCSI_DISK1_MAJOR + major_idx - 1;
 	case 8 ... 15:
 		return SCSI_DISK8_MAJOR + major_idx - 8;
+#define MAX_IDX        (TOTAL_SD_DISKS >> 4)
+	case 16 ... MAX_IDX:
+		return SCSI_DISK15_MAJOR;
 	default:
 		BUG();
 		return 0;	/* shut up gcc */
@@ -1322,8 +1326,8 @@
 		goto out_free;
 
 	spin_lock(&sd_index_lock);
-	index = find_first_zero_bit(sd_index_bits, SD_DISKS);
-	if (index == SD_DISKS) {
+	index = find_first_zero_bit(sd_index_bits, TOTAL_SD_DISKS);
+	if (index == TOTAL_SD_DISKS) {
 		spin_unlock(&sd_index_lock);
 		error = -EBUSY;
 		goto out_put;
@@ -1338,15 +1342,24 @@
 	sdkp->openers = 0;
 
 	gd->major = sd_major(index >> 4);
-	gd->first_minor = (index & 15) << 4;
+	if (index > SD_DISKS)
+		gd->first_minor = ((index - SD_DISKS) & 15) << 4;
+	else
+		gd->first_minor = (index & 15) << 4;
 	gd->minors = 16;
 	gd->fops = &sd_fops;
 
-	if (index >= 26) {
+	if (index < 26) {
+		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+	} else if (index < (26*27)) {
 		sprintf(gd->disk_name, "sd%c%c",
 			'a' + index/26-1,'a' + index % 26);
 	} else {
-		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+		const unsigned int m1 = (index/ 26 - 1) / 26 - 1;
+		const unsigned int m2 = (index / 26 - 1) % 26;
+		const unsigned int m3 = index % 26;
+		sprintf(gd->disk_name, "sd%c%c%c",
+			'a' + m1, 'a' + m2, 'a' + m3);
 	}
 
 	strcpy(gd->devfs_name, sdp->devfs_name);
--- diff/drivers/serial/68360serial.c	2003-06-30 10:07:23.000000000 +0100
+++ source/drivers/serial/68360serial.c	2004-02-18 09:04:01.000000000 +0000
@@ -1282,12 +1282,19 @@
 }
 #endif
 
-static int get_modem_info(ser_info_t *info, unsigned int *value)
+static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
 	unsigned int result = 0;
 #ifdef modem_control
 	unsigned char control, status;
 
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
 	control = info->MCR;
 	local_irq_disable();
 	status = serial_in(info, UART_MSR);
@@ -1303,63 +1310,42 @@
 		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
 		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
 #endif
-	/* return put_user(result,value); */
-	put_user(result,value);
-	return (0);
+	return result;
 }
 
-static int set_modem_info(ser_info_t *info, unsigned int cmd,
-			  unsigned int *value)
+static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
+			   unsigned int set, unsigned int clear)
 {
-	int error;
- 	unsigned int arg; 
-
-	error = get_user(arg,value);
-	if (error)
-		return error;
 #ifdef modem_control
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS)
-			info->MCR |= UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR |= UART_MCR_DTR;
-#ifdef TIOCM_OUT1
-		if (arg & TIOCM_OUT1)
-			info->MCR |= UART_MCR_OUT1;
-		if (arg & TIOCM_OUT2)
-			info->MCR |= UART_MCR_OUT2;
-#endif
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			info->MCR &= ~UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR &= ~UART_MCR_DTR;
-#ifdef TIOCM_OUT1
-		if (arg & TIOCM_OUT1)
-			info->MCR &= ~UART_MCR_OUT1;
-		if (arg & TIOCM_OUT2)
-			info->MCR &= ~UART_MCR_OUT2;
-#endif
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
-#ifdef TIOCM_OUT1
-					    UART_MCR_OUT1 |
-					    UART_MCR_OUT2 |
-#endif
-					    UART_MCR_DTR))
-			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+ 	unsigned int arg;
+
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+ 	if (set & TIOCM_RTS)
+ 		info->mcr |= UART_MCR_RTS;
+ 	if (set & TIOCM_DTR)
+ 		info->mcr |= UART_MCR_DTR;
+	if (clear & TIOCM_RTS)
+		info->MCR &= ~UART_MCR_RTS;
+	if (clear & TIOCM_DTR)
+		info->MCR &= ~UART_MCR_DTR;
+
 #ifdef TIOCM_OUT1
-			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
-			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+	if (set & TIOCM_OUT1)
+		info->MCR |= UART_MCR_OUT1;
+	if (set & TIOCM_OUT2)
+		info->MCR |= UART_MCR_OUT2;
+	if (clear & TIOCM_OUT1)
+		info->MCR &= ~UART_MCR_OUT1;
+	if (clear & TIOCM_OUT2)
+		info->MCR &= ~UART_MCR_OUT2;
 #endif
-			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		break;
-	default:
-		return -EINVAL;
-	}
+
 	local_irq_disable();
 	serial_out(info, UART_MCR, info->MCR);
 	local_irq_enable();
@@ -1506,12 +1492,6 @@
 				((tty->termios->c_cflag & ~CLOCAL) |
 				 (arg ? CLOCAL : 0));
 			return 0;
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
 #ifdef maybe
 		case TIOCSERGETLSR: /* Get line status register */
 			return get_lsr_info(info, (unsigned int *) arg);
@@ -2513,6 +2493,8 @@
 	.hangup = rs_360_hangup,
 	/* .wait_until_sent = rs_360_wait_until_sent, */
 	/* .read_proc = rs_360_read_proc, */
+	.tiocmget = rs_360_tiocmget,
+	.tiocmset = rs_360_tiocmset,
 };
 
 /* int __init rs_360_init(void) */
--- diff/drivers/serial/8250.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/serial/8250.c	2004-02-18 09:04:01.000000000 +0000
@@ -837,7 +837,7 @@
 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
 			tty->flip.work.func((void *)tty);
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-				return; // if TTY_DONT_FLIP is set
+				return;	/* if TTY_DONT_FLIP is set */
 		}
 		ch = serial_inp(up, UART_RX);
 		*tty->flip.char_buf_ptr = ch;
@@ -1198,12 +1198,21 @@
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#ifdef CONFIG_KGDB
+static int kgdb_irq = -1;
+#endif
+
 static int serial8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
 	int retval;
 
+#ifdef CONFIG_KGDB
+	if (up->port.irq == kgdb_irq)
+		return -EBUSY;
+#endif
+
 	up->capabilities = uart_config[up->port.type].flags;
 
 	if (up->port.type == PORT_16C950) {
@@ -1869,6 +1878,10 @@
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
+#ifdef CONFIG_KGDB
+		if (up->port.irq == kgdb_irq)
+			up->port.kgdb = 1;
+#endif
 		up->port.line = i;
 		up->port.ops = &serial8250_pops;
 		init_timer(&up->timer);
@@ -2138,6 +2151,31 @@
 	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * Find all the ports using the given irq and shut them down.
+ * Result should be that the irq will be released.
+ */
+void shutdown_for_kgdb(struct async_struct * info)
+{
+        int irq = info->state->irq;
+        struct uart_8250_port *up;
+	int ttyS;
+
+	kgdb_irq = irq;			/* save for later init */
+	for (ttyS = 0; ttyS < UART_NR; ttyS++){
+		up =  &serial8250_ports[ttyS];
+		if (up->port.irq == irq && (irq_lists + irq)->head) {
+#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
+			if(up->port.lock.magic != SPINLOCK_MAGIC)
+				spin_lock_init(&up->port.lock);
+#endif
+			serial8250_shutdown(&up->port);
+		}
+        }
+}
+#endif	/* CONFIG_KGDB */
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
--- diff/drivers/serial/Kconfig	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/serial/Kconfig	2004-02-18 09:04:01.000000000 +0000
@@ -256,6 +256,27 @@
 	help
 	  ::: To be written :::
 
+config SERIAL_DZ
+	bool "DECstation DZ serial driver"
+	depends on DECSTATION
+	select SERIAL_CORE
+	help
+	  DZ11-family serial controllers for VAXstations, including the
+	  DC7085, M7814, and M7819.
+
+config SERIAL_DZ_CONSOLE
+	bool "Support console on DECstation DZ serial driver"
+	depends on SERIAL_DZ=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you say Y here, it will be possible to use a serial port as the
+	  system console (the system console is the device which receives all
+	  kernel messages and warnings and which allows logins in single user
+	  mode).  Note that the firmware uses ttyS0 as the serial console on
+	  the Maxine and ttyS2 on the others.
+
+	  If unsure, say Y.
+
 config SERIAL_21285
 	tristate "DC21285 serial port support"
 	depends on ARM && FOOTBRIDGE
@@ -422,6 +443,20 @@
 	  on your Sparc system as the console, you can do so by answering
 	  Y to this option.
 
+config SERIAL_IP22_ZILOG
+	tristate "IP22 Zilog8530 serial support"
+	depends on SGI_IP22
+	select SERIAL_CORE
+	help
+	  This driver supports the Zilog8530 serial ports found on SGI IP22
+	  systems.  Say Y or M if you want to be able to these serial ports.
+
+config SERIAL_IP22_ZILOG_CONSOLE
+	bool "Console on IP22 Zilog8530 serial port"
+	depends on SERIAL_IP22_ZILOG=y
+	select SERIAL_CORE_CONSOLE
+	help
+
 config V850E_UART
 	bool "NEC V850E on-chip UART support"
 	depends on V850E_MA1 || V850E_ME2 || V850E_TEG || V850E2_ANNA || V850E_AS85EP1
@@ -451,6 +486,22 @@
         depends on SERIAL98=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_AU1X00
+	bool "Enable Au1x00 UART Support"
+	depends on MIPS && SOC_AU1X00
+	select SERIAL_CORE
+	help
+	  If you have an Alchemy AU1X00 processor (MIPS based) and you want
+	  to use serial ports, say Y.  Otherwise, say N.
+
+config SERIAL_AU1X00_CONSOLE
+	bool "Enable Au1x00 serial console"
+	depends on SERIAL_AU1X00
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you have an Alchemy AU1X00 processor (MIPS based) and you want
+	  to use a console on a serial port, say Y.  Otherwise, say N.
+
 config SERIAL_CORE
 	tristate
 
--- diff/drivers/serial/Makefile	2003-09-30 15:46:17.000000000 +0100
+++ source/drivers/serial/Makefile	2004-02-18 09:04:01.000000000 +0000
@@ -23,6 +23,7 @@
 obj-$(CONFIG_SERIAL_UART00) += uart00.o
 obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
 obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
 obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
 obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
@@ -32,3 +33,5 @@
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
 obj-$(CONFIG_SERIAL98) += serial98.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
+obj-$(CONFIG_SERIAL_DZ) += dz.o
--- diff/drivers/serial/mcfserial.c	2003-07-11 09:39:50.000000000 +0100
+++ source/drivers/serial/mcfserial.c	2004-02-18 09:04:01.000000000 +0000
@@ -985,6 +985,43 @@
 	local_irq_restore(flags);
 }
 
+static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+	return mcfrs_getsignals(info);
+}
+
+static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
+			  unsigned int set, unsigned int clear)
+{
+	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
+	int rts = -1, dtr = -1;
+
+	if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
+		return -ENODEV;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	mcfrs_setsignals(info, dtr, rts);
+
+	return 0;
+}
+
 static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -1059,45 +1096,6 @@
 				    info, sizeof(struct mcf_serial));
 			return 0;
 			
-		case TIOCMGET:
-			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
-                            sizeof(unsigned int))))
-                                return(error);
-			val = mcfrs_getsignals(info);
-			put_user(val, (unsigned int *) arg);
-			break;
-
-                case TIOCMBIS:
-			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
-                            sizeof(unsigned int))))
-				return(error);
-
-			get_user(val, (unsigned int *) arg);
-			rts = (val & TIOCM_RTS) ? 1 : -1;
-			dtr = (val & TIOCM_DTR) ? 1 : -1;
-			mcfrs_setsignals(info, dtr, rts);
-			break;
-
-                case TIOCMBIC:
-			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
-                            sizeof(unsigned int))))
-				return(error);
-			get_user(val, (unsigned int *) arg);
-			rts = (val & TIOCM_RTS) ? 0 : -1;
-			dtr = (val & TIOCM_DTR) ? 0 : -1;
-			mcfrs_setsignals(info, dtr, rts);
-			break;
-
-                case TIOCMSET:
-			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
-                            sizeof(unsigned int))))
-				return(error);
-			get_user(val, (unsigned int *) arg);
-			rts = (val & TIOCM_RTS) ? 1 : 0;
-			dtr = (val & TIOCM_DTR) ? 1 : 0;
-			mcfrs_setsignals(info, dtr, rts);
-			break;
-
 #ifdef TIOCSET422
 		case TIOCSET422:
 			get_user(val, (unsigned int *) arg);
@@ -1563,6 +1561,8 @@
 	.start = mcfrs_start,
 	.hangup = mcfrs_hangup,
 	.read_proc = mcfrs_readproc,
+	.tiocmget = mcfrs_tiocmget,
+	.tiocmset = mcfrs_tiocmset,
 };
 
 /* mcfrs_init inits the driver */
--- diff/drivers/serial/serial_core.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/serial/serial_core.c	2004-02-18 09:04:01.000000000 +0000
@@ -1987,6 +1987,11 @@
 {
 	unsigned int flags;
 
+#ifdef CONFIG_KGDB
+	if (port->kgdb)
+		return;
+#endif
+
 	/*
 	 * If there isn't a port here, don't do anything further.
 	 */
--- diff/drivers/tc/zs.c	2003-09-30 15:46:17.000000000 +0100
+++ source/drivers/tc/zs.c	2004-02-18 09:04:01.000000000 +0000
@@ -1176,11 +1176,21 @@
 	return 0;
 }
 
-static int get_modem_info(struct dec_serial *info, unsigned int *value)
+static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 {
+	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
 	unsigned char control, status_a, status_b;
 	unsigned int result;
 
+	if (info->hook)
+		return -ENODEV;
+
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
 	if (info->zs_channel == info->zs_chan_a)
 		result = 0;
 	else {
@@ -1196,41 +1206,37 @@
 			| ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
 			| ((status_b & CTS) ? TIOCM_CTS: 0);
 	}
-	put_user(result, value);
-	return 0;
+	return result;
 }
 
-static int set_modem_info(struct dec_serial *info, unsigned int cmd,
-			  unsigned int *value)
+static int rs_tiocmset(struct tty_struct *tty, struct file *file,
+		       unsigned int set, unsigned int clear)
 {
+	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
 	int error;
 	unsigned int arg, bits;
 
-	error = verify_area(VERIFY_READ, value, sizeof(int));
-	if (error)
-		return error;
+	if (info->hook)
+		return -ENODEV;
+
+	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+		return -ENODEV;
+
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
 	if (info->zs_channel == info->zs_chan_a)
 		return 0;
 
-	get_user(arg, value);
-	bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
 	cli();
-	switch (cmd) {
-	case TIOCMBIS:
-		info->zs_chan_a->curregs[5] |= bits;
-		break;
-	case TIOCMBIC:
-		info->zs_chan_a->curregs[5] &= ~bits;
-		break;
-	case TIOCMSET:
-		info->zs_chan_a->curregs[5] = 
-			(info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
-		break;
-	default:
-		sti();
-		return -EINVAL;
-	}
+	if (set & TIOCM_RTS)
+		info->zs_chan_a->curregs[5] |= RTS;
+	if (set & TIOCM_DTR)
+		info->zs_chan_a->curregs[5] |= DTR;
+	if (clear & TIOCM_RTS)
+		info->zs_chan_a->curregs[5] &= ~RTS;
+	if (clear & TIOCM_DTR)
+		info->zs_chan_a->curregs[5] &= ~DTR;
 	write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
 	sti();
 	return 0;
@@ -1278,16 +1284,6 @@
 	}
 	
 	switch (cmd) {
-		case TIOCMGET:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
 			error = verify_area(VERIFY_WRITE, (void *) arg,
 						sizeof(struct serial_struct));
@@ -1816,6 +1812,8 @@
 	.hangup = rs_hangup,
 	.break_ctl = rs_break,
 	.wait_until_sent = rs_wait_until_sent,
+	.tiocmget = rs_tiocmget,
+	.tiocmset = rs_tiocmset,
 };
 
 /* zs_init inits the driver */
--- diff/drivers/usb/class/usblp.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/usb/class/usblp.c	2004-02-18 09:04:01.000000000 +0000
@@ -603,7 +603,7 @@
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct usblp *usblp = file->private_data;
-	int timeout, err = 0;
+	int timeout, err = 0, transfer_length;
 	size_t writecount = 0;
 
 	while (writecount < count) {
@@ -654,19 +654,13 @@
 			continue;
 		}
 
-		writecount += usblp->writeurb->transfer_buffer_length;
-		usblp->writeurb->transfer_buffer_length = 0;
+		transfer_length=(count - writecount);
+		if (transfer_length > USBLP_BUF_SIZE)
+			transfer_length = USBLP_BUF_SIZE;
 
-		if (writecount == count) {
-			up (&usblp->sem);
-			break;
-		}
+		usblp->writeurb->transfer_buffer_length = transfer_length;
 
-		usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
-							  (count - writecount) : USBLP_BUF_SIZE;
-
-		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
-				usblp->writeurb->transfer_buffer_length)) {
+		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, transfer_length)) {
 			up(&usblp->sem);
 			return writecount ? writecount : -EFAULT;
 		}
@@ -683,6 +677,8 @@
 			break;
 		}
 		up (&usblp->sem);
+
+		writecount += transfer_length;
 	}
 
 	return count;
--- diff/drivers/usb/core/buffer.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/core/buffer.c	2004-02-18 09:04:01.000000000 +0000
@@ -2,14 +2,19 @@
  * DMA memory management for framework level HCD code (hc_driver)
  *
  * This implementation plugs in through generic "usb_bus" level methods,
- * and works with real PCI, or when "pci device == null" makes sense.
+ * and should work with all USB controllers, regardles of bus type.
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
 
 
 #ifdef CONFIG_USB_DEBUG
@@ -62,7 +67,7 @@
 		if (!(size = pool_max [i]))
 			continue;
 		snprintf (name, sizeof name, "buffer-%d", size);
-		hcd->pool [i] = pci_pool_create (name, hcd->pdev,
+		hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
 				size, size, 0);
 		if (!hcd->pool [i]) {
 			hcd_buffer_destroy (hcd);
@@ -86,9 +91,9 @@
 	int		i;
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-		struct pci_pool		*pool = hcd->pool [i];
+		struct dma_pool		*pool = hcd->pool [i];
 		if (pool) {
-			pci_pool_destroy (pool);
+			dma_pool_destroy (pool);
 			hcd->pool [i] = 0;
 		}
 	}
@@ -112,9 +117,9 @@
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i])
-			return pci_pool_alloc (hcd->pool [i], mem_flags, dma);
+			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
 	}
-	return pci_alloc_consistent (hcd->pdev, size, dma);
+	return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
 }
 
 void hcd_buffer_free (
@@ -131,9 +136,9 @@
 		return;
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i]) {
-			pci_pool_free (hcd->pool [i], addr, dma);
+			dma_pool_free (hcd->pool [i], addr, dma);
 			return;
 		}
 	}
-	pci_free_consistent (hcd->pdev, size, addr, dma);
+	dma_free_coherent (hcd->self.controller, size, addr, dma);
 }
--- diff/drivers/usb/core/hcd-pci.c	2003-10-27 09:20:38.000000000 +0000
+++ source/drivers/usb/core/hcd-pci.c	2004-02-18 09:04:01.000000000 +0000
@@ -146,12 +146,10 @@
 	pci_set_drvdata (dev, hcd);
 	hcd->driver = driver;
 	hcd->description = driver->description;
-	hcd->pdev = dev;
 	hcd->self.bus_name = pci_name(dev);
 	if (hcd->product_desc == NULL)
 		hcd->product_desc = "USB Host Controller";
 	hcd->self.controller = &dev->dev;
-	hcd->controller = hcd->self.controller;
 
 	if ((retval = hcd_buffer_create (hcd)) != 0) {
 clean_3:
@@ -159,11 +157,11 @@
 		goto clean_2;
 	}
 
-	dev_info (hcd->controller, "%s\n", hcd->product_desc);
+	dev_info (hcd->self.controller, "%s\n", hcd->product_desc);
 
 	/* till now HC has been in an indeterminate state ... */
 	if (driver->reset && (retval = driver->reset (hcd)) < 0) {
-		dev_err (hcd->controller, "can't reset\n");
+		dev_err (hcd->self.controller, "can't reset\n");
 		goto clean_3;
 	}
 	hcd->state = USB_STATE_HALT;
@@ -177,13 +175,13 @@
 	retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
 				hcd->description, hcd);
 	if (retval != 0) {
-		dev_err (hcd->controller,
+		dev_err (hcd->self.controller,
 				"request interrupt %s failed\n", bufp);
 		goto clean_3;
 	}
 	hcd->irq = dev->irq;
 
-	dev_info (hcd->controller, "irq %s, %s %p\n", bufp,
+	dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
 		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
 		base);
 
@@ -226,7 +224,7 @@
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	dev_info (hcd->controller, "remove, state %x\n", hcd->state);
+	dev_info (hcd->self.controller, "remove, state %x\n", hcd->state);
 
 	if (in_interrupt ())
 		BUG ();
@@ -235,7 +233,7 @@
 	if (HCD_IS_RUNNING (hcd->state))
 		hcd->state = USB_STATE_QUIESCING;
 
-	dev_dbg (hcd->controller, "roothub graceful disconnect\n");
+	dev_dbg (hcd->self.controller, "roothub graceful disconnect\n");
 	usb_disconnect (&hub);
 
 	hcd->driver->stop (hcd);
@@ -273,15 +271,15 @@
 	int			retval = 0;
 
 	hcd = pci_get_drvdata(dev);
-	dev_dbg (hcd->controller, "suspend D%d --> D%d\n",
+	dev_dbg (hcd->self.controller, "suspend D%d --> D%d\n",
 			dev->current_state, state);
 
 	switch (hcd->state) {
 	case USB_STATE_HALT:
-		dev_dbg (hcd->controller, "halted; hcd not suspended\n");
+		dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
 		break;
 	case USB_STATE_SUSPENDED:
-		dev_dbg (hcd->controller, "hcd already suspended\n");
+		dev_dbg (hcd->self.controller, "hcd already suspended\n");
 		break;
 	default:
 		/* remote wakeup needs hub->suspend() cooperation */
@@ -293,7 +291,8 @@
 		hcd->state = USB_STATE_QUIESCING;
 		retval = hcd->driver->suspend (hcd, state);
 		if (retval)
-			dev_dbg (hcd->controller, "suspend fail, retval %d\n",
+			dev_dbg (hcd->self.controller, 
+					"suspend fail, retval %d\n",
 					retval);
 		else
 			hcd->state = USB_STATE_SUSPENDED;
@@ -316,11 +315,12 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	dev_dbg (hcd->controller, "resume from state D%d\n",
+	dev_dbg (hcd->self.controller, "resume from state D%d\n",
 			dev->current_state);
 
 	if (hcd->state != USB_STATE_SUSPENDED) {
-		dev_dbg (hcd->controller, "can't resume, not suspended!\n");
+		dev_dbg (hcd->self.controller, 
+				"can't resume, not suspended!\n");
 		return -EL3HLT;
 	}
 	hcd->state = USB_STATE_RESUMING;
@@ -333,7 +333,8 @@
 
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
-		dev_dbg (hcd->controller, "resume fail, retval %d\n", retval);
+		dev_dbg (hcd->self.controller, 
+				"resume fail, retval %d\n", retval);
 		usb_hc_died (hcd);
 	}
 
--- diff/drivers/usb/core/hcd.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/core/hcd.c	2004-02-18 09:04:01.000000000 +0000
@@ -351,7 +351,7 @@
 			/* FALLTHROUGH */
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 	case DeviceOutRequest | USB_REQ_SET_FEATURE:
-		dev_dbg (hcd->controller, "no device features yet yet\n");
+		dev_dbg (hcd->self.controller, "no device features yet yet\n");
 		break;
 	case DeviceRequest | USB_REQ_GET_CONFIGURATION:
 		ubuf [0] = 1;
@@ -394,7 +394,7 @@
 		break;
 	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 		// wValue == urb->dev->devaddr
-		dev_dbg (hcd->controller, "root hub device address %d\n",
+		dev_dbg (hcd->self.controller, "root hub device address %d\n",
 			wValue);
 		break;
 
@@ -409,7 +409,7 @@
 			/* FALLTHROUGH */
 	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
 	case EndpointOutRequest | USB_REQ_SET_FEATURE:
-		dev_dbg (hcd->controller, "no endpoint features yet\n");
+		dev_dbg (hcd->self.controller, "no endpoint features yet\n");
 		break;
 
 	/* CLASS REQUESTS (and errors) */
@@ -423,12 +423,12 @@
 error:
 		/* "protocol stall" on error */
 		urb->status = -EPIPE;
-		dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n",
+		dev_dbg (hcd->self.controller, "unsupported hub control message (maxchild %d)\n",
 				urb->dev->maxchild);
 	}
 	if (urb->status) {
 		urb->actual_length = 0;
-		dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",
+		dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",
 			typeReq, wValue, wIndex, wLength, urb->status);
 	}
 	if (bufp) {
@@ -464,7 +464,7 @@
 			|| urb->status != -EINPROGRESS
 			|| urb->transfer_buffer_length < len
 			|| !HCD_IS_RUNNING (hcd->state)) {
-		dev_dbg (hcd->controller,
+		dev_dbg (hcd->self.controller,
 				"not queuing rh status urb, stat %d\n",
 				urb->status);
 		return -EINVAL;
@@ -1068,18 +1068,18 @@
 	/* lower level hcd code should use *_dma exclusively,
 	 * unless it uses pio or talks to another transport.
 	 */
-	if (hcd->controller->dma_mask) {
+	if (hcd->self.controller->dma_mask) {
 		if (usb_pipecontrol (urb->pipe)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			urb->setup_dma = dma_map_single (
-					hcd->controller,
+					hcd->self.controller,
 					urb->setup_packet,
 					sizeof (struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 		if (urb->transfer_buffer_length != 0
 			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
 			urb->transfer_dma = dma_map_single (
-					hcd->controller,
+					hcd->self.controller,
 					urb->transfer_buffer,
 					urb->transfer_buffer_length,
 					usb_pipein (urb->pipe)
@@ -1125,7 +1125,7 @@
 		/* failures "should" be harmless */
 		value = hcd->driver->urb_dequeue (hcd, urb);
 		if (value != 0)
-			dev_dbg (hcd->controller,
+			dev_dbg (hcd->self.controller,
 				"dequeue %p --> %d\n",
 				urb, value);
 	}
@@ -1232,7 +1232,7 @@
 	 * finish unlinking the initial failed usb_set_address().
 	 */
 	if (!hcd->saw_irq) {
-		dev_warn (hcd->controller, "Unlink after no-IRQ?  "
+		dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
 			"Different ACPI or APIC settings may help."
 			"\n");
 		hcd->saw_irq = 1;
@@ -1244,7 +1244,8 @@
 	 */
 	if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
 		if (in_interrupt ()) {
-			dev_dbg (hcd->controller, "non-async unlink in_interrupt");
+			dev_dbg (hcd->self.controller, 
+				"non-async unlink in_interrupt");
 			retval = -EWOULDBLOCK;
 			goto done;
 		}
@@ -1363,7 +1364,7 @@
 		if (tmp == -EINPROGRESS) {
 			tmp = urb->pipe;
 			unlink1 (hcd, urb);
-			dev_dbg (hcd->controller,
+			dev_dbg (hcd->self.controller,
 				"shutdown urb %p pipe %08x ep%d%s%s\n",
 				urb, tmp, usb_pipeendpoint (tmp),
 				(tmp & USB_DIR_IN) ? "in" : "out",
@@ -1417,7 +1418,7 @@
 
 	/* device driver problem with refcounts? */
 	if (!list_empty (&dev->urb_list)) {
-		dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n",
+		dev_dbg (hcd->self.controller, "free busy dev, %s devnum %d (bug!)\n",
 			hcd->self.bus_name, udev->devnum);
 		return -EINVAL;
 	}
@@ -1474,15 +1475,16 @@
 	// It would catch exit/unlink paths for all urbs.
 
 	/* lower level hcd code should use *_dma exclusively */
-	if (hcd->controller->dma_mask) {
+	if (hcd->self.controller->dma_mask) {
 		if (usb_pipecontrol (urb->pipe)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-			dma_unmap_single (hcd->controller, urb->setup_dma,
+			dma_unmap_single (hcd->self.controller, urb->setup_dma,
 					sizeof (struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 		if (urb->transfer_buffer_length != 0
 			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-			dma_unmap_single (hcd->controller, urb->transfer_dma,
+			dma_unmap_single (hcd->self.controller, 
+					urb->transfer_dma,
 					urb->transfer_buffer_length,
 					usb_pipein (urb->pipe)
 					    ? DMA_FROM_DEVICE
@@ -1551,7 +1553,7 @@
  */
 void usb_hc_died (struct usb_hcd *hcd)
 {
-	dev_err (hcd->controller, "HC died; cleaning up\n");
+	dev_err (hcd->self.controller, "HC died; cleaning up\n");
 
 	/* clean up old urbs and devices; needs a task context */
 	INIT_WORK (&hcd->work, hcd_panic, hcd);
--- diff/drivers/usb/core/hcd.h	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/core/hcd.h	2004-02-18 09:04:01.000000000 +0000
@@ -76,17 +76,14 @@
 	unsigned		saw_irq : 1;
 	int			irq;		/* irq allocated */
 	void			*regs;		/* device memory/io */
-	struct device		*controller;	/* handle to hardware */
 
-	/* a few non-PCI controllers exist, mostly for OHCI */
-	struct pci_dev		*pdev;		/* pci is typical */
 #ifdef	CONFIG_PCI
 	int			region;		/* pci region for regs */
 	u32			pci_state [16];	/* for PM state save */
 #endif
 
 #define HCD_BUFFER_POOLS	4
-	struct pci_pool		*pool [HCD_BUFFER_POOLS];
+	struct dma_pool		*pool [HCD_BUFFER_POOLS];
 
 	int			state;
 #	define	__ACTIVE		0x01
@@ -355,7 +352,7 @@
 static inline int hcd_register_root (struct usb_hcd *hcd)
 {
 	return usb_register_root_hub (
-		hcd_to_bus (hcd)->root_hub, hcd->controller);
+		hcd_to_bus (hcd)->root_hub, hcd->self.controller);
 }
 
 /*-------------------------------------------------------------------------*/
--- diff/drivers/usb/gadget/goku_udc.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/gadget/goku_udc.c	2004-02-18 09:04:01.000000000 +0000
@@ -1111,7 +1111,7 @@
 	int t;
 
 	/* int_status is the same format ... */
-	t = snprintf(*next, *size,
+	t = scnprintf(*next, *size,
 		"%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",
 		label, mask,
 		(mask & INT_PWRDETECT) ? " power" : "",
@@ -1164,7 +1164,7 @@
 	/* basic device status */
 	tmp = readl(&regs->power_detect);
 	is_usb_connected = tmp & PW_DETECT;
-	t = snprintf(next, size,
+	t = scnprintf(next, size,
 		"%s - %s\n"
 		"%s version: %s %s\n"
 		"Gadget driver: %s\n"
@@ -1198,7 +1198,7 @@
 		goto done;
 
 	/* registers for (active) device and ep0 */
-	t = snprintf(next, size, "\nirqs %lu\ndataset %02x "
+	t = scnprintf(next, size, "\nirqs %lu\ndataset %02x "
 			"single.bcs %02x.%02x state %x addr %u\n",
 			dev->irqs, readl(&regs->DataSet),
 			readl(&regs->EPxSingle), readl(&regs->EPxBCS),
@@ -1208,7 +1208,7 @@
 	next += t;
 
 	tmp = readl(&regs->dma_master);
-	t = snprintf(next, size,
+	t = scnprintf(next, size,
 		"dma %03X =" EIGHTBITS "%s %s\n", tmp,
 		(tmp & MST_EOPB_DIS) ? " eopb-" : "",
 		(tmp & MST_EOPB_ENA) ? " eopb+" : "",
@@ -1237,7 +1237,7 @@
 			continue;
 
 		tmp = readl(ep->reg_status);
-		t = snprintf(next, size,
+		t = scnprintf(next, size,
 			"%s %s max %u %s, irqs %lu, "
 			"status %02x (%s) " FOURBITS "\n",
 			ep->ep.name,
@@ -1277,7 +1277,7 @@
 		next += t;
 
 		if (list_empty(&ep->queue)) {
-			t = snprintf(next, size, "\t(nothing queued)\n");
+			t = scnprintf(next, size, "\t(nothing queued)\n");
 			if (t <= 0 || t > size)
 				goto done;
 			size -= t;
@@ -1295,7 +1295,7 @@
 			} else
 				tmp = req->req.actual;
 
-			t = snprintf(next, size,
+			t = scnprintf(next, size,
 				"\treq %p len %u/%u buf %p\n",
 				&req->req, tmp, req->req.length,
 				req->req.buf);
@@ -1913,7 +1913,7 @@
 	INFO(dev, "%s\n", driver_desc);
 	INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr());
 #ifndef __sparc__
-	snprintf(buf, sizeof buf, "%d", pdev->irq);
+	scnprintf(buf, sizeof buf, "%d", pdev->irq);
 	bufp = buf;
 #else
 	bufp = __irq_itoa(pdev->irq);
--- diff/drivers/usb/gadget/net2280.c	2004-02-18 08:54:11.000000000 +0000
+++ source/drivers/usb/gadget/net2280.c	2004-02-18 09:04:01.000000000 +0000
@@ -1439,7 +1439,7 @@
 			|| !dev->driver->function
 			|| strlen (dev->driver->function) > PAGE_SIZE)
 		return 0;
-	return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
+	return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
 }
 static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
@@ -1465,7 +1465,7 @@
 		s = "(none)";
 
 	/* Main Control Registers */
-	t = snprintf (next, size, "%s version " DRIVER_VERSION
+	t = scnprintf (next, size, "%s version " DRIVER_VERSION
 			", chiprev %04x, dma %s\n\n"
 			"devinit %03x fifoctl %08x gadget '%s'\n"
 			"pci irqenb0 %02x irqenb1 %08x "
@@ -1497,7 +1497,7 @@
 		/* full speed bit (6) not working?? */
 	} else
 			s = "not attached";
-	t = snprintf (next, size,
+	t = scnprintf (next, size,
 			"stdrsp %08x usbctl %08x usbstat %08x "
 				"addr 0x%02x (%s)\n",
 			readl (&dev->usb->stdrsp), t1, t2,
@@ -1519,7 +1519,7 @@
 
 		t1 = readl (&ep->regs->ep_cfg);
 		t2 = readl (&ep->regs->ep_rsp) & 0xff;
-		t = snprintf (next, size,
+		t = scnprintf (next, size,
 				"\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
 					"irqenb %02x\n",
 				ep->ep.name, t1, t2,
@@ -1543,7 +1543,7 @@
 		size -= t;
 		next += t;
 
-		t = snprintf (next, size,
+		t = scnprintf (next, size,
 				"\tstat %08x avail %04x "
 				"(ep%d%s-%s)%s\n",
 				readl (&ep->regs->ep_stat),
@@ -1557,7 +1557,7 @@
 		if (!ep->dma)
 			continue;
 
-		t = snprintf (next, size,
+		t = scnprintf (next, size,
 				"  dma\tctl %08x stat %08x count %08x\n"
 				"\taddr %08x desc %08x\n",
 				readl (&ep->dma->dmactl),
@@ -1574,7 +1574,7 @@
 		// none yet 
 
 	/* Statistics */
-	t = snprintf (next, size, "\nirqs:  ");
+	t = scnprintf (next, size, "\nirqs:  ");
 	size -= t;
 	next += t;
 	for (i = 0; i < 7; i++) {
@@ -1583,12 +1583,12 @@
 		ep = &dev->ep [i];
 		if (i && !ep->irqs)
 			continue;
-		t = snprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs);
+		t = scnprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs);
 		size -= t;
 		next += t;
 
 	}
-	t = snprintf (next, size, "\n");
+	t = scnprintf (next, size, "\n");
 	size -= t;
 	next += t;
 
@@ -1624,7 +1624,7 @@
 			if (!d)
 				continue;
 			t = d->bEndpointAddress;
-			t = snprintf (next, size,
+			t = scnprintf (next, size,
 				"\n%s (ep%d%s-%s) max %04x %s fifo %d\n",
 				ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
 				(t & USB_DIR_IN) ? "in" : "out",
@@ -1641,7 +1641,7 @@
 				ep->dma ? "dma" : "pio", ep->fifo_size
 				);
 		} else /* ep0 should only have one transfer queued */
-			t = snprintf (next, size, "ep0 max 64 pio %s\n",
+			t = scnprintf (next, size, "ep0 max 64 pio %s\n",
 					ep->is_in ? "in" : "out");
 		if (t <= 0 || t > size)
 			goto done;
@@ -1649,7 +1649,7 @@
 		next += t;
 
 		if (list_empty (&ep->queue)) {
-			t = snprintf (next, size, "\t(nothing queued)\n");
+			t = scnprintf (next, size, "\t(nothing queued)\n");
 			if (t <= 0 || t > size)
 				goto done;
 			size -= t;
@@ -1658,14 +1658,14 @@
 		}
 		list_for_each_entry (req, &ep->queue, queue) {
 			if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc))
-				t = snprintf (next, size,
+				t = scnprintf (next, size,
 					"\treq %p len %d/%d "
 					"buf %p (dmacount %08x)\n",
 					&req->req, req->req.actual,
 					req->req.length, req->req.buf,
 					readl (&ep->dma->dmacount));
 			else
-				t = snprintf (next, size,
+				t = scnprintf (next, size,
 					"\treq %p len %d/%d buf %p\n",
 					&req->req, req->req.actual,
 					req->req.length, req->req.buf);
@@ -1678,7 +1678,7 @@
 				struct net2280_dma	*td;
 
 				td = req->td;
-				t = snprintf (next, size, "\t    td %08x "
+				t = scnprintf (next, size, "\t    td %08x "
 					" count %08x buf %08x desc %08x\n",
 					req->td_dma, td->dmacount,
 					td->dmaaddr, td->dmadesc);
@@ -2788,7 +2788,7 @@
 		goto done;
 	}
 #ifndef __sparc__
-	snprintf (buf, sizeof buf, "%d", pdev->irq);
+	scnprintf (buf, sizeof buf, "%d", pdev->irq);
 	bufp = buf;
 #else
 	bufp = __irq_itoa(pdev->irq);
--- diff/drivers/usb/gadget/pxa2xx_udc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/gadget/pxa2xx_udc.c	2004-02-18 09:04:01.000000000 +0000
@@ -1232,7 +1232,7 @@
 	local_irq_save(flags);
 
 	/* basic device status */
-	t = snprintf(next, size, DRIVER_DESC "\n"
+	t = scnprintf(next, size, DRIVER_DESC "\n"
 		"%s version: %s\nGadget driver: %s\nHost %s\n\n",
 		driver_name, DRIVER_VERSION SIZE_STR DMASTR,
 		dev->driver ? dev->driver->driver.name : "(none)",
@@ -1241,14 +1241,14 @@
 	next += t;
 
 	/* registers for device and ep0 */
-	t = snprintf(next, size,
+	t = scnprintf(next, size,
 		"uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
 		UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
 	size -= t;
 	next += t;
 
 	tmp = UDCCR;
-	t = snprintf(next, size,
+	t = scnprintf(next, size,
 		"udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
 		(tmp & UDCCR_REM) ? " rem" : "",
 		(tmp & UDCCR_RSTIR) ? " rstir" : "",
@@ -1262,7 +1262,7 @@
 	next += t;
 
 	tmp = UDCCS0;
-	t = snprintf(next, size,
+	t = scnprintf(next, size,
 		"udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
 		(tmp & UDCCS0_SA) ? " sa" : "",
 		(tmp & UDCCS0_RNE) ? " rne" : "",
@@ -1277,7 +1277,7 @@
 
 	if (dev->has_cfr) {
 		tmp = UDCCFR;
-		t = snprintf(next, size,
+		t = scnprintf(next, size,
 			"udccfr %02X =%s%s\n", tmp,
 			(tmp & UDCCFR_AREN) ? " aren" : "",
 			(tmp & UDCCFR_ACM) ? " acm" : "");
@@ -1288,7 +1288,7 @@
 	if (!is_usb_connected() || !dev->driver)
 		goto done;
 
-	t = snprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+	t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
 		dev->stats.write.bytes, dev->stats.write.ops,
 		dev->stats.read.bytes, dev->stats.read.ops,
 		dev->stats.irqs);
@@ -1308,7 +1308,7 @@
 			if (!d)
 				continue;
 			tmp = *dev->ep [i].reg_udccs;
-			t = snprintf(next, size,
+			t = scnprintf(next, size,
 				"%s max %d %s udccs %02x irqs %lu/%lu\n",
 				ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
 				(ep->dma >= 0) ? "dma" : "pio", tmp,
@@ -1316,7 +1316,7 @@
 			/* TODO translate all five groups of udccs bits! */
 
 		} else /* ep0 should only have one transfer queued */
-			t = snprintf(next, size, "ep0 max 16 pio irqs %lu\n",
+			t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",
 				ep->pio_irqs);
 		if (t <= 0 || t > size)
 			goto done;
@@ -1324,7 +1324,7 @@
 		next += t;
 
 		if (list_empty(&ep->queue)) {
-			t = snprintf(next, size, "\t(nothing queued)\n");
+			t = scnprintf(next, size, "\t(nothing queued)\n");
 			if (t <= 0 || t > size)
 				goto done;
 			size -= t;
@@ -1334,7 +1334,7 @@
 		list_for_each_entry(req, &ep->queue, queue) {
 #ifdef	USE_DMA
 			if (ep->dma >= 0 && req->queue.prev == &ep->queue)
-				t = snprintf(next, size,
+				t = scnprintf(next, size,
 					"\treq %p len %d/%d "
 					"buf %p (dma%d dcmd %08x)\n",
 					&req->req, req->req.actual,
@@ -1344,7 +1344,7 @@
 					);
 			else
 #endif
-				t = snprintf(next, size,
+				t = scnprintf(next, size,
 					"\treq %p len %d/%d buf %p\n",
 					&req->req, req->req.actual,
 					req->req.length, req->req.buf);
@@ -1382,7 +1382,7 @@
 			|| !dev->driver->function
 			|| strlen (dev->driver->function) > PAGE_SIZE)
 		return 0;
-	return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
+	return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
 }
 static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
--- diff/drivers/usb/host/ehci-dbg.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci-dbg.c	2004-02-18 09:04:01.000000000 +0000
@@ -19,13 +19,13 @@
 /* this file is part of ehci-hcd.c */
 
 #define ehci_dbg(ehci, fmt, args...) \
-	dev_dbg ((ehci)->hcd.controller , fmt , ## args )
+	dev_dbg ((ehci)->hcd.self.controller , fmt , ## args )
 #define ehci_err(ehci, fmt, args...) \
-	dev_err ((ehci)->hcd.controller , fmt , ## args )
+	dev_err ((ehci)->hcd.self.controller , fmt , ## args )
 #define ehci_info(ehci, fmt, args...) \
-	dev_info ((ehci)->hcd.controller , fmt , ## args )
+	dev_info ((ehci)->hcd.self.controller , fmt , ## args )
 #define ehci_warn(ehci, fmt, args...) \
-	dev_warn ((ehci)->hcd.controller , fmt , ## args )
+	dev_warn ((ehci)->hcd.self.controller , fmt , ## args )
 
 #ifdef EHCI_VERBOSE_DEBUG
 #	define vdbg dbg
@@ -173,7 +173,7 @@
 static int __attribute__((__unused__))
 dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
 {
-	return snprintf (buf, len,
+	return scnprintf (buf, len,
 		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
 		label, label [0] ? " " : "", status,
 		(status & STS_ASS) ? " Async" : "",
@@ -192,7 +192,7 @@
 static int __attribute__((__unused__))
 dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
 {
-	return snprintf (buf, len,
+	return scnprintf (buf, len,
 		"%s%sintrenable %02x%s%s%s%s%s%s",
 		label, label [0] ? " " : "", enable,
 		(enable & STS_IAA) ? " IAA" : "",
@@ -209,7 +209,7 @@
 
 static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
 {
-	return snprintf (buf, len,
+	return scnprintf (buf, len,
 		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
 		label, label [0] ? " " : "", command,
 		(command & CMD_PARK) ? "park" : "(park)",
@@ -238,7 +238,7 @@
 	default: sig = "?"; break;
 	}
 
-	return snprintf (buf, len,
+	return scnprintf (buf, len,
 		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
 		label, label [0] ? " " : "", port, status,
 		(status & PORT_POWER) ? " POWER" : "",
@@ -359,7 +359,7 @@
 	}
 	scratch = cpu_to_le32p (&qh->hw_info1);
 	hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0;
-	temp = snprintf (next, size,
+	temp = scnprintf (next, size,
 			"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
 			qh, scratch & 0x007f,
 			speed_char (scratch),
@@ -367,7 +367,7 @@
 			scratch, cpu_to_le32p (&qh->hw_info2),
 			cpu_to_le32p (&qh->hw_token), mark,
 			(__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
-				? "data0" : "data1",
+				? "data1" : "data0",
 			(cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f);
 	size -= temp;
 	next += temp;
@@ -449,7 +449,7 @@
 	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
 		qh_lines (ehci, qh, &next, &size);
 	if (ehci->reclaim && size > 0) {
-		temp = snprintf (next, size, "\nreclaim =\n");
+		temp = scnprintf (next, size, "\nreclaim =\n");
 		size -= temp;
 		next += temp;
 
@@ -486,7 +486,7 @@
 	next = buf;
 	size = PAGE_SIZE;
 
-	temp = snprintf (next, size, "size = %d\n", ehci->periodic_size);
+	temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
 	size -= temp;
 	next += temp;
 
@@ -500,14 +500,14 @@
 			continue;
 		tag = Q_NEXT_TYPE (ehci->periodic [i]);
 
-		temp = snprintf (next, size, "%4d: ", i);
+		temp = scnprintf (next, size, "%4d: ", i);
 		size -= temp;
 		next += temp;
 
 		do {
 			switch (tag) {
 			case Q_TYPE_QH:
-				temp = snprintf (next, size, " qh%d-%04x/%p",
+				temp = scnprintf (next, size, " qh%d-%04x/%p",
 						p.qh->period,
 						le32_to_cpup (&p.qh->hw_info2)
 							/* uframe masks */
@@ -520,7 +520,7 @@
 					if (seen [temp].ptr != p.ptr)
 						continue;
 					if (p.qh->qh_next.ptr)
-						temp = snprintf (next, size,
+						temp = scnprintf (next, size,
 							" ...");
 					p.ptr = 0;
 					break;
@@ -545,7 +545,7 @@
 						}
 					}
 
-					temp = snprintf (next, size,
+					temp = scnprintf (next, size,
 						" (%c%d ep%d%s "
 						"[%d/%d] q%d p%d)",
 						speed_char (scratch),
@@ -565,20 +565,20 @@
 				}
 				break;
 			case Q_TYPE_FSTN:
-				temp = snprintf (next, size,
+				temp = scnprintf (next, size,
 					" fstn-%8x/%p", p.fstn->hw_prev,
 					p.fstn);
 				tag = Q_NEXT_TYPE (p.fstn->hw_next);
 				p = p.fstn->fstn_next;
 				break;
 			case Q_TYPE_ITD:
-				temp = snprintf (next, size,
+				temp = scnprintf (next, size,
 					" itd/%p", p.itd);
 				tag = Q_NEXT_TYPE (p.itd->hw_next);
 				p = p.itd->itd_next;
 				break;
 			case Q_TYPE_SITD:
-				temp = snprintf (next, size,
+				temp = scnprintf (next, size,
 					" sitd/%p", p.sitd);
 				tag = Q_NEXT_TYPE (p.sitd->hw_next);
 				p = p.sitd->sitd_next;
@@ -588,7 +588,7 @@
 			next += temp;
 		} while (p.ptr);
 
-		temp = snprintf (next, size, "\n");
+		temp = scnprintf (next, size, "\n");
 		size -= temp;
 		next += temp;
 	}
@@ -623,44 +623,44 @@
 
 	/* Capability Registers */
 	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
-	temp = snprintf (next, size,
+	temp = scnprintf (next, size,
 		"PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
-		pci_name(hcd->pdev),
+		pci_name(to_pci_dev(hcd->self.controller)),
 		i >> 8, i & 0x0ff, ehci->hcd.state);
 	size -= temp;
 	next += temp;
 
 	// FIXME interpret both types of params
 	i = readl (&ehci->caps->hcs_params);
-	temp = snprintf (next, size, "structural params 0x%08x\n", i);
+	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
 	i = readl (&ehci->caps->hcc_params);
-	temp = snprintf (next, size, "capability params 0x%08x\n", i);
+	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
 	/* Operational Registers */
 	temp = dbg_status_buf (scratch, sizeof scratch, label,
 			readl (&ehci->regs->status));
-	temp = snprintf (next, size, fmt, temp, scratch);
+	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_command_buf (scratch, sizeof scratch, label,
 			readl (&ehci->regs->command));
-	temp = snprintf (next, size, fmt, temp, scratch);
+	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_intr_buf (scratch, sizeof scratch, label,
 			readl (&ehci->regs->intr_enable));
-	temp = snprintf (next, size, fmt, temp, scratch);
+	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
-	temp = snprintf (next, size, "uframe %04x\n",
+	temp = scnprintf (next, size, "uframe %04x\n",
 			readl (&ehci->regs->frame_index));
 	size -= temp;
 	next += temp;
@@ -668,13 +668,13 @@
 	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
 		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
 				readl (&ehci->regs->port_status [i]));
-		temp = snprintf (next, size, fmt, temp, scratch);
+		temp = scnprintf (next, size, fmt, temp, scratch);
 		size -= temp;
 		next += temp;
 	}
 
 	if (ehci->reclaim) {
-		temp = snprintf (next, size, "reclaim qh %p%s\n",
+		temp = scnprintf (next, size, "reclaim qh %p%s\n",
 				ehci->reclaim,
 				ehci->reclaim_ready ? " ready" : "");
 		size -= temp;
@@ -682,14 +682,14 @@
 	}
 
 #ifdef EHCI_STATS
-	temp = snprintf (next, size,
+	temp = scnprintf (next, size,
 		"irq normal %ld err %ld reclaim %ld (lost %ld)\n",
 		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
 		ehci->stats.lost_iaa);
 	size -= temp;
 	next += temp;
 
-	temp = snprintf (next, size, "complete %ld unlink %ld\n",
+	temp = scnprintf (next, size, "complete %ld unlink %ld\n",
 		ehci->stats.complete, ehci->stats.unlink);
 	size -= temp;
 	next += temp;
--- diff/drivers/usb/host/ehci-hcd.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ehci-hcd.c	2004-02-18 09:04:01.000000000 +0000
@@ -26,6 +26,7 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/dmapool.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
@@ -67,6 +68,7 @@
  *
  * HISTORY:
  *
+ * 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
  * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
  *	<sojkam@centrum.cz>, updates by DB).
  *
@@ -288,13 +290,13 @@
 
 		/* request handoff to OS */
 		cap &= 1 << 24;
-		pci_write_config_dword (ehci->hcd.pdev, where, cap);
+		pci_write_config_dword (to_pci_dev(ehci->hcd.self.controller), where, cap);
 
 		/* and wait a while for it to happen */
 		do {
 			wait_ms (10);
 			msec -= 10;
-			pci_read_config_dword (ehci->hcd.pdev, where, &cap);
+			pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), where, &cap);
 		} while ((cap & (1 << 16)) && msec);
 		if (cap & (1 << 16)) {
 			ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
@@ -339,7 +341,7 @@
 	while (temp) {
 		u32		cap;
 
-		pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
+		pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), temp, &cap);
 		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
 		switch (cap & 0xff) {
 		case 1:			/* BIOS/SMM/... handoff */
@@ -378,7 +380,7 @@
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
 	 */
 	ehci->periodic_size = DEFAULT_I_TDPS;
-	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
+	if ((retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
 		return retval;
 
 	/* controllers may cache some of the periodic schedule ... */
@@ -433,13 +435,13 @@
 		writel (0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
-		if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
+		if (!pci_set_dma_mask (to_pci_dev(ehci->hcd.self.controller), 0xffffffffffffffffULL))
 			ehci_info (ehci, "enabled 64bit PCI DMA\n");
 #endif
 	}
 
 	/* help hc dma work well with cachelines */
-	pci_set_mwi (ehci->hcd.pdev);
+	pci_set_mwi (to_pci_dev(ehci->hcd.self.controller));
 
 	/* clear interrupt enables, set irq latency */
 	temp = readl (&ehci->regs->command) & 0x0fff;
@@ -493,7 +495,7 @@
 	readl (&ehci->regs->command);	/* unblock posted write */
 
         /* PCI Serial Bus Release Number is at 0x60 offset */
-	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
+	pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte);
 	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	ehci_info (ehci,
 		"USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
@@ -758,7 +760,7 @@
  * non-error returns are a promise to giveback() the urb later
  * we drop ownership so next owner (or urb unlink) can get it
  *
- * urb + dev is in hcd_dev.urb_list
+ * urb + dev is in hcd.self.controller.urb_list
  * we're queueing TDs onto software and hardware lists
  *
  * hcd-specific init for hcpriv hasn't been done yet
--- diff/drivers/usb/host/ehci-hub.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci-hub.c	2004-02-18 09:04:01.000000000 +0000
@@ -113,7 +113,7 @@
 	u16		temp;
 
 	desc->bDescriptorType = 0x29;
-	desc->bPwrOn2PwrGood = 10;	/* FIXME: f(system power) */
+	desc->bPwrOn2PwrGood = 10;	/* ehci 1.0, 2.3.9 says 20ms max */
 	desc->bHubContrCurrent = 0;
 
 	desc->bNbrPorts = ports;
--- diff/drivers/usb/host/ehci-mem.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci-mem.c	2004-02-18 09:04:01.000000000 +0000
@@ -24,7 +24,7 @@
  * There's basically three types of memory:
  *	- data used only by the HCD ... kmalloc is fine
  *	- async and periodic schedules, shared by HC and HCD ... these
- *	  need to use pci_pool or pci_alloc_consistent
+ *	  need to use dma_pool or dma_alloc_coherent
  *	- driver buffers, read/written by HC ... single shot DMA mapped 
  *
  * There's also PCI "register" data, which is memory mapped.
@@ -74,7 +74,7 @@
 	struct ehci_qtd		*qtd;
 	dma_addr_t		dma;
 
-	qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
+	qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
 	if (qtd != 0) {
 		ehci_qtd_init (qtd, dma);
 	}
@@ -83,7 +83,7 @@
 
 static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 {
-	pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+	dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
 }
 
 
@@ -93,7 +93,7 @@
 	dma_addr_t		dma;
 
 	qh = (struct ehci_qh *)
-		pci_pool_alloc (ehci->qh_pool, flags, &dma);
+		dma_pool_alloc (ehci->qh_pool, flags, &dma);
 	if (!qh)
 		return qh;
 
@@ -107,7 +107,7 @@
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
 	if (qh->dummy == 0) {
 		ehci_dbg (ehci, "no dummy td\n");
-		pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+		dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 		qh = 0;
 	}
 	return qh;
@@ -132,7 +132,7 @@
 	if (qh->dummy)
 		ehci_qtd_free (ehci, qh->dummy);
 	usb_put_dev (qh->dev);
-	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+	dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -148,26 +148,26 @@
 		qh_put (ehci, ehci->async);
 	ehci->async = 0;
 
-	/* PCI consistent memory and pools */
+	/* DMA consistent memory and pools */
 	if (ehci->qtd_pool)
-		pci_pool_destroy (ehci->qtd_pool);
+		dma_pool_destroy (ehci->qtd_pool);
 	ehci->qtd_pool = 0;
 
 	if (ehci->qh_pool) {
-		pci_pool_destroy (ehci->qh_pool);
+		dma_pool_destroy (ehci->qh_pool);
 		ehci->qh_pool = 0;
 	}
 
 	if (ehci->itd_pool)
-		pci_pool_destroy (ehci->itd_pool);
+		dma_pool_destroy (ehci->itd_pool);
 	ehci->itd_pool = 0;
 
 	if (ehci->sitd_pool)
-		pci_pool_destroy (ehci->sitd_pool);
+		dma_pool_destroy (ehci->sitd_pool);
 	ehci->sitd_pool = 0;
 
 	if (ehci->periodic)
-		pci_free_consistent (ehci->hcd.pdev,
+		dma_free_coherent (ehci->hcd.self.controller,
 			ehci->periodic_size * sizeof (u32),
 			ehci->periodic, ehci->periodic_dma);
 	ehci->periodic = 0;
@@ -184,7 +184,8 @@
 	int i;
 
 	/* QTDs for control/bulk/intr transfers */
-	ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
+	ehci->qtd_pool = dma_pool_create ("ehci_qtd", 
+			ehci->hcd.self.controller,
 			sizeof (struct ehci_qtd),
 			32 /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
@@ -193,7 +194,8 @@
 	}
 
 	/* QHs for control/bulk/intr transfers */
-	ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
+	ehci->qh_pool = dma_pool_create ("ehci_qh", 
+			ehci->hcd.self.controller,
 			sizeof (struct ehci_qh),
 			32 /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
@@ -206,7 +208,8 @@
 	}
 
 	/* ITD for high speed ISO transfers */
-	ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
+	ehci->itd_pool = dma_pool_create ("ehci_itd", 
+			ehci->hcd.self.controller,
 			sizeof (struct ehci_itd),
 			32 /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
@@ -215,7 +218,8 @@
 	}
 
 	/* SITD for full/low speed split ISO transfers */
-	ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
+	ehci->sitd_pool = dma_pool_create ("ehci_sitd", 
+			ehci->hcd.self.controller,
 			sizeof (struct ehci_sitd),
 			32 /* byte alignment (for hw parts) */,
 			4096 /* can't cross 4K */);
@@ -225,9 +229,9 @@
 
 	/* Hardware periodic table */
 	ehci->periodic = (u32 *)
-		pci_alloc_consistent (ehci->hcd.pdev,
+		dma_alloc_coherent (ehci->hcd.self.controller,
 			ehci->periodic_size * sizeof (u32),
-			&ehci->periodic_dma);
+			&ehci->periodic_dma, 0);
 	if (ehci->periodic == 0) {
 		goto fail;
 	}
--- diff/drivers/usb/host/ehci-q.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci-q.c	2004-02-18 09:04:01.000000000 +0000
@@ -776,7 +776,7 @@
 	qh = (struct ehci_qh *) *ptr;
 	if (unlikely (qh == 0)) {
 		/* can't sleep here, we have ehci->lock... */
-		qh = qh_make (ehci, urb, SLAB_ATOMIC);
+		qh = qh_make (ehci, urb, GFP_ATOMIC);
 		*ptr = qh;
 	}
 	if (likely (qh != 0)) {
--- diff/drivers/usb/host/ehci-sched.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci-sched.c	2004-02-18 09:04:01.000000000 +0000
@@ -490,33 +490,6 @@
 	return status;
 }
 
-static unsigned
-intr_complete (
-	struct ehci_hcd	*ehci,
-	unsigned	frame,
-	struct ehci_qh	*qh,
-	struct pt_regs	*regs
-) {
-	unsigned	count;
-
-	/* nothing to report? */
-	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
-			!= 0))
-		return 0;
-	if (unlikely (list_empty (&qh->qtd_list))) {
-		dbg ("intr qh %p no TDs?", qh);
-		return 0;
-	}
-	
-	/* handle any completions */
-	count = qh_completions (ehci, qh, regs);
-
-	if (unlikely (list_empty (&qh->qtd_list)))
-		intr_deschedule (ehci, qh, 0);
-
-	return count;
-}
-
 /*-------------------------------------------------------------------------*/
 
 static inline struct ehci_iso_stream *
@@ -605,7 +578,7 @@
 			itd = list_entry (stream->free_itd_list.next,
 				struct ehci_itd, itd_list);
 			list_del (&itd->itd_list);
-			pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+			dma_pool_free (ehci->itd_pool, itd, itd->itd_dma);
 		}
 
 		is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
@@ -718,7 +691,8 @@
 
 		trans = EHCI_ISOC_ACTIVE;
 		trans |= buf & 0x0fff;
-		if (unlikely ((i + 1) == urb->number_of_packets))
+		if (unlikely (((i + 1) == urb->number_of_packets))
+				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
 			trans |= EHCI_ITD_IOC;
 		trans |= length << 16;
 		uframe->transaction = cpu_to_le32 (trans);
@@ -786,7 +760,7 @@
 			list_del (&itd->itd_list);
 			itd_dma = itd->itd_dma;
 		} else
-			itd = pci_pool_alloc (ehci->itd_pool, mem_flags,
+			itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
 					&itd_dma);
 
 		if (unlikely (0 == itd)) {
@@ -809,7 +783,10 @@
  * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
  * "as small as possible" to be cache-friendlier.)  That limits the size
  * transfers you can stream reliably; avoid more than 64 msec per urb.
- * Also avoid queue depths of less than the system's worst irq latency.
+ * Also avoid queue depths of less than ehci's worst irq latency (affected
+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
+ * and other factors); or more than about 230 msec total (for portability,
+ * given EHCI_TUNE_FLS and the slop).  Or, write a smarter scheduler!
  */
 
 #define SCHEDULE_SLOP	10	/* frames */
@@ -1233,7 +1210,7 @@
 scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
 {
 	unsigned	frame, clock, now_uframe, mod;
-	unsigned	count = 0;
+	unsigned	modified;
 
 	mod = ehci->periodic_size << 3;
 
@@ -1244,47 +1221,50 @@
 	 */
 	now_uframe = ehci->next_uframe;
 	if (HCD_IS_RUNNING (ehci->hcd.state))
-		clock = readl (&ehci->regs->frame_index) % mod;
+		clock = readl (&ehci->regs->frame_index);
 	else
 		clock = now_uframe + mod - 1;
+	clock %= mod;
 
 	for (;;) {
 		union ehci_shadow	q, *q_p;
 		u32			type, *hw_p;
 		unsigned		uframes;
 
+		/* don't scan past the live uframe */
 		frame = now_uframe >> 3;
-restart:
-		/* scan schedule to _before_ current frame index */
-		if ((frame == (clock >> 3))
-				&& HCD_IS_RUNNING (ehci->hcd.state))
+		if (frame == (clock >> 3))
 			uframes = now_uframe & 0x07;
-		else
+		else {
+			/* safe to scan the whole frame at once */
+			now_uframe |= 0x07;
 			uframes = 8;
+		}
 
+restart:
+		/* scan each element in frame's queue for completions */
 		q_p = &ehci->pshadow [frame];
 		hw_p = &ehci->periodic [frame];
 		q.ptr = q_p->ptr;
 		type = Q_NEXT_TYPE (*hw_p);
+		modified = 0;
 
-		/* scan each element in frame's queue for completions */
 		while (q.ptr != 0) {
-			int			last;
 			unsigned		uf;
 			union ehci_shadow	temp;
 
 			switch (type) {
 			case Q_TYPE_QH:
-				last = (q.qh->hw_next == EHCI_LIST_END);
-				temp = q.qh->qh_next;
+				/* handle any completions */
+				temp.qh = qh_get (q.qh);
 				type = Q_NEXT_TYPE (q.qh->hw_next);
-				count += intr_complete (ehci, frame,
-						qh_get (q.qh), regs);
-				qh_put (ehci, q.qh);
-				q = temp;
+				q = q.qh->qh_next;
+				modified = qh_completions (ehci, temp.qh, regs);
+				if (unlikely (list_empty (&temp.qh->qtd_list)))
+					intr_deschedule (ehci, temp.qh, 0);
+				qh_put (ehci, temp.qh);
 				break;
 			case Q_TYPE_FSTN:
-				last = (q.fstn->hw_next == EHCI_LIST_END);
 				/* for "save place" FSTNs, look at QH entries
 				 * in the previous frame for completions.
 				 */
@@ -1295,8 +1275,6 @@
 				q = q.fstn->fstn_next;
 				break;
 			case Q_TYPE_ITD:
-				last = (q.itd->hw_next == EHCI_LIST_END);
-
 				/* skip itds for later in the frame */
 				rmb ();
 				for (uf = uframes; uf < 8; uf++) {
@@ -1317,31 +1295,24 @@
 				 */
 				*q_p = q.itd->itd_next;
 				*hw_p = q.itd->hw_next;
+				type = Q_NEXT_TYPE (q.itd->hw_next);
 				wmb();
-
-				/* always rescan here; simpler */
-				count += itd_complete (ehci, q.itd, regs);
-				goto restart;
+				modified = itd_complete (ehci, q.itd, regs);
+				q = *q_p;
+				break;
 #ifdef have_split_iso
 			case Q_TYPE_SITD:
-				last = (q.sitd->hw_next == EHCI_LIST_END);
-				sitd_complete (ehci, q.sitd);
-				type = Q_NEXT_TYPE (q.sitd->hw_next);
-
-				// FIXME unlink SITD after split completes
-				q = q.sitd->sitd_next;
-				break;
+				// nyet!
 #endif /* have_split_iso */
 			default:
 				dbg ("corrupt type %d frame %d shadow %p",
 					type, frame, q.ptr);
 				// BUG ();
-				last = 1;
 				q.ptr = 0;
 			}
 
-			/* did completion remove an interior q entry? */
-			if (unlikely (q.ptr == 0 && !last))
+			/* assume completion callbacks modify the queue */
+			if (unlikely (modified))
 				goto restart;
 		}
 
@@ -1368,9 +1339,6 @@
 			/* rescan the rest of this frame, then ... */
 			clock = now;
 		} else {
-			/* FIXME sometimes we can scan the next frame
-			 * right away, not always inching up on it ...
-			 */
 			now_uframe++;
 			now_uframe %= mod;
 		}
--- diff/drivers/usb/host/ehci.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/host/ehci.h	2004-02-18 09:04:01.000000000 +0000
@@ -74,11 +74,11 @@
 	struct ehci_regs	*regs;
 	u32			hcs_params;	/* cached register copy */
 
-	/* per-HC memory pools (could be per-PCI-bus, but ...) */
-	struct pci_pool		*qh_pool;	/* qh per active urb */
-	struct pci_pool		*qtd_pool;	/* one or more per qh */
-	struct pci_pool		*itd_pool;	/* itd per iso urb */
-	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+	/* per-HC memory pools (could be per-bus, but ...) */
+	struct dma_pool		*qh_pool;	/* qh per active urb */
+	struct dma_pool		*qtd_pool;	/* one or more per qh */
+	struct dma_pool		*itd_pool;	/* itd per iso urb */
+	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
 
 	struct timer_list	watchdog;
 	struct notifier_block	reboot_notifier;
--- diff/drivers/usb/host/ohci-dbg.c	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/usb/host/ohci-dbg.c	2004-02-18 09:04:01.000000000 +0000
@@ -76,7 +76,7 @@
 	do { \
 	if (next) { \
 		unsigned s_len; \
-		s_len = snprintf (*next, *size, format, ## arg ); \
+		s_len = scnprintf (*next, *size, format, ## arg ); \
 		*size -= s_len; *next += s_len; \
 	} else \
 		ohci_dbg(ohci,format, ## arg ); \
@@ -420,7 +420,7 @@
 		struct list_head	*entry;
 		struct td		*td;
 
-		temp = snprintf (buf, size,
+		temp = scnprintf (buf, size,
 			"ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
 			ed,
 			(info & ED_LOWSPEED) ? 'l' : 'f',
@@ -442,7 +442,7 @@
 			scratch = cpu_to_le32p (&td->hwINFO);
 			cbp = le32_to_cpup (&td->hwCBP);
 			be = le32_to_cpup (&td->hwBE);
-			temp = snprintf (buf, size,
+			temp = scnprintf (buf, size,
 					"\n\ttd %p %s %d cc=%x urb %p (%08x)",
 					td,
 					({ char *pid;
@@ -458,7 +458,7 @@
 			buf += temp;
 		}
 
-		temp = snprintf (buf, size, "\n");
+		temp = scnprintf (buf, size, "\n");
 		size -= temp;
 		buf += temp;
 
@@ -515,7 +515,7 @@
 	next = buf;
 	size = PAGE_SIZE;
 
-	temp = snprintf (next, size, "size = %d\n", NUM_INTS);
+	temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
 	size -= temp;
 	next += temp;
 
@@ -525,12 +525,12 @@
 		if (!(ed = ohci->periodic [i]))
 			continue;
 
-		temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
+		temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
 		size -= temp;
 		next += temp;
 
 		do {
-			temp = snprintf (next, size, " ed%d/%p",
+			temp = scnprintf (next, size, " ed%d/%p",
 				ed->interval, ed);
 			size -= temp;
 			next += temp;
@@ -550,7 +550,7 @@
 				list_for_each (entry, &ed->td_list)
 					qlen++;
 
-				temp = snprintf (next, size,
+				temp = scnprintf (next, size,
 					" (%cs dev%d ep%d%s-%s qlen %u"
 					" max %d %08x%s%s)",
 					(info & ED_LOWSPEED) ? 'l' : 'f',
@@ -579,7 +579,7 @@
 
 		} while (ed);
 
-		temp = snprintf (next, size, "\n");
+		temp = scnprintf (next, size, "\n");
 		size -= temp;
 		next += temp;
 	}
@@ -628,7 +628,7 @@
 
 	/* other registers mostly affect frame timings */
 	rdata = readl (&regs->fminterval);
-	temp = snprintf (next, size,
+	temp = scnprintf (next, size,
 			"fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
 			rdata, (rdata >> 31) ? " FIT" : "",
 			(rdata >> 16) & 0xefff, rdata & 0xffff);
@@ -636,20 +636,20 @@
 	next += temp;
 
 	rdata = readl (&regs->fmremaining);
-	temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
+	temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
 			rdata, (rdata >> 31) ? " FRT" : "",
 			rdata & 0x3fff);
 	size -= temp;
 	next += temp;
 
 	rdata = readl (&regs->periodicstart);
-	temp = snprintf (next, size, "periodicstart 0x%04x\n",
+	temp = scnprintf (next, size, "periodicstart 0x%04x\n",
 			rdata & 0x3fff);
 	size -= temp;
 	next += temp;
 
 	rdata = readl (&regs->lsthresh);
-	temp = snprintf (next, size, "lsthresh 0x%04x\n",
+	temp = scnprintf (next, size, "lsthresh 0x%04x\n",
 			rdata & 0x3fff);
 	size -= temp;
 	next += temp;
--- diff/drivers/usb/host/ohci-hcd.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ohci-hcd.c	2004-02-18 09:04:01.000000000 +0000
@@ -17,6 +17,7 @@
  *
  * History:
  * 
+ * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
  * 2003/02/24 show registers in sysfs (Kevin Brosius)
  *
  * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
@@ -96,6 +97,8 @@
 #include <linux/interrupt.h>  /* for in_interrupt () */
 #include <linux/usb.h>
 #include "../core/hcd.h"
+#include <linux/dma-mapping.h> 
+#include <linux/dmapool.h>    /* needed by ohci-mem.c when no PCI */
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -642,8 +645,9 @@
 	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
-		pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
-					ohci->hcca, ohci->hcca_dma);
+		dma_free_coherent (ohci->hcd.self.controller, 
+				sizeof *ohci->hcca, 
+				ohci->hcca, ohci->hcca_dma);
 		ohci->hcca = NULL;
 		ohci->hcca_dma = 0;
 	}
--- diff/drivers/usb/host/ohci-mem.c	2003-08-20 14:16:31.000000000 +0100
+++ source/drivers/usb/host/ohci-mem.c	2004-02-18 09:04:01.000000000 +0000
@@ -13,7 +13,7 @@
  * There's basically three types of memory:
  *	- data used only by the HCD ... kmalloc is fine
  *	- async and periodic schedules, shared by HC and HCD ... these
- *	  need to use pci_pool or pci_alloc_consistent
+ *	  need to use dma_pool or dma_alloc_coherent
  *	- driver buffers, read/written by HC ... the hcd glue or the
  *	  device driver provides us with dma addresses
  *
@@ -45,18 +45,18 @@
 
 static int ohci_mem_init (struct ohci_hcd *ohci)
 {
-	ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
+	ohci->td_cache = dma_pool_create ("ohci_td", ohci->hcd.self.controller,
 		sizeof (struct td),
 		32 /* byte alignment */,
 		0 /* no page-crossing issues */);
 	if (!ohci->td_cache)
 		return -ENOMEM;
-	ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
+	ohci->ed_cache = dma_pool_create ("ohci_ed", ohci->hcd.self.controller,
 		sizeof (struct ed),
 		16 /* byte alignment */,
 		0 /* no page-crossing issues */);
 	if (!ohci->ed_cache) {
-		pci_pool_destroy (ohci->td_cache);
+		dma_pool_destroy (ohci->td_cache);
 		return -ENOMEM;
 	}
 	return 0;
@@ -65,11 +65,11 @@
 static void ohci_mem_cleanup (struct ohci_hcd *ohci)
 {
 	if (ohci->td_cache) {
-		pci_pool_destroy (ohci->td_cache);
+		dma_pool_destroy (ohci->td_cache);
 		ohci->td_cache = 0;
 	}
 	if (ohci->ed_cache) {
-		pci_pool_destroy (ohci->ed_cache);
+		dma_pool_destroy (ohci->ed_cache);
 		ohci->ed_cache = 0;
 	}
 }
@@ -96,7 +96,7 @@
 	dma_addr_t	dma;
 	struct td	*td;
 
-	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+	td = dma_pool_alloc (hc->td_cache, mem_flags, &dma);
 	if (td) {
 		/* in case hc fetches it, make it look dead */
 		memset (td, 0, sizeof *td);
@@ -118,7 +118,7 @@
 		*prev = td->td_hash;
 	else if ((td->hwINFO & TD_DONE) != 0)
 		ohci_dbg (hc, "no hash for td %p\n", td);
-	pci_pool_free (hc->td_cache, td, td->td_dma);
+	dma_pool_free (hc->td_cache, td, td->td_dma);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -130,7 +130,7 @@
 	dma_addr_t	dma;
 	struct ed	*ed;
 
-	ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
+	ed = dma_pool_alloc (hc->ed_cache, mem_flags, &dma);
 	if (ed) {
 		memset (ed, 0, sizeof (*ed));
 		INIT_LIST_HEAD (&ed->td_list);
@@ -142,6 +142,6 @@
 static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
-	pci_pool_free (hc->ed_cache, ed, ed->dma);
+	dma_pool_free (hc->ed_cache, ed, ed->dma);
 }
 
--- diff/drivers/usb/host/ohci-omap.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ohci-omap.c	2004-02-18 09:04:01.000000000 +0000
@@ -388,9 +388,7 @@
 	hcd->description = driver->description;
 	hcd->irq = dev->irq[0];
 	hcd->regs = dev->mapbase;
-	hcd->pdev = OMAP_FAKE_PCIDEV;
 	hcd->self.controller = &dev->dev;
-	hcd->controller = hcd->self.controller;
 
 	retval = hcd_buffer_create (hcd);
 	if (retval != 0) {
@@ -494,12 +492,10 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	if (hcd->pdev) {
-		ohci->hcca = pci_alloc_consistent (hcd->pdev,
-				sizeof *ohci->hcca, &ohci->hcca_dma);
-		if (!ohci->hcca)
-			return -ENOMEM;
-	}
+	ohci->hcca = dma_alloc_consistent (hcd->self.controller,
+			sizeof *ohci->hcca, &ohci->hcca_dma);
+	if (!ohci->hcca)
+		return -ENOMEM;
 
         memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 	if ((ret = ohci_mem_init (ohci)) < 0) {
--- diff/drivers/usb/host/ohci-pci.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ohci-pci.c	2004-02-18 09:04:01.000000000 +0000
@@ -45,17 +45,19 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	if (hcd->pdev) {
-		ohci->hcca = pci_alloc_consistent (hcd->pdev,
-				sizeof *ohci->hcca, &ohci->hcca_dma);
-		if (!ohci->hcca)
-			return -ENOMEM;
+	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
+			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+	if (!ohci->hcca)
+		return -ENOMEM;
+
+	if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
 		/* AMD 756, for most chips (early revs), corrupts register
 		 * values on read ... so enable the vendor workaround.
 		 */
-		if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD
-				&& hcd->pdev->device == 0x740c) {
+		if (pdev->vendor == PCI_VENDOR_ID_AMD
+				&& pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
 			ohci_info (ohci, "AMD756 erratum 4 workaround\n");
 		}
@@ -68,8 +70,8 @@
 		 * for this chip.  Evidently control and bulk lists
 		 * can get confused.  (B&W G3 models, and ...)
 		 */
-		else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI
-				&& hcd->pdev->device == 0xc861) {
+		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
+				&& pdev->device == 0xc861) {
 			ohci_info (ohci,
 				"WARNING: OPTi workarounds unavailable\n");
 		}
@@ -78,12 +80,11 @@
 		 * identify the USB (fn2). This quirk might apply to more or
 		 * even all NSC stuff.
 		 */
-		else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {
-			struct pci_dev	*b, *hc;
+		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
+			struct pci_dev	*b;
 
-			hc = hcd->pdev;
-			b  = pci_find_slot (hc->bus->number,
-					PCI_DEVFN (PCI_SLOT (hc->devfn), 1));
+			b  = pci_find_slot (pdev->bus->number,
+					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
 			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
 					&& b->vendor == PCI_VENDOR_ID_NS) {
 				ohci->flags |= OHCI_QUIRK_SUPERIO;
@@ -145,7 +146,7 @@
 		
 #ifdef CONFIG_PMAC_PBOOK
 	if (_machine == _MACH_Pmac)
-		disable_irq (hcd->pdev->irq);
+		disable_irq ((to_pci_dev(hcd->self.controller))->irq);
  	/* else, 2.4 assumes shared irqs -- don't disable */
 #endif
 
@@ -179,15 +180,17 @@
 	 * memory during sleep. We disable its bus master bit during
 	 * suspend
 	 */
-	pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+	pci_read_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND, 
+				&cmd);
 	cmd &= ~PCI_COMMAND_MASTER;
-	pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+	pci_write_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND, 
+				cmd);
 #ifdef CONFIG_PMAC_PBOOK
 	{
 	   	struct device_node	*of_node;
  
 		/* Disable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (hcd->pdev);
+		of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
 		if (of_node)
 			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
 	}
@@ -207,7 +210,7 @@
 		struct device_node *of_node;
 
 		/* Re-enable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (hcd->pdev);
+		of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
 		if (of_node)
 			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
 	}
@@ -222,7 +225,7 @@
 #endif
 
 	/* Re-enable bus mastering */
-	pci_set_master (ohci->hcd.pdev);
+	pci_set_master (to_pci_dev(ohci->hcd.self.controller));
 	
 	switch (temp) {
 
@@ -282,7 +285,7 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 		if (_machine == _MACH_Pmac)
-			enable_irq (hcd->pdev->irq);
+			enable_irq (to_pci_dev(hcd->self.controller)->irq);
 #endif
 
 		/* Check for a pending done list */
--- diff/drivers/usb/host/ohci-q.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ohci-q.c	2004-02-18 09:04:01.000000000 +0000
@@ -375,7 +375,7 @@
 	if (!(ed = dev->ep [ep])) {
 		struct td	*td;
 
-		ed = ed_alloc (ohci, SLAB_ATOMIC);
+		ed = ed_alloc (ohci, GFP_ATOMIC);
 		if (!ed) {
 			/* out of memory */
 			goto done;
@@ -383,7 +383,7 @@
 		dev->ep [ep] = ed;
 
   		/* dummy td; end of td list for ed */
-		td = td_alloc (ohci, SLAB_ATOMIC);
+		td = td_alloc (ohci, GFP_ATOMIC);
  		if (!td) {
 			/* out of memory */
 			ed_free (ohci, ed);
--- diff/drivers/usb/host/ohci-sa1111.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/ohci-sa1111.c	2004-02-18 09:04:01.000000000 +0000
@@ -167,9 +167,7 @@
 	hcd->description = driver->description;
 	hcd->irq = dev->irq[1];
 	hcd->regs = dev->mapbase;
-	hcd->pdev = SA1111_FAKE_PCIDEV;
 	hcd->self.controller = &dev->dev;
-	hcd->controller = hcd->self.controller;
 
 	retval = hcd_buffer_create (hcd);
 	if (retval != 0) {
@@ -270,14 +268,12 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	if (hcd->pdev) {
-		ohci->hcca = pci_alloc_consistent (hcd->pdev,
-				sizeof *ohci->hcca, &ohci->hcca_dma);
-		if (!ohci->hcca)
-			return -ENOMEM;
-	}
-
-        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
+			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+	if (!ohci->hcca)
+		return -ENOMEM;
+        
+	memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 	if ((ret = ohci_mem_init (ohci)) < 0) {
 		ohci_stop (hcd);
 		return ret;
--- diff/drivers/usb/host/ohci.h	2004-01-19 10:22:58.000000000 +0000
+++ source/drivers/usb/host/ohci.h	2004-02-18 09:04:01.000000000 +0000
@@ -361,8 +361,8 @@
 	/*
 	 * memory management for queue data structures
 	 */
-	struct pci_pool		*td_cache;
-	struct pci_pool		*ed_cache;
+	struct dma_pool		*td_cache;
+	struct dma_pool		*ed_cache;
 	struct td		*td_hash [TD_HASH_SIZE];
 
 	/*
@@ -391,13 +391,13 @@
 #endif	/* DEBUG */
 
 #define ohci_dbg(ohci, fmt, args...) \
-	dev_dbg ((ohci)->hcd.controller , fmt , ## args )
+	dev_dbg ((ohci)->hcd.self.controller , fmt , ## args )
 #define ohci_err(ohci, fmt, args...) \
-	dev_err ((ohci)->hcd.controller , fmt , ## args )
+	dev_err ((ohci)->hcd.self.controller , fmt , ## args )
 #define ohci_info(ohci, fmt, args...) \
-	dev_info ((ohci)->hcd.controller , fmt , ## args )
+	dev_info ((ohci)->hcd.self.controller , fmt , ## args )
 #define ohci_warn(ohci, fmt, args...) \
-	dev_warn ((ohci)->hcd.controller , fmt , ## args )
+	dev_warn ((ohci)->hcd.self.controller , fmt , ## args )
 
 #ifdef OHCI_VERBOSE_DEBUG
 #	define ohci_vdbg ohci_dbg
--- diff/drivers/usb/host/uhci-debug.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/usb/host/uhci-debug.c	2004-02-18 09:04:01.000000000 +0000
@@ -321,8 +321,8 @@
 	out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
 	out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
 
-	if (urbp->status != -EINPROGRESS)
-		out += sprintf(out, "Status=%d ", urbp->status);
+	if (urbp->urb->status != -EINPROGRESS)
+		out += sprintf(out, "Status=%d ", urbp->urb->status);
 	//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
 	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
 
@@ -402,7 +402,7 @@
 		head = &uhci->complete_list;
 		tmp = head->next;
 		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
 
 			out += sprintf(out, "  %d: ", ++count);
 			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
@@ -418,7 +418,7 @@
 {
 	unsigned long flags;
 	char *out = buf;
-	int i;
+	int i, j;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
@@ -473,10 +473,11 @@
 			continue;
 		}
 
+		j = (i < 7) ? 7 : i+1;		/* Next skeleton */
 		if (list_empty(&qh->list)) {
 			if (i < UHCI_NUM_SKELQH - 1) {
 				if (qh->link !=
-				    (cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH)) {
+				    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
 					show_qh_name();
 					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
 				}
@@ -500,7 +501,7 @@
 
 		if (i < UHCI_NUM_SKELQH - 1) {
 			if (qh->link !=
-			    (cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH))
+			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
 				out += sprintf(out, "    last QH not linked to next skeleton!\n");
 		}
 	}
--- diff/drivers/usb/host/uhci-hcd.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.c	2004-02-18 09:04:01.000000000 +0000
@@ -41,6 +41,8 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/proc_fs.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
 #ifdef CONFIG_USB_DEBUG
 #define DEBUG
 #else
@@ -48,6 +50,7 @@
 #endif
 #include <linux/usb.h>
 
+#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -80,7 +83,7 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug level");
 static char *errbuf;
-#define ERRBUF_LEN    (PAGE_SIZE * 8)
+#define ERRBUF_LEN    (32 * 1024)
 
 #include "uhci-hub.c"
 #include "uhci-debug.c"
@@ -121,21 +124,17 @@
 
 static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	spin_lock(&uhci->frame_list_lock);
 	uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+	spin_unlock(&uhci->frame_list_lock);
 }
 
-static inline void uhci_add_complete(struct uhci_hcd *uhci, struct urb *urb)
+static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
+					struct urb_priv *urbp)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	list_add_tail(&urbp->complete_list, &uhci->complete_list);
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+	spin_lock(&uhci->complete_list_lock);
+	list_move_tail(&urbp->urb_list, &uhci->complete_list);
+	spin_unlock(&uhci->complete_list_lock);
 }
 
 static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
@@ -143,7 +142,7 @@
 	dma_addr_t dma_handle;
 	struct uhci_td *td;
 
-	td = pci_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
+	td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
 	if (!td)
 		return NULL;
 
@@ -295,7 +294,7 @@
 	if (td->dev)
 		usb_put_dev(td->dev);
 
-	pci_pool_free(uhci->td_pool, td, td->dma_handle);
+	dma_pool_free(uhci->td_pool, td, td->dma_handle);
 }
 
 static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
@@ -303,7 +302,7 @@
 	dma_addr_t dma_handle;
 	struct uhci_qh *qh;
 
-	qh = pci_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
+	qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
 	if (!qh)
 		return NULL;
 
@@ -333,7 +332,7 @@
 	if (qh->dev)
 		usb_put_dev(qh->dev);
 
-	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
 /*
@@ -671,7 +670,6 @@
 	
 	INIT_LIST_HEAD(&urbp->td_list);
 	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->complete_list);
 	INIT_LIST_HEAD(&urbp->urb_list);
 
 	list_add_tail(&urbp->urb_list, &uhci->urb_list);
@@ -722,9 +720,6 @@
 	if (!list_empty(&urbp->urb_list))
 		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
 
-	if (!list_empty(&urbp->complete_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
-
 	spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
@@ -913,7 +908,7 @@
 
 	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
 
-	/* Low speed transfers get a different queue, and won't hog the bus */
+	/* Low-speed transfers get a different queue, and won't hog the bus */
 	if (urb->dev->speed == USB_SPEED_LOW)
 		skelqh = uhci->skel_ls_control_qh;
 	else {
@@ -971,7 +966,7 @@
 	/* One TD, who cares about Breadth first? */
 	uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH);
 
-	/* Low speed transfers get a different queue */
+	/* Low-speed transfers get a different queue */
 	if (urb->dev->speed == USB_SPEED_LOW)
 		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	else
@@ -1255,7 +1250,7 @@
 {
 	int ret;
 
-	/* Can't have low speed bulk transfers */
+	/* Can't have low-speed bulk transfers */
 	if (urb->dev->speed == USB_SPEED_LOW)
 		return -EINVAL;
 
@@ -1462,11 +1457,14 @@
 
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
 
+	if (urb->status != -EINPROGRESS)	/* URB already unlinked! */
+		goto out;
+
 	eurb = uhci_find_urb_ep(uhci, urb);
 
 	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out;
 	}
 
 	switch (usb_pipetype(urb->pipe)) {
@@ -1514,10 +1512,11 @@
 
 		return ret;
 	}
+	ret = 0;
 
+out:
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	return 0;
+	return ret;
 }
 
 /*
@@ -1527,18 +1526,15 @@
  */
 static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
 {
-	int ret = -EINVAL;
-	unsigned long flags;
+	int ret = -EINPROGRESS;
 	struct urb_priv *urbp;
 
-	spin_lock_irqsave(&urb->lock, flags);
+	spin_lock(&urb->lock);
 
 	urbp = (struct urb_priv *)urb->hcpriv;
 
-	if (urb->status != -EINPROGRESS) {
-		info("uhci_transfer_result: called for URB %p not in flight?", urb);
+	if (urb->status != -EINPROGRESS)	/* URB already dequeued */
 		goto out;
-	}
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
@@ -1555,10 +1551,9 @@
 		break;
 	}
 
-	urbp->status = ret;
-
 	if (ret == -EINPROGRESS)
 		goto out;
+	urb->status = ret;
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
@@ -1589,13 +1584,11 @@
 			usb_pipetype(urb->pipe), urb);
 	}
 
-	/* Remove it from uhci->urb_list */
-	list_del_init(&urbp->urb_list);
-
-	uhci_add_complete(uhci, urb);
+	/* Move it from uhci->urb_list to uhci->complete_list */
+	uhci_moveto_complete(uhci, urbp);
 
 out:
-	spin_unlock_irqrestore(&urb->lock, flags);
+	spin_unlock(&urb->lock);
 }
 
 /*
@@ -1607,10 +1600,6 @@
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	int prevactive = 1;
 
-	/* We can get called when urbp allocation fails, so check */
-	if (!urbp)
-		return;
-
 	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
 
 	/*
@@ -1660,13 +1649,6 @@
 	unsigned long flags;
 	struct urb_priv *urbp = urb->hcpriv;
 
-	/* If this is an interrupt URB that is being killed in urb->complete, */
-	/* then just set its status and return */
-	if (!urbp) {
-	  urb->status = -ECONNRESET;
-	  return 0;
-	}
-
 	spin_lock_irqsave(&uhci->urb_list_lock, flags);
 
 	list_del_init(&urbp->urb_list);
@@ -1678,7 +1660,7 @@
 	/* If we're the first, set the next interrupt bit */
 	if (list_empty(&uhci->urb_remove_list))
 		uhci_set_next_interrupt(uhci);
-	list_add(&urbp->urb_list, &uhci->urb_remove_list);
+	list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
 
 	spin_unlock(&uhci->urb_remove_list_lock);
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
@@ -1805,9 +1787,8 @@
 static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
 {
 	struct list_head *tmp, *head;
-	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+	spin_lock(&uhci->qh_remove_list_lock);
 	head = &uhci->qh_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1819,15 +1800,14 @@
 
 		uhci_free_qh(uhci, qh);
 	}
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+	spin_unlock(&uhci->qh_remove_list_lock);
 }
 
 static void uhci_free_pending_tds(struct uhci_hcd *uhci)
 {
 	struct list_head *tmp, *head;
-	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
+	spin_lock(&uhci->td_remove_list_lock);
 	head = &uhci->td_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1839,23 +1819,16 @@
 
 		uhci_free_td(uhci, td);
 	}
-	spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags);
+	spin_unlock(&uhci->td_remove_list_lock);
 }
 
 static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	int status;
-	unsigned long flags;
 
-	spin_lock_irqsave(&urb->lock, flags);
-	status = urbp->status;
+	spin_lock(&urb->lock);
 	uhci_destroy_urb_priv(uhci, urb);
-
- 	if (urb->status != -ENOENT && urb->status != -ECONNRESET)
-		urb->status = status;
-	spin_unlock_irqrestore(&urb->lock, flags);
+	spin_unlock(&urb->lock);
 
 	usb_hcd_giveback_urb(hcd, urb, regs);
 }
@@ -1864,48 +1837,40 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct list_head *tmp, *head;
-	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	spin_lock(&uhci->complete_list_lock);
 	head = &uhci->complete_list;
 	tmp = head->next;
 	while (tmp != head) {
-		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
 		struct urb *urb = urbp->urb;
 
-		list_del_init(&urbp->complete_list);
-		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+		list_del_init(&urbp->urb_list);
+		spin_unlock(&uhci->complete_list_lock);
 
 		uhci_finish_urb(hcd, urb, regs);
 
-		spin_lock_irqsave(&uhci->complete_list_lock, flags);
+		spin_lock(&uhci->complete_list_lock);
 		head = &uhci->complete_list;
 		tmp = head->next;
 	}
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+	spin_unlock(&uhci->complete_list_lock);
 }
 
-static void uhci_remove_pending_qhs(struct uhci_hcd *uhci)
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
 {
 	struct list_head *tmp, *head;
-	unsigned long flags;
 
-	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
+	spin_lock(&uhci->urb_remove_list_lock);
 	head = &uhci->urb_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
 		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-		struct urb *urb = urbp->urb;
 
 		tmp = tmp->next;
-
-		list_del_init(&urbp->urb_list);
-
-		urbp->status = urb->status = -ECONNRESET;
-
-		uhci_add_complete(uhci, urb);
+		uhci_moveto_complete(uhci, urbp);
 	}
-	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
+	spin_unlock(&uhci->urb_remove_list_lock);
 }
 
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
@@ -1917,10 +1882,11 @@
 
 	/*
 	 * Read the interrupt status, and write it back to clear the
-	 * interrupt cause
+	 * interrupt cause.  Contrary to the UHCI specification, the
+	 * "HC Halted" status bit is persistent: it is RO, not R/WC.
 	 */
 	status = inw(io_addr + USBSTS);
-	if (!status)	/* shared interrupt, not mine */
+	if (!(status & ~USBSTS_HCH))	/* shared interrupt, not mine */
 		return IRQ_NONE;
 	outw(status, io_addr + USBSTS);		/* Clear it */
 
@@ -1942,7 +1908,7 @@
 
 	uhci_free_pending_tds(uhci);
 
-	uhci_remove_pending_qhs(uhci);
+	uhci_remove_pending_urbps(uhci);
 
 	uhci_clear_next_interrupt(uhci);
 
@@ -2049,7 +2015,8 @@
 	unsigned int io_addr = uhci->io_addr;
 	int i;
 
-	if (!uhci->hcd.pdev || uhci->hcd.pdev->vendor != PCI_VENDOR_ID_INTEL)
+	if (!uhci->hcd.self.controller || 
+		to_pci_dev(uhci->hcd.self.controller)->vendor != PCI_VENDOR_ID_INTEL)
 		return 1;
 
 	/* Some of Intel's USB controllers have a bug that causes false
@@ -2163,17 +2130,17 @@
 	}
 
 	if (uhci->qh_pool) {
-		pci_pool_destroy(uhci->qh_pool);
+		dma_pool_destroy(uhci->qh_pool);
 		uhci->qh_pool = NULL;
 	}
 
 	if (uhci->td_pool) {
-		pci_pool_destroy(uhci->td_pool);
+		dma_pool_destroy(uhci->td_pool);
 		uhci->td_pool = NULL;
 	}
 
 	if (uhci->fl) {
-		pci_free_consistent(uhci->hcd.pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+		dma_free_coherent(uhci->hcd.self.controller, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
 		uhci->fl = NULL;
 	}
 
@@ -2198,7 +2165,7 @@
 	 * interrupts from any previous setup.
 	 */
 	reset_hc(uhci);
-	pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+	pci_write_config_word(to_pci_dev(hcd->self.controller), USBLEGSUP, USBLEGSUP_DEFAULT);
 	return 0;
 }
 
@@ -2213,10 +2180,10 @@
  *    of the queues. We don't do that here, because
  *    we'll create the actual TD entries on demand.
  *  - The first queue is the interrupt queue.
- *  - The second queue is the control queue, split into low and high speed
+ *  - The second queue is the control queue, split into low- and full-speed
  *  - The third queue is bulk queue.
  *  - The fourth queue is the bandwidth reclamation queue, which loops back
- *    to the high speed control queue.
+ *    to the full-speed control queue.
  */
 static int uhci_start(struct usb_hcd *hcd)
 {
@@ -2230,7 +2197,7 @@
 	struct proc_dir_entry *ent;
 #endif
 
-	io_size = pci_resource_len(hcd->pdev, hcd->region);
+	io_size = pci_resource_len(to_pci_dev(hcd->self.controller), hcd->region);
 
 #ifdef CONFIG_PROC_FS
 	ent = create_proc_entry(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
@@ -2266,7 +2233,8 @@
 
 	spin_lock_init(&uhci->frame_list_lock);
 
-	uhci->fl = pci_alloc_consistent(hcd->pdev, sizeof(*uhci->fl), &dma_handle);
+	uhci->fl = dma_alloc_coherent(hcd->self.controller, 
+			sizeof(*uhci->fl), &dma_handle, 0);
 	if (!uhci->fl) {
 		err("unable to allocate consistent memory for frame list");
 		goto err_alloc_fl;
@@ -2276,17 +2244,17 @@
 
 	uhci->fl->dma_handle = dma_handle;
 
-	uhci->td_pool = pci_pool_create("uhci_td", hcd->pdev,
+	uhci->td_pool = dma_pool_create("uhci_td", hcd->self.controller,
 		sizeof(struct uhci_td), 16, 0);
 	if (!uhci->td_pool) {
-		err("unable to create td pci_pool");
+		err("unable to create td dma_pool");
 		goto err_create_td_pool;
 	}
 
-	uhci->qh_pool = pci_pool_create("uhci_qh", hcd->pdev,
+	uhci->qh_pool = dma_pool_create("uhci_qh", hcd->self.controller,
 		sizeof(struct uhci_qh), 16, 0);
 	if (!uhci->qh_pool) {
-		err("unable to create qh pci_pool");
+		err("unable to create qh dma_pool");
 		goto err_create_qh_pool;
 	}
 
@@ -2336,16 +2304,17 @@
 	}
 
 	/*
-	 * 8 Interrupt queues; link int2 to int1, int4 to int2, etc
+	 * 8 Interrupt queues; link all higher int queues to int1,
 	 * then link int1 to control and control to bulk
 	 */
-	uhci->skel_int128_qh->link = cpu_to_le32(uhci->skel_int64_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int64_qh->link = cpu_to_le32(uhci->skel_int32_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int32_qh->link = cpu_to_le32(uhci->skel_int16_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int16_qh->link = cpu_to_le32(uhci->skel_int8_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int8_qh->link = cpu_to_le32(uhci->skel_int4_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int4_qh->link = cpu_to_le32(uhci->skel_int2_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int2_qh->link = cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
+	uhci->skel_int128_qh->link =
+			uhci->skel_int64_qh->link =
+			uhci->skel_int32_qh->link =
+			uhci->skel_int16_qh->link =
+			uhci->skel_int8_qh->link =
+			uhci->skel_int4_qh->link =
+			uhci->skel_int2_qh->link =
+			cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
 	uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
 
 	uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH;
@@ -2361,39 +2330,33 @@
 	uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
 
 	/*
-	 * Fill the frame list: make all entries point to
-	 * the proper interrupt queue.
+	 * Fill the frame list: make all entries point to the proper
+	 * interrupt queue.
 	 *
-	 * This is probably silly, but it's a simple way to
-	 * scatter the interrupt queues in a way that gives
-	 * us a reasonable dynamic range for irq latencies.
+	 * The interrupt queues will be interleaved as evenly as possible.
+	 * There's not much to be done about period-1 interrupts; they have
+	 * to occur in every frame.  But we can schedule period-2 interrupts
+	 * in odd-numbered frames, period-4 interrupts in frames congruent
+	 * to 2 (mod 4), and so on.  This way each frame only has two
+	 * interrupt QHs, which will help spread out bandwidth utilization.
 	 */
 	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq = 0;
+		int irq;
 
-		if (i & 1) {
-			irq++;
-			if (i & 2) {
-				irq++;
-				if (i & 4) { 
-					irq++;
-					if (i & 8) { 
-						irq++;
-						if (i & 16) {
-							irq++;
-							if (i & 32) {
-								irq++;
-								if (i & 64)
-									irq++;
-							}
-						}
-					}
-				}
-			}
-		}
+		/*
+		 * ffs (Find First bit Set) does exactly what we need:
+		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],
+		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
+		 * ffs > 6 => not on any high-period queue, so use
+		 *	skel_int1_qh = skelqh[7].
+		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
+		 */
+		irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
+		if (irq < 0)
+			irq = 7;
 
 		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[7 - irq]->dma_handle);
+		uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle);
 	}
 
 	start_hc(uhci);
@@ -2402,7 +2365,7 @@
 
 	udev->speed = USB_SPEED_FULL;
 
-	if (usb_register_root_hub(udev, &hcd->pdev->dev) != 0) {
+	if (usb_register_root_hub(udev, hcd->self.controller) != 0) {
 		err("unable to start root hub");
 		retval = -ENOMEM;
 		goto err_start_root_hub;
@@ -2433,15 +2396,16 @@
 	hcd->self.root_hub = NULL;
 
 err_alloc_root_hub:
-	pci_pool_destroy(uhci->qh_pool);
+	dma_pool_destroy(uhci->qh_pool);
 	uhci->qh_pool = NULL;
 
 err_create_qh_pool:
-	pci_pool_destroy(uhci->td_pool);
+	dma_pool_destroy(uhci->td_pool);
 	uhci->td_pool = NULL;
 
 err_create_td_pool:
-	pci_free_consistent(hcd->pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+	dma_free_coherent(hcd->self.controller, 
+			sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
 	uhci->fl = NULL;
 
 err_alloc_fl:
@@ -2458,6 +2422,7 @@
 static void uhci_stop(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	unsigned long flags;
 
 	del_timer_sync(&uhci->stall_timer);
 
@@ -2465,15 +2430,17 @@
 	 * At this point, we're guaranteed that no new connects can be made
 	 * to this bus since there are no more parents
 	 */
+	local_irq_save(flags);
 	uhci_free_pending_qhs(uhci);
 	uhci_free_pending_tds(uhci);
-	uhci_remove_pending_qhs(uhci);
+	uhci_remove_pending_urbps(uhci);
 
 	reset_hc(uhci);
 
 	uhci_free_pending_qhs(uhci);
 	uhci_free_pending_tds(uhci);
-
+	local_irq_restore(flags);
+	
 	release_uhci(uhci);
 }
 
@@ -2494,7 +2461,7 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	pci_set_master(uhci->hcd.pdev);
+	pci_set_master(to_pci_dev(uhci->hcd.self.controller));
 
 	if (uhci->state == UHCI_SUSPENDED)
 		uhci->resume_detect = 1;
--- diff/drivers/usb/host/uhci-hcd.h	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/host/uhci-hcd.h	2004-02-18 09:04:01.000000000 +0000
@@ -200,8 +200,8 @@
  * The UHCI driver places Interrupt, Control and Bulk into QH's both
  * to group together TD's for one transfer, and also to faciliate queuing
  * of URB's. To make it easy to insert entries into the schedule, we have
- * a skeleton of QH's for each predefined Interrupt latency, low speed
- * control, high speed control and terminating QH (see explanation for
+ * a skeleton of QH's for each predefined Interrupt latency, low-speed
+ * control, full-speed control and terminating QH (see explanation for
  * the terminating QH below).
  *
  * When we want to add a new QH, we add it to the end of the list for the
@@ -216,9 +216,9 @@
  * skel int32 QH
  * ...
  * skel int1 QH
- * skel low speed control QH
+ * skel low-speed control QH
  * dev 5 control QH
- * skel high speed control QH
+ * skel full-speed control QH
  * skel bulk QH
  * dev 1 bulk QH
  * dev 2 bulk QH
@@ -227,7 +227,7 @@
  * The terminating QH is used for 2 reasons:
  * - To place a terminating TD which is used to workaround a PIIX bug
  *   (see Intel errata for explanation)
- * - To loop back to the high speed control queue for full speed bandwidth
+ * - To loop back to the full-speed control queue for full-speed bandwidth
  *   reclamation
  *
  * Isochronous transfers are stored before the start of the skeleton
@@ -326,8 +326,8 @@
 	/* Grabbed from PCI */
 	unsigned long io_addr;
 
-	struct pci_pool *qh_pool;
-	struct pci_pool *td_pool;
+	struct dma_pool *qh_pool;
+	struct dma_pool *td_pool;
 
 	struct usb_bus *bus;
 
@@ -336,7 +336,7 @@
 
 	spinlock_t frame_list_lock;
 	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
-	int fsbr;				/* Full speed bandwidth reclamation */
+	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
 	enum uhci_state state;			/* FIXME: needs a spinlock */
@@ -383,13 +383,10 @@
 					/*  a control transfer, retrigger */
 					/*  the status phase */
 
-	int status;			/* Final status */
-
 	unsigned long inserttime;	/* In jiffies */
 	unsigned long fsbrtime;		/* In jiffies */
 
 	struct list_head queue_list;	/* P: uhci->frame_list_lock */
-	struct list_head complete_list;	/* P: uhci->complete_list_lock */
 };
 
 /*
--- diff/drivers/usb/input/hid-core.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/input/hid-core.c	2004-02-18 09:04:01.000000000 +0000
@@ -224,6 +224,9 @@
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	if (usages < parser->global.report_count)
+		usages = parser->global.report_count;
+
 	if (usages == 0)
 		return 0; /* ignore padding fields */
 
@@ -235,9 +238,13 @@
 	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
 	for (i = 0; i < usages; i++) {
-		field->usage[i].hid = parser->local.usage[i];
+		int j = i;
+		/* Duplicate the last usage we parsed if we have excess values */
+		if (i >= parser->local.usage_index)
+			j = parser->local.usage_index - 1;
+		field->usage[i].hid = parser->local.usage[j];
 		field->usage[i].collection_index =
-			parser->local.collection_index[i];
+			parser->local.collection_index[j];
 	}
 
 	field->maxusage = usages;
@@ -1317,7 +1324,6 @@
 #define USB_VENDOR_ID_KBGEAR            0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO  0x1001
 
-
 #define USB_VENDOR_ID_AIPTEK		0x08ca
 #define USB_DEVICE_ID_AIPTEK_6000	0x0020
 
@@ -1356,17 +1362,40 @@
 #define USB_VENDOR_ID_A4TECH		0x09DA
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 
+#define USB_VENDOR_ID_CYPRESS		0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
+
 #define USB_VENDOR_ID_BERKSHIRE		0x0c98
 #define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
 
 #define USB_VENDOR_ID_ALPS		0x0433
 #define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
 
+#define USB_VENDOR_ID_SAITEK		0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
 	unsigned quirks;
 } hid_blacklist[] = {
+
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
+
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
@@ -1388,32 +1417,24 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK },
-	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+
+	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_BACK },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA },
+
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+
 	{ 0, 0 }
 };
 
--- diff/drivers/usb/input/hid-input.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid-input.c	2004-02-18 09:04:01.000000000 +0000
@@ -377,7 +377,8 @@
 
 	set_bit(usage->type, input->evbit);
 	if ((usage->type == EV_REL)
-			&& (device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
+			&& (device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK
+				| HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA))
 			&& (usage->code == REL_WHEEL)) {
 		set_bit(REL_HWHEEL, bit);
 	}
@@ -431,21 +432,22 @@
 
 	input_regs(input, regs);
 
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
-			&& (usage->code == BTN_BACK)) {
+	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) && (usage->code == BTN_EXTRA))
+		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) && (usage->code == BTN_BACK))) {
 		if (value)
 			hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		else
 			hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		return;
 	}
+
 	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
 			&& (usage->code == REL_WHEEL)) {
 		input_event(input, usage->type, REL_HWHEEL, value);
 		return;
 	}
 
-	if (usage->hat_min != usage->hat_max) {
+	if (usage->hat_min != usage->hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */
 		value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
 		if (value < 0 || value > 8) value = 0;
 		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
@@ -484,7 +486,7 @@
 		return;
 	}
 
-	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
+	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
 		return;
 
 	input_event(input, usage->type, usage->code, value);
--- diff/drivers/usb/input/hid.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hid.h	2004-02-18 09:04:01.000000000 +0000
@@ -201,15 +201,16 @@
  * HID device quirks.
  */
 
-#define HID_QUIRK_INVERT		0x001
-#define HID_QUIRK_NOTOUCH		0x002
-#define HID_QUIRK_IGNORE		0x004
-#define HID_QUIRK_NOGET			0x008
-#define HID_QUIRK_HIDDEV		0x010
-#define HID_QUIRK_BADPAD		0x020
-#define HID_QUIRK_MULTI_INPUT		0x040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK	0x080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON	0x100
+#define HID_QUIRK_INVERT			0x001
+#define HID_QUIRK_NOTOUCH			0x002
+#define HID_QUIRK_IGNORE			0x004
+#define HID_QUIRK_NOGET				0x008
+#define HID_QUIRK_HIDDEV			0x010
+#define HID_QUIRK_BADPAD			0x020
+#define HID_QUIRK_MULTI_INPUT			0x040
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_BACK	0x080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA	0x100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x200
 
 /*
  * This is the global environment of the parser. This information is
--- diff/drivers/usb/input/hiddev.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/hiddev.c	2004-02-18 09:04:01.000000000 +0000
@@ -403,7 +403,8 @@
 	struct hiddev_collection_info cinfo;
 	struct hiddev_report_info rinfo;
 	struct hiddev_field_info finfo;
-	struct hiddev_usage_ref uref;
+	struct hiddev_usage_ref_multi uref_multi;
+	struct hiddev_usage_ref *uref = &uref_multi.uref;
 	struct hiddev_devinfo dinfo;
 	struct hid_report *report;
 	struct hid_field *field;
@@ -575,68 +576,98 @@
 		return 0;
 
 	case HIDIOCGUCODE:
-		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+		if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
 			return -EFAULT;
 
-		rinfo.report_type = uref.report_type;
-		rinfo.report_id = uref.report_id;
+		rinfo.report_type = uref->report_type;
+		rinfo.report_id = uref->report_id;
 		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 			return -EINVAL;
 
-		if (uref.field_index >= report->maxfield)
+		if (uref->field_index >= report->maxfield)
 			return -EINVAL;
 
-		field = report->field[uref.field_index];
-		if (uref.usage_index >= field->maxusage)
+		field = report->field[uref->field_index];
+		if (uref->usage_index >= field->maxusage)
 			return -EINVAL;
 
-		uref.usage_code = field->usage[uref.usage_index].hid;
+		uref->usage_code = field->usage[uref->usage_index].hid;
 
-		if (copy_to_user((void *) arg, &uref, sizeof(uref)))
+		if (copy_to_user((void *) arg, uref, sizeof(*uref)))
 			return -EFAULT;
 
 		return 0;
 
 	case HIDIOCGUSAGE:
 	case HIDIOCSUSAGE:
+	case HIDIOCGUSAGES:
+	case HIDIOCSUSAGES:
 	case HIDIOCGCOLLECTIONINDEX:
-		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
-			return -EFAULT;
+		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+			if (copy_from_user(&uref_multi, (void *) arg, 
+					   sizeof(uref_multi)))
+				return -EFAULT;
+		} else {
+			if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
+				return -EFAULT;
+		}
 
-		if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT)
-				return -EINVAL;
+		if (cmd != HIDIOCGUSAGE && 
+		    cmd != HIDIOCGUSAGES &&
+		    uref->report_type == HID_REPORT_TYPE_INPUT)
+			return -EINVAL;
 
-		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
-			field = hiddev_lookup_usage(hid, &uref);
+		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+			field = hiddev_lookup_usage(hid, uref);
 			if (field == NULL)
 				return -EINVAL;
 		} else {
-			rinfo.report_type = uref.report_type;
-			rinfo.report_id = uref.report_id;
+			rinfo.report_type = uref->report_type;
+			rinfo.report_id = uref->report_id;
 			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
 				return -EINVAL;
 
-			if (uref.field_index >= report->maxfield)
+			if (uref->field_index >= report->maxfield)
 				return -EINVAL;
 
-			field = report->field[uref.field_index];
-			if (uref.usage_index >= field->maxusage)
+			field = report->field[uref->field_index];
+			if (uref->usage_index >= field->maxusage)
 				return -EINVAL;
+
+			if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+				if (uref_multi.num_values >= HID_MAX_USAGES || 
+				    uref->usage_index >= field->maxusage || 
+				   (uref->usage_index + uref_multi.num_values) >= field->maxusage)
+					return -EINVAL;
+			}
 		}
 
 		switch (cmd) {
 			case HIDIOCGUSAGE:
-				uref.value = field->value[uref.usage_index];
-				if (copy_to_user((void *) arg, &uref, sizeof(uref)))
+				uref->value = field->value[uref->usage_index];
+				if (copy_to_user((void *) arg, uref, sizeof(*uref)))
 					return -EFAULT;
 				return 0;
 
 			case HIDIOCSUSAGE:
-				field->value[uref.usage_index] = uref.value;
+				field->value[uref->usage_index] = uref->value;
 				return 0;
 
 			case HIDIOCGCOLLECTIONINDEX:
-				return field->usage[uref.usage_index].collection_index;
+				return field->usage[uref->usage_index].collection_index;
+			case HIDIOCGUSAGES:
+				for (i = 0; i < uref_multi.num_values; i++)
+					uref_multi.values[i] = 
+					    field->value[uref->usage_index + i];
+				if (copy_to_user((void *) arg, &uref_multi, 
+						 sizeof(uref_multi)))
+					return -EFAULT;
+				return 0;
+			case HIDIOCSUSAGES:
+				for (i = 0; i < uref_multi.num_values; i++)
+					field->value[uref->usage_index + i] = 
+				  	    uref_multi.values[i];
+				return 0;
 		}
 
 		return 0;
--- diff/drivers/usb/input/wacom.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/input/wacom.c	2004-02-18 09:04:01.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  *  USB Wacom Graphire and Wacom Intuos tablet support
  *
- *  Copyright (c) 2000-2002 Vojtech Pavlik	<vojtech@ucw.cz>
+ *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@ucw.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
  *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
  *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
@@ -9,6 +9,7 @@
  *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
  *  Copyright (c) 2002 Ping Cheng		<pingc@wacom.com>
+ *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -48,6 +49,7 @@
  *	v1.30 (vp) - Merge 2.4 and 2.5 drivers
  *		   - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
  *		   - Cleanups here and there
+ *    v1.30.1 (pi) - Added Graphire3 support
  */
 
 /*
--- diff/drivers/usb/media/stv680.c	2003-09-17 12:28:10.000000000 +0100
+++ source/drivers/usb/media/stv680.c	2004-02-18 09:04:01.000000000 +0000
@@ -490,10 +490,9 @@
 	stv680->hue = 32767;
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
-	swapRGB = 0;
 	if ((swapRGB_on == 0) && (swapRGB == 0))
 		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
-	else if ((swapRGB_on == 1) && (swapRGB == 1))
+	else if ((swapRGB_on == 0) && (swapRGB == 1))
 		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
 	else if (swapRGB_on == 1)
 		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
@@ -657,7 +656,7 @@
 	/* Resubmit urb for new data */
 	urb->status = 0;
 	urb->dev = stv680->udev;
-	if (usb_submit_urb (urb, GFP_KERNEL))
+	if (usb_submit_urb (urb, GFP_ATOMIC))
 		PDEBUG (0, "STV(e): urb burned down in video irq");
 	return;
 }				/*  _video_irq  */
@@ -1252,13 +1251,10 @@
 			return -EINVAL;
 		}
 	case VIDIOCSFBUF:
-		return -EINVAL;
 	case VIDIOCGTUNER:
 	case VIDIOCSTUNER:
-		return -EINVAL;
 	case VIDIOCGFREQ:
 	case VIDIOCSFREQ:
-		return -EINVAL;
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
 		return -EINVAL;
@@ -1434,7 +1430,7 @@
 	if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		PDEBUG (0, "STV(e): video_register_device failed");
 		retval = -EIO;
-		goto error;
+		goto error_vdev;
 	}
 	PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
 
@@ -1442,6 +1438,8 @@
 	stv680_create_sysfs_files(stv680->vdev);
 	return 0;
 
+error_vdev:
+	video_device_release(stv680->vdev);
 error:
 	kfree(stv680);
 	return retval;
@@ -1466,9 +1464,7 @@
 			kfree (stv680->sbuf[i].data);
 		}
 	for (i = 0; i < STV680_NUMSCRATCH; i++)
-		if (stv680->scratch[i].data) {
-			kfree (stv680->scratch[i].data);
-		}
+		kfree (stv680->scratch[i].data);
 	PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
 
 	/* Free the memory */
--- diff/drivers/usb/misc/speedtch.c	2003-10-09 09:47:34.000000000 +0100
+++ source/drivers/usb/misc/speedtch.c	2004-02-18 09:04:01.000000000 +0000
@@ -1161,7 +1161,7 @@
 	buf += i;
 	length -= i;
 
-	i = snprintf (buf, length, " (");
+	i = scnprintf (buf, length, " (");
 	buf += i;
 	length -= i;
 
--- diff/drivers/usb/net/catc.c	2003-08-26 10:00:54.000000000 +0100
+++ source/drivers/usb/net/catc.c	2004-02-18 09:04:01.000000000 +0000
@@ -838,7 +838,7 @@
 			usb_free_urb(catc->rx_urb);
 		if (catc->irq_urb)
 			usb_free_urb(catc->irq_urb);
-		kfree(netdev);
+		free_netdev(netdev);
 		kfree(catc);
 		return -ENOMEM;
 	}
@@ -943,7 +943,7 @@
 		usb_free_urb(catc->tx_urb);
 		usb_free_urb(catc->rx_urb);
 		usb_free_urb(catc->irq_urb);
-		kfree(netdev);
+		free_netdev(netdev);
 		kfree(catc);
 		return -EIO;
 	}
--- diff/drivers/usb/net/kaweth.c	2003-11-25 15:24:58.000000000 +0000
+++ source/drivers/usb/net/kaweth.c	2004-02-18 09:04:01.000000000 +0000
@@ -1150,7 +1150,7 @@
 err_only_tx:
 	usb_free_urb(kaweth->tx_urb);
 err_no_urb:
-	kfree(netdev);
+	free_netdev(netdev);
 err_no_netdev:
 	kfree(kaweth);
 	return -EIO;
--- diff/drivers/usb/net/pegasus.c	2003-08-26 10:00:54.000000000 +0100
+++ source/drivers/usb/net/pegasus.c	2004-02-18 09:04:01.000000000 +0000
@@ -1283,7 +1283,7 @@
 	usb_set_intfdata(intf, NULL);
 	free_skb_pool(pegasus);
 out3:
-	kfree(net);
+	free_netdev(net);
 out2:
 	free_all_urbs(pegasus);
 out1:
--- diff/drivers/usb/net/rtl8150.c	2003-08-26 10:00:54.000000000 +0100
+++ source/drivers/usb/net/rtl8150.c	2004-02-18 09:04:01.000000000 +0000
@@ -852,7 +852,7 @@
 	free_all_urbs(dev);
 out:
 	kfree(dev->intr_buff);
-	kfree(netdev);
+	free_netdev(netdev);
 	kfree(dev);
 	return -EIO;
 }
--- diff/drivers/usb/net/usbnet.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/net/usbnet.c	2004-02-18 09:04:01.000000000 +0000
@@ -2981,7 +2981,7 @@
 	if (dev->driver_info->unbind)
 		dev->driver_info->unbind (dev, intf);
 
-	kfree(dev->net);
+	free_netdev(dev->net);
 	kfree (dev);
 	usb_put_dev (xdev);
 }
@@ -3111,7 +3111,7 @@
 	if (info->unbind)
 		info->unbind (dev, udev);
 out2:
-	kfree(net);
+	free_netdev(net);
 out1:
 	kfree(dev);
 out:
--- diff/drivers/usb/serial/ftdi_sio.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.c	2004-02-18 09:04:01.000000000 +0000
@@ -17,6 +17,11 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (09/Feb/2004) Ian Abbott
+ *      Changed full name of USB-UIRT device to avoid "/" character.
+ *      Added FTDI's alternate PID (0x6006) for FT232/245 devices.
+ *      Added PID for "ELV USB Module UO100" from Stefan Frings.
+ * 
  * (21/Oct/2003) Ian Abbott
  *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
  *      devices.  Removed Matrix Orbital and Perle Systems devices from the
@@ -282,6 +287,7 @@
 
 static struct usb_device_id id_table_8U232AM [] = {
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
@@ -346,12 +352,14 @@
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
 	{ }						/* Terminating entry */
 };
 
 
 static struct usb_device_id id_table_FT232BM [] = {
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
@@ -425,6 +433,7 @@
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -444,6 +453,7 @@
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
@@ -518,6 +528,7 @@
 	{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
 	{ }						/* Terminating entry */
 };
 
@@ -669,7 +680,7 @@
 
 static struct usb_serial_device_type ftdi_USB_UIRT_device = {
 	.owner =		THIS_MODULE,
-	.name =			"USB-UIRT Infrared Receiver/Transmitter",
+	.name =			"USB-UIRT Infrared Tranceiver",
 	.id_table =		id_table_USB_UIRT,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
--- diff/drivers/usb/serial/ftdi_sio.h	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/serial/ftdi_sio.h	2004-02-18 09:04:01.000000000 +0000
@@ -25,6 +25,7 @@
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
 #define FTDI_RELAIS_PID	0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
@@ -132,6 +133,9 @@
 /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
 #define FTDI_USB_UIRT_PID	0xF850	/* Product Id */
 
+/* ELV USB Module UO100 (PID sent by Stefan Frings) */
+#define FTDI_ELV_UO100_PID	0xFB58	/* Product Id */
+
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
  */
--- diff/drivers/usb/storage/sddr09.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/storage/sddr09.c	2004-02-18 09:04:01.000000000 +0000
@@ -27,6 +27,20 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/*
+ * Known vendor commands: 12 bytes, first byte is opcode
+ *
+ * E7: read scatter gather
+ * E8: read
+ * E9: write
+ * EA: erase
+ * EB: reset
+ * EC: read status
+ * ED: read ID
+ * EE: write CIS (?)
+ * EF: compute checksum (?)
+ */
+
 #include "transport.h"
 #include "protocol.h"
 #include "usb.h"
@@ -461,6 +475,7 @@
  * 
  * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
  * The byte address being erased is 2*Eaddress.
+ * The CIS cannot be erased.
  */
 static int
 sddr09_erase(struct us_data *us, unsigned long Eaddress) {
@@ -487,6 +502,20 @@
 }
 
 /*
+ * Write CIS Command: 12 bytes.
+ * byte 0: opcode: EE
+ * bytes 2-5: write address in shorts
+ * bytes 10-11: sector count
+ *
+ * This writes at the indicated address. Don't know how it differs
+ * from E9. Maybe it does not erase? However, it will also write to
+ * the CIS.
+ *
+ * When two such commands on the same page follow each other directly,
+ * the second one is not done.
+ */
+
+/*
  * Write Command: 12 bytes.
  * byte 0: opcode: E9
  * bytes 2-5: write address (big-endian, counting shorts, sector aligned).
@@ -1478,7 +1507,7 @@
 				  "mode page 0x%x\n", modepage);
 
 			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
-			((u16*)ptr)[0] = sizeof(mode_page_01) - 2;
+			((u16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
 			ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
 			usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
 			return USB_STOR_TRANSPORT_GOOD;
--- diff/drivers/usb/storage/transport.c	2004-02-09 10:36:11.000000000 +0000
+++ source/drivers/usb/storage/transport.c	2004-02-18 09:04:01.000000000 +0000
@@ -552,6 +552,8 @@
 		return;
 	}
 
+	srb->result = SAM_STAT_GOOD;
+
 	/* Determine if we need to auto-sense
 	 *
 	 * I normally don't use a flag like this, but it's almost impossible
@@ -561,23 +563,14 @@
 
 	/*
 	 * If we're running the CB transport, which is incapable
-	 * of determining status on it's own, we need to auto-sense almost
-	 * every time.
+	 * of determining status on its own, we need to auto-sense
+	 * unless the operation involved a data-in transfer.  Devices
+	 * can signal data-in errors by stalling the bulk-in pipe.
 	 */
-	if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) {
+	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
+			srb->sc_data_direction != SCSI_DATA_READ) {
 		US_DEBUGP("-- CB transport device requiring auto-sense\n");
 		need_auto_sense = 1;
-
-		/* There are some exceptions to this.  Notably, if this is
-		 * a UFI device and the command is REQUEST_SENSE or INQUIRY,
-		 * then it is impossible to truly determine status.
-		 */
-		if (us->subclass == US_SC_UFI &&
-		    ((srb->cmnd[0] == REQUEST_SENSE) ||
-		     (srb->cmnd[0] == INQUIRY))) {
-			US_DEBUGP("** no auto-sense for a special command\n");
-			need_auto_sense = 0;
-		}
 	}
 
 	/*
@@ -591,8 +584,8 @@
 	}
 
 	/*
-	 * Also, if we have a short transfer on a command that can't have
-	 * a short transfer, we're going to do this.
+	 * A short transfer on a command where we don't expect it
+	 * is unusual, but it doesn't mean we need to auto-sense.
 	 */
 	if ((srb->resid > 0) &&
 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
@@ -601,7 +594,6 @@
 	      (srb->cmnd[0] == LOG_SENSE) ||
 	      (srb->cmnd[0] == MODE_SENSE_10))) {
 		US_DEBUGP("-- unexpectedly short transfer\n");
-		need_auto_sense = 1;
 	}
 
 	/* Now, if we need to do the auto-sense, let's do it */
@@ -614,6 +606,7 @@
 		unsigned char old_cmd_len;
 		unsigned char old_cmnd[MAX_COMMAND_SIZE];
 		unsigned long old_serial_number;
+		int old_resid;
 
 		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
 
@@ -654,9 +647,12 @@
 		srb->serial_number ^= 0x80000000;
 
 		/* issue the auto-sense command */
+		old_resid = srb->resid;
+		srb->resid = 0;
 		temp_result = us->transport(us->srb, us);
 
 		/* let's clean up right away */
+		srb->resid = old_resid;
 		srb->request_buffer = old_request_buffer;
 		srb->request_bufflen = old_request_bufflen;
 		srb->use_sg = old_sg;
@@ -698,26 +694,15 @@
 		/* set the result so the higher layers expect this data */
 		srb->result = SAM_STAT_CHECK_CONDITION;
 
-		/* If things are really okay, then let's show that */
-		if ((srb->sense_buffer[2] & 0xf) == 0x0)
+		/* If things are really okay, then let's show that.  Zero
+		 * out the sense buffer so the higher layers won't realize
+		 * we did an unsolicited auto-sense. */
+		if (result == USB_STOR_TRANSPORT_GOOD &&
+				(srb->sense_buffer[2] & 0xf) == 0x0) {
 			srb->result = SAM_STAT_GOOD;
-	} else /* if (need_auto_sense) */
-		srb->result = SAM_STAT_GOOD;
-
-	/* Regardless of auto-sense, if we _know_ we have an error
-	 * condition, show that in the result code
-	 */
-	if (result == USB_STOR_TRANSPORT_FAILED)
-		srb->result = SAM_STAT_CHECK_CONDITION;
-
-	/* If we think we're good, then make sure the sense data shows it.
-	 * This is necessary because the auto-sense for some devices always
-	 * sets byte 0 == 0x70, even if there is no error
-	 */
-	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && 
-	    (result == USB_STOR_TRANSPORT_GOOD) &&
-	    ((srb->sense_buffer[2] & 0xf) == 0x0))
-		srb->sense_buffer[0] = 0x0;
+			srb->sense_buffer[0] = 0x0;
+		}
+	}
 	return;
 
 	/* abort processing: the bulk-only transport requires a reset
@@ -792,6 +777,10 @@
 					srb->request_buffer, transfer_length,
 					srb->use_sg, &srb->resid);
 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
+
+		/* if we stalled the data transfer it means command failed */
+		if (result == USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_FAILED;
 		if (result > USB_STOR_XFER_STALLED)
 			return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -883,6 +872,10 @@
 					srb->request_buffer, transfer_length,
 					srb->use_sg, &srb->resid);
 		US_DEBUGP("CB data stage result is 0x%x\n", result);
+
+		/* if we stalled the data transfer it means command failed */
+		if (result == USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_FAILED;
 		if (result > USB_STOR_XFER_STALLED)
 			return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -929,6 +922,7 @@
 	unsigned int residue;
 	int result;
 	int fake_sense = 0;
+	unsigned int cswlen;
 
 	/* set up the command wrapper */
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -985,7 +979,17 @@
 	/* get CSW for device status */
 	US_DEBUGP("Attempting to get CSW...\n");
 	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
-				bcs, US_BULK_CS_WRAP_LEN, NULL);
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+
+	/* Some broken devices add unnecessary zero-length packets to the
+	 * end of their data transfers.  Such packets show up as 0-length
+	 * CSWs.  If we encounter such a thing, try to read the CSW again.
+	 */
+	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+		US_DEBUGP("Received 0-length CSW; retrying...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+	}
 
 	/* did the attempt to read the CSW fail? */
 	if (result == USB_STOR_XFER_STALLED) {
--- diff/drivers/usb/storage/unusual_devs.h	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/usb/storage/unusual_devs.h	2004-02-18 09:04:01.000000000 +0000
@@ -108,6 +108,15 @@
 		"Finecam S5",
 		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
 
+/* Patch for Kyocera Finecam L3
+ * Submitted by Michael Krauth <michael.krauth@web.de>
+ */
+UNUSUAL_DEV(  0x0482, 0x0105, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam L3",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY),
+
 /* Reported by Paul Stewart <stewart@wetlogic.net>
  * This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
@@ -414,6 +423,28 @@
 		US_FL_SINGLE_LUN ),
 #endif
 
+/* Following three Minolta cameras reported by Martin Pool
+ * <mbp@sourcefrog.net>.  Originally discovered by Kedar Petankar,
+ * Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
+ */
+UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
+		"Minolta",
+		"DiMAGE 7",
+		US_SC_SCSI, US_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
+		"Minolta",
+		"DiMAGE 7i",
+		US_SC_SCSI, US_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
+		"Minolta",
+		"DiMAGE 7Hi",
+		US_SC_SCSI, US_PR_DEVICE, NULL,
+		0 ),
+
 /* Submitted by Benny Sjostrand <benny@hostmobility.com> */
 UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
 		"Minolta",
@@ -426,28 +457,6 @@
                 "DIMAGE E223",
                 US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
 
-/* Following three Minolta cameras reported by Martin Pool
- * <mbp@sourcefrog.net>.  Originally discovered by Kedar Petankar,
- * Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
- */
-UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
-             "Minolta",
-             "DiMAGE 7",
-             US_SC_SCSI, US_PR_DEVICE, NULL,
-             0 ),
-
-UNUSUAL_DEV( 0x0686, 0x400b, 0x0001, 0x0001,
-             "Minolta",
-             "DiMAGE 7i",
-             US_SC_SCSI, US_PR_DEVICE, NULL,
-             0 ),
-
-UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
-             "Minolta",
-             "DiMAGE 7Hi",
-             US_SC_SCSI, US_PR_DEVICE, NULL,
-             0 ),
-
 UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
 		"Hagiwara",
 		"FlashGate SmartMedia",
@@ -607,7 +616,7 @@
 UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
 		"Casio",
 		"QV DigitalCamera",
-		US_SC_8070, US_PR_CB, NULL,
+		US_SC_DEVICE, US_PR_CB, NULL,
 		US_FL_FIX_INQUIRY ),
 
 /* Later Casio cameras apparently tell the truth */
@@ -633,15 +642,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ),
 
-/*Medion 6047 Digital Camera
-Davide Andrian <_nessuno_@katamail.com>
-*/
-UNUSUAL_DEV( 0x08ca, 0x2011, 0x0001, 0x0001,
-		"3MegaCam",
-		"3MegaCam",
-		US_SC_DEVICE, US_PR_BULK, NULL,
-		US_FL_MODE_XLATE ),
-
 /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
 UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
 		"Trumpion",
--- diff/drivers/video/console/fbcon.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/video/console/fbcon.c	2004-02-18 09:04:01.000000000 +0000
@@ -324,7 +324,7 @@
 	unsigned int buf_align = info->pixmap.buf_align - 1;
 	unsigned int scan_align = info->pixmap.scan_align - 1;
 	unsigned int idx = vc->vc_font.width >> 3;
-	u8 mask, *src, *dst, *dst0;
+	u8 *src, *dst, *dst0;
 
 	while (count) {
 		if (count > maxcnt)
@@ -337,15 +337,15 @@
 		pitch &= ~scan_align;
 		size = pitch * vc->vc_font.height + buf_align;
 		size &= ~buf_align;
-		dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+		dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
 		image->data = dst0;
 		while (k--) {
 			src = vc->vc_font.data + (scr_readw(s++) & charmask)*
 			cellsize;
 			dst = dst0;
-			mask = (u8) (0xfff << shift_high);
-			move_buf_unaligned(info, dst, src, pitch, image->height,
-					mask, shift_high, shift_low, mod, idx);
+			fb_move_buf_unaligned(info, &info->pixmap, dst, pitch, src,
+						idx, image->height, shift_high,
+						shift_low, mod);
 			shift_low += mod;
 			dst0 += (shift_low >= 8) ? width : width - 1;
 			shift_low &= 7;
@@ -381,12 +381,13 @@
 		size = pitch * vc->vc_font.height + buf_align;
 		size &= ~buf_align;
 		image->width = vc->vc_font.width * cnt;
-		dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
+		dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
 		image->data = dst0;
 		while (k--) {
 			src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize;
 			dst = dst0;
-			move_buf_aligned(info, dst, src, pitch, width, image->height);
+			fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src,
+						width, image->height);
 			dst0 += width;
 		}
 		info->fbops->fb_imageblit(info, image);
@@ -455,11 +456,11 @@
 	size = pitch * vc->vc_font.height;
 	size += buf_align;
 	size &= ~buf_align;
-	dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+	dst = fb_get_buffer_offset(info, &info->pixmap, size);
 	image.data = dst;
 	src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
 
-	move_buf_aligned(info, dst, src, pitch, width, image.height);
+	fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height);
 
 	info->fbops->fb_imageblit(info, &image);
 }
--- diff/drivers/video/fbmem.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/video/fbmem.c	2004-02-18 09:04:01.000000000 +0000
@@ -395,7 +395,7 @@
 };
 
 #define NUM_FB_DRIVERS	(sizeof(fb_drivers)/sizeof(*fb_drivers))
-#define FBPIXMAPSIZE	8192
+#define FBPIXMAPSIZE	16384
 
 extern const char *global_mode_option;
 
@@ -412,52 +412,54 @@
 /*
  * Drawing helpers.
  */
-u8 sys_inbuf(u8 *src)
+u8 sys_inbuf(struct fb_info *info, u8 *src)
 {	
 	return *src;
 }
 
-void sys_outbuf(u8 *src, u8 *dst, unsigned int size)
+void sys_outbuf(struct fb_info *info, u8 *dst, u8 *src, unsigned int size)
 {
 	memcpy(dst, src, size);
 }	
 
-void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, 
-			u32 s_pitch, u32 height)
+void fb_move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
+			u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+			u32 height)
 {
 	int i;
 
 	for (i = height; i--; ) {
-		info->pixmap.outbuf(src, dst, s_pitch);
+		buf->outbuf(info, dst, src, s_pitch);
 		src += s_pitch;
 		dst += d_pitch;
 	}
 }
 
-void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, 
-			u32 height, u32 mask, u32 shift_high, u32 shift_low,
-			u32 mod, u32 idx)
+void fb_move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
+			u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+			u32 height, u32 shift_high, u32 shift_low,
+			u32 mod)
 {
+	u8 mask = (u8) (0xfff << shift_high), tmp;
 	int i, j;
-	u8 tmp;
 
 	for (i = height; i--; ) {
 		for (j = 0; j < idx; j++) {
-			tmp = info->pixmap.inbuf(dst+j);
+			tmp = buf->inbuf(info, dst+j);
 			tmp &= mask;
 			tmp |= *src >> shift_low;
-			info->pixmap.outbuf(&tmp, dst+j, 1);
+			buf->outbuf(info, dst+j, &tmp, 1);
 			tmp = *src << shift_high;
-			info->pixmap.outbuf(&tmp, dst+j+1, 1);
+			buf->outbuf(info, dst+j+1, &tmp, 1);
 			src++;
 		}
-		tmp = info->pixmap.inbuf(dst+idx);
+		tmp = buf->inbuf(info, dst+idx);
 		tmp &= mask;
 		tmp |= *src >> shift_low;
-		info->pixmap.outbuf(&tmp, dst+idx, 1);
+		buf->outbuf(info, dst+idx, &tmp, 1);
 		if (shift_high < mod) {
 			tmp = *src << shift_high;
-			info->pixmap.outbuf(&tmp, dst+idx+1, 1);
+			buf->outbuf(info, dst+idx+1, &tmp, 1);
 		}	
 		src++;
 		dst += d_pitch;
@@ -468,10 +470,10 @@
  * we need to lock this section since fb_cursor
  * may use fb_imageblit()
  */
-u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
+char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
 {
-	struct fb_pixmap *buf = &info->pixmap;
 	u32 align = buf->buf_align - 1, offset;
+	char *addr = buf->addr;
 
 	/* If IO mapped, we need to sync before access, no sharing of
 	 * the pixmap is done
@@ -479,7 +481,7 @@
 	if (buf->flags & FB_PIXMAP_IO) {
 		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
 			info->fbops->fb_sync(info);
-		return 0;
+		return addr;
 	}
 
 	/* See if we fit in the remaining pixmap space */
@@ -495,8 +497,9 @@
 		offset = 0;
 	}
 	buf->offset = offset + size;
+	addr += offset;
 
-	return offset;
+	return addr;
 }
 
 #ifdef CONFIG_LOGO
@@ -869,6 +872,15 @@
 }
 #endif /* CONFIG_KMOD */
 
+void
+fb_load_cursor_image(struct fb_info *info)
+{
+	unsigned int width = (info->cursor.image.width + 7) >> 3;
+	u8 *data = (u8 *) info->cursor.image.data;
+
+	info->sprite.outbuf(info, info->sprite.addr, data, width);
+}
+
 int
 fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
 {
@@ -1276,6 +1288,21 @@
 	if (fb_info->pixmap.inbuf == NULL)
 		fb_info->pixmap.inbuf = sys_inbuf;
 
+	if (fb_info->sprite.addr == NULL) {
+		fb_info->sprite.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
+		if (fb_info->sprite.addr) {
+			fb_info->sprite.size = FBPIXMAPSIZE;
+			fb_info->sprite.buf_align = 1;
+			fb_info->sprite.scan_align = 1;
+			fb_info->sprite.flags = FB_PIXMAP_DEFAULT;
+		}
+	}
+	fb_info->sprite.offset = 0;
+	if (fb_info->sprite.outbuf == NULL)
+		fb_info->sprite.outbuf = sys_outbuf;
+	if (fb_info->sprite.inbuf == NULL)
+		fb_info->sprite.inbuf = sys_inbuf;
+
 	registered_fb[i] = fb_info;
 
 	devfs_mk_cdev(MKDEV(FB_MAJOR, i),
@@ -1304,8 +1331,10 @@
 		return -EINVAL;
 	devfs_remove("fb/%d", i);
 
-	if (fb_info->pixmap.addr)
+	if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
+	if (fb_info->sprite.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+		kfree(fb_info->sprite.addr);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
 	return 0;
@@ -1460,8 +1489,9 @@
 EXPORT_SYMBOL(fb_blank);
 EXPORT_SYMBOL(fb_pan_display);
 EXPORT_SYMBOL(fb_get_buffer_offset);
-EXPORT_SYMBOL(move_buf_unaligned);
-EXPORT_SYMBOL(move_buf_aligned);
+EXPORT_SYMBOL(fb_move_buf_unaligned);
+EXPORT_SYMBOL(fb_move_buf_aligned);
+EXPORT_SYMBOL(fb_load_cursor_image);
 EXPORT_SYMBOL(fb_set_suspend);
 EXPORT_SYMBOL(fb_register_client);
 EXPORT_SYMBOL(fb_unregister_client);
--- diff/drivers/video/softcursor.c	2004-02-18 08:54:12.000000000 +0000
+++ source/drivers/video/softcursor.c	2004-02-18 09:04:01.000000000 +0000
@@ -19,8 +19,8 @@
 
 int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-	unsigned int scan_align = info->pixmap.scan_align - 1;
-	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int scan_align = info->sprite.scan_align - 1;
+	unsigned int buf_align = info->sprite.buf_align - 1;
 	unsigned int i, size, dsize, s_pitch, d_pitch;
 	u8 *dst, src[64];
 
@@ -56,7 +56,7 @@
 	d_pitch = (s_pitch + scan_align) & ~scan_align;
 	size = d_pitch * info->cursor.image.height + buf_align;
 	size &= ~buf_align;
-	dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
+	dst = fb_get_buffer_offset(info, &info->sprite, size);
 
 	if (info->cursor.enable) {
 		switch (info->cursor.rop) {
@@ -73,7 +73,7 @@
 	} else 
 		memcpy(src, cursor->image.data, dsize);
 	
-	move_buf_aligned(info, dst, src, d_pitch, s_pitch, info->cursor.image.height);
+	fb_move_buf_aligned(info, &info->sprite, dst, d_pitch, src, s_pitch, info->cursor.image.height);
 	info->cursor.image.data = dst;
 	
 	info->fbops->fb_imageblit(info, &info->cursor.image);
--- diff/fs/Kconfig	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/Kconfig	2004-02-18 09:04:01.000000000 +0000
@@ -780,6 +780,30 @@
 	bool
 	default y if !ARM
 
+config SYSFS
+	bool "sysfs file system support" if EMBEDDED
+	default y
+	help
+	The sysfs filesystem is a virtual filesystem that the kernel uses to export
+	internal kernel objects, their attributes, and their relationships to one
+	another.
+
+	Users can use sysfs to ascertain useful information about the running kernel,
+	such as the devices the kernel has discovered on each bus and which driver
+	each is bound to. sysfs can also be used to tune devices and other kernel
+	subsystems.
+
+	Some system agents rely on the information in sysfs to operate. /sbin/hotplug
+	uses device and object attributes in sysfs to assist in delegating policy
+	decisions, like persistantly naming devices.
+
+	sysfs is currently needed by the block subsystem to mount the root partition.
+	Therefore, you MUST say Y if you're booting from a hard drive. If you use any
+	type of hotpluggable device, you'll also need sysfs for /sbin/hotplug support.
+
+	However, designers of embedded systems may want to say N here to conserve
+	space.
+
 config DEVFS_FS
 	bool "/dev file system support (OBSOLETE)"
 	depends on EXPERIMENTAL
@@ -797,8 +821,7 @@
 	  the file README there.
 
 	  Note that devfs no longer manages /dev/pts!  If you are using UNIX98
-	  ptys, you will also need to enable (and mount) the /dev/pts
-	  filesystem (CONFIG_DEVPTS_FS).
+	  ptys, you will also need to mount the /dev/pts filesystem (devpts).
 
 	  Note that devfs has been obsoleted by udev,
 	  <http://www.kernel.org/pub/linux/utils/kernel/hotplug/>.
@@ -831,32 +854,9 @@
 
 	  If unsure, say N.
 
-config DEVPTS_FS
-# It compiles as a module for testing only.  It should not be used
-# as a module in general.  If we make this "tristate", a bunch of people
-# who don't know what they are doing turn it on and complain when it
-# breaks.
-	bool "/dev/pts file system for Unix98 PTYs"
-	depends on UNIX98_PTYS
-	---help---
-	  You should say Y here if you said Y to "Unix98 PTY support" above.
-	  You'll then get a virtual file system which can be mounted on
-	  /dev/pts with "mount -t devpts". This, together with the pseudo
-	  terminal master multiplexer /dev/ptmx, is used for pseudo terminal
-	  support as described in The Open Group's Unix98 standard: in order
-	  to acquire a pseudo terminal, a process opens /dev/ptmx; the number
-	  of the pseudo terminal is then made available to the process and the
-	  pseudo terminal slave can be accessed as /dev/pts/<number>. What was
-	  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-	  The GNU C library glibc 2.1 contains the requisite support for this
-	  mode of operation; you also need client programs that use the Unix98
-	  API. Please read <file:Documentation/Changes> for more information
-	  about the Unix98 pty devices.
-
 config DEVPTS_FS_XATTR
 	bool "/dev/pts Extended Attributes"
-	depends on DEVPTS_FS
+	depends on UNIX98_PTYS
 	help
 	  Extended attributes are name:value pairs associated with inodes by
 	  the kernel or by users (see the attr(5) manual page, or visit
@@ -1592,9 +1592,12 @@
 	  
 	  For most cases you probably want to say N.
 
+#
+# Intermezzo broke when we added the expanded NGROUPS patches
+#
 config INTERMEZZO_FS
 	tristate "InterMezzo file system support (replicating fs) (EXPERIMENTAL)"
-	depends on INET && EXPERIMENTAL
+	depends on INET && EXPERIMENTAL && BROKEN
 	help
 	  InterMezzo is a networked file system with disconnected operation
 	  and kernel level write back caching.  It is most often used for
--- diff/fs/Makefile	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/Makefile	2004-02-18 09:04:01.000000000 +0000
@@ -39,7 +39,7 @@
 
 obj-$(CONFIG_PROC_FS)		+= proc/
 obj-y				+= partitions/
-obj-y				+= sysfs/
+obj-$(CONFIG_SYSFS)		+= sysfs/
 obj-y				+= devpts/
 
 obj-$(CONFIG_PROFILING)		+= dcookies.o
--- diff/fs/adfs/adfs.h	2003-09-17 12:28:11.000000000 +0100
+++ source/fs/adfs/adfs.h	2004-02-18 09:04:01.000000000 +0000
@@ -68,12 +68,8 @@
 
 
 /* Inode stuff */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 int adfs_get_block(struct inode *inode, sector_t block,
 		   struct buffer_head *bh, int create);
-#else
-int adfs_bmap(struct inode *inode, int block);
-#endif
 struct inode *adfs_iget(struct super_block *sb, struct object_info *obj);
 void adfs_read_inode(struct inode *inode);
 void adfs_write_inode(struct inode *inode,int unused);
--- diff/fs/binfmt_aout.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/binfmt_aout.c	2004-02-18 09:04:01.000000000 +0000
@@ -309,7 +309,7 @@
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
 
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
--- diff/fs/binfmt_elf.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/binfmt_elf.c	2004-02-18 09:04:01.000000000 +0000
@@ -36,6 +36,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
@@ -671,7 +672,7 @@
 
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
 	retval = setup_arg_pages(bprm);
 	if (retval < 0) {
--- diff/fs/binfmt_flat.c	2003-08-20 14:16:32.000000000 +0100
+++ source/fs/binfmt_flat.c	2004-02-18 09:04:01.000000000 +0000
@@ -643,7 +643,7 @@
 		current->mm->start_brk = datapos + data_len + bss_len;
 		current->mm->brk = (current->mm->start_brk + 3) & ~3;
 		current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
-		current->mm->rss = 0;
+		zero_rss(current->mm);
 	}
 
 	if (flags & FLAT_FLAG_KTRACE)
--- diff/fs/binfmt_misc.c	2003-11-25 15:24:58.000000000 +0000
+++ source/fs/binfmt_misc.c	2004-02-18 09:04:01.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/pagemap.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
 
@@ -38,6 +39,8 @@
 
 enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
+#define MISC_FMT_OPEN_BINARY (1<<30)
+#define MISC_FMT_CREDENTIALS (1<<29)
 
 typedef struct {
 	struct list_head list;
@@ -101,10 +104,15 @@
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	Node *fmt;
-	struct file * file;
+	struct file * interp_file = NULL;
+	struct file * binary_file = NULL;
 	char iname[BINPRM_BUF_SIZE];
 	char *iname_addr = iname;
 	int retval;
+	int fd_binary = -1;
+	char fd_str[32];
+	char * fdsp = fd_str;
+	int is_open_bin;
 
 	retval = -ENOEXEC;
 	if (!enabled)
@@ -119,33 +127,105 @@
 	if (!fmt)
 		goto _ret;
 
-	allow_write_access(bprm->file);
-	fput(bprm->file);
-	bprm->file = NULL;
+	is_open_bin = (fmt->flags & MISC_FMT_OPEN_BINARY) ? 1 : 0;
+
+ 	if (is_open_bin) {
+		/* if the binary should be opened on behalf of the
+		 * interpreter than keep it open and assign descriptor
+		 * to it */
+ 		fd_binary = get_unused_fd ();
+ 		if (fd_binary < 0) {
+ 			retval = fd_binary;
+ 			goto _ret;
+ 		}
+ 		snprintf (fd_str, sizeof(fd_str) - 1, "%d", fd_binary);
+ 	} else {
+ 		allow_write_access (bprm->file);
+ 		fput (bprm->file);
+ 		bprm->file = NULL;
+ 	}
 
 	/* Build args for interpreter */
 	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
 		remove_arg_zero(bprm);
 	}
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	retval = copy_strings_kernel(1, &iname_addr, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
+
+ 	if (is_open_bin) {
+		/* make argv[1] be the file descriptor of the binary */
+ 		retval = copy_strings_kernel (1, &fdsp, bprm);
+ 	} else {
+		/* make argv[1] be the path to the binary */
+ 		retval = copy_strings_kernel (1, &bprm->interp, bprm);
+ 	}
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
+	retval = copy_strings_kernel (1, &iname_addr, bprm);
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
 	bprm->interp = iname;	/* for binfmt_script */
 
-	file = open_exec(iname);
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		goto _ret;
-	bprm->file = file;
+	interp_file = open_exec (iname);
+	retval = PTR_ERR (interp_file);
+	if (IS_ERR (interp_file))
+		goto _error;
+
+
+	binary_file = bprm->file;
+	if (fmt->flags & MISC_FMT_CREDENTIALS) {
+		/*
+		 * Call prepare_binprm before switching to interpreter's file
+		 * so that all security calculation will be done according to
+		 * binary and not interpreter
+		 */
+		retval = prepare_binprm(bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->file = interp_file;
+		memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+		retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
+	} else {
+		bprm->file = interp_file;
+		retval = prepare_binprm (bprm);
+	}
+
+	if (retval < 0)
+		goto _error;
+
+	if (is_open_bin) {
+		/* if the binary is not readable than enforce mm->dumpable=0
+		   regardless of the interpreter's permissions */
+		if (permission (binary_file->f_dentry->d_inode, MAY_READ, NULL)) {
+			bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+		}
+		/* install the binary's fd. it is done at the latest possible point
+	 	 * because once it is installed it will need to be sys_close()ed
+	 	 * in case of error.
+	 	 */
+ 		fd_install (fd_binary, binary_file);
+	}
+
+	retval = search_binary_handler (bprm, regs);
+
+	if (retval < 0)
+		goto _error_close_file;
 
-	retval = prepare_binprm(bprm);
-	if (retval >= 0)
-		retval = search_binary_handler(bprm, regs);
 _ret:
 	return retval;
+
+_error_close_file:
+	if (fd_binary > 0) {
+		sys_close (fd_binary);
+		fd_binary = -1;
+		bprm->file = NULL;
+	}
+_error:
+	if (fd_binary > 0)
+		put_unused_fd (fd_binary);
+	bprm->interp_flags = 0;
+	goto _ret;
+
 }
 
 /* Command parsers */
@@ -190,6 +270,36 @@
 	return p - from;
 }
 
+static inline char * check_special_flags (char * sfs, Node * e)
+{
+	char * p = sfs;
+	int cont = 1;
+
+	/* special flags */
+	while (cont) {
+		switch (*p) {
+			case 'P':
+				p++;
+				e->flags |= MISC_FMT_PRESERVE_ARGV0;
+				break;
+			case 'O':
+				p++;
+				e->flags |= MISC_FMT_OPEN_BINARY;
+				break;
+			case 'C':
+				p++;
+				/* this flags also implies the
+				   open-binary flag */
+				e->flags |= (MISC_FMT_CREDENTIALS |
+						MISC_FMT_OPEN_BINARY);
+				break;
+			default:
+				cont = 0;
+		}
+	}
+
+	return p;
+}
 /*
  * This registers a new binary format, it recognises the syntax
  * ':name:type:offset:magic:mask:interpreter:'
@@ -292,10 +402,8 @@
 	if (!e->interpreter[0])
 		goto Einval;
 
-	if (*p == 'P') {
-		p++;
-		e->flags |= MISC_FMT_PRESERVE_ARGV0;
-	}
+
+	p = check_special_flags (p, e);
 
 	if (*p == '\n')
 		p++;
@@ -345,6 +453,7 @@
 {
 	char *dp;
 	char *status = "disabled";
+	const char * flags = "flags: ";
 
 	if (test_bit(Enabled, &e->flags))
 		status = "enabled";
@@ -356,6 +465,22 @@
 
 	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
 	dp = page + strlen(page);
+
+	/* print the special flags */
+	sprintf (dp, "%s", flags);
+	dp += strlen (flags);
+	if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
+		*dp ++ = 'P';
+	}
+	if (e->flags & MISC_FMT_OPEN_BINARY) {
+		*dp ++ = 'O';
+	}
+	if (e->flags & MISC_FMT_CREDENTIALS) {
+		*dp ++ = 'C';
+	}
+	*dp ++ = '\n';
+
+
 	if (!test_bit(Magic, &e->flags)) {
 		sprintf(dp, "extension .%s\n", e->magic);
 	} else {
--- diff/fs/binfmt_som.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/binfmt_som.c	2004-02-18 09:04:01.000000000 +0000
@@ -259,7 +259,7 @@
 	create_som_tables(bprm);
 
 	current->mm->start_stack = bprm->p;
-	current->mm->rss = 0;
+	zero_rss(current->mm);
 
 #if 0
 	printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk);
--- diff/fs/block_dev.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/block_dev.c	2004-02-18 09:04:01.000000000 +0000
@@ -146,8 +146,8 @@
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_mapping->host;
 
-	return blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
-				nr_segs, blkdev_get_blocks, NULL);
+	return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode),
+				iov, offset, nr_segs, blkdev_get_blocks, NULL);
 }
 
 static int blkdev_writepage(struct page *page, struct writeback_control *wbc)
@@ -525,7 +525,8 @@
 static void bd_set_size(struct block_device *bdev, loff_t size)
 {
 	unsigned bsize = bdev_hardsect_size(bdev);
-	i_size_write(bdev->bd_inode, size);
+
+	bdev->bd_inode->i_size = size;
 	while (bsize < PAGE_CACHE_SIZE) {
 		if (size & bsize)
 			break;
@@ -785,7 +786,7 @@
 	.fsync		= block_fsync,
 	.ioctl		= block_ioctl,
 	.readv		= generic_file_readv,
-	.writev		= generic_file_writev,
+	.writev		= generic_file_write_nolock,
 	.sendfile	= generic_file_sendfile,
 };
 
--- diff/fs/buffer.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/buffer.c	2004-02-18 09:04:01.000000000 +0000
@@ -431,6 +431,7 @@
 	printk("block=%llu, b_blocknr=%llu\n",
 		(unsigned long long)block, (unsigned long long)bh->b_blocknr);
 	printk("b_state=0x%08lx, b_size=%u\n", bh->b_state, bh->b_size);
+	printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
 out_unlock:
 	spin_unlock(&bd_mapping->private_lock);
 	page_cache_release(page);
@@ -857,10 +858,13 @@
 		struct buffer_head *bh = head;
 
 		do {
-			if (buffer_uptodate(bh))
+			if (buffer_uptodate(bh)) {
 				set_buffer_dirty(bh);
-			else
+				if (unlikely(block_dump))
+					printk("%s(%d): dirtied buffer\n", current->comm, current->pid);
+			} else {
 				buffer_error();
+			}
 			bh = bh->b_this_page;
 		} while (bh != head);
 	}
@@ -1806,23 +1810,23 @@
 
 	do {
 		get_bh(bh);
-		if (buffer_mapped(bh) && buffer_dirty(bh)) {
-			if (wbc->sync_mode != WB_SYNC_NONE) {
-				lock_buffer(bh);
-			} else {
-				if (test_set_buffer_locked(bh)) {
-					__set_page_dirty_nobuffers(page);
-					continue;
-				}
-			}
-			if (test_clear_buffer_dirty(bh)) {
-				if (!buffer_uptodate(bh))
-					buffer_error();
-				mark_buffer_async_write(bh);
-			} else {
-				unlock_buffer(bh);
+		if (!buffer_mapped(bh))
+			continue;
+		if (wbc->sync_mode != WB_SYNC_NONE) {
+			lock_buffer(bh);
+		} else {
+			if (test_set_buffer_locked(bh)) {
+				__set_page_dirty_nobuffers(page);
+				continue;
 			}
 		}
+		if (test_clear_buffer_dirty(bh)) {
+			if (!buffer_uptodate(bh))
+				buffer_error();
+			mark_buffer_async_write(bh);
+		} else {
+			unlock_buffer(bh);
+		}
 	} while ((bh = bh->b_this_page) != head);
 
 	BUG_ON(PageWriteback(page));
@@ -2987,33 +2991,26 @@
 	}
 }
 
-static void buffer_init_cpu(int cpu)
+#ifdef CONFIG_HOTPLUG_CPU
+static void buffer_exit_cpu(int cpu)
 {
-	struct bh_accounting *bha = &per_cpu(bh_accounting, cpu);
-	struct bh_lru *bhl = &per_cpu(bh_lrus, cpu);
+	int i;
+	struct bh_lru *b = &per_cpu(bh_lrus, cpu);
 
-	bha->nr = 0;
-	bha->ratelimit = 0;
-	memset(bhl, 0, sizeof(*bhl));
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		brelse(b->bhs[i]);
+		b->bhs[i] = NULL;
+	}
 }
-	
-static int __devinit buffer_cpu_notify(struct notifier_block *self, 
-				unsigned long action, void *hcpu)
+
+static int buffer_cpu_notify(struct notifier_block *self,
+			      unsigned long action, void *hcpu)
 {
-	long cpu = (long)hcpu;
-	switch(action) {
-	case CPU_UP_PREPARE:
-		buffer_init_cpu(cpu);
-		break;
-	default:
-		break;
-	}
+	if (action == CPU_DEAD)
+		buffer_exit_cpu((unsigned long)hcpu);
 	return NOTIFY_OK;
 }
-
-static struct notifier_block __devinitdata buffer_nb = {
-	.notifier_call	= buffer_cpu_notify,
-};
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init buffer_init(void)
 {
@@ -3031,9 +3028,7 @@
 	 */
 	nrpages = (nr_free_buffer_pages() * 10) / 100;
 	max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));
-	buffer_cpu_notify(&buffer_nb, (unsigned long)CPU_UP_PREPARE,
-				(void *)(long)smp_processor_id());
-	register_cpu_notifier(&buffer_nb);
+	hotcpu_notifier(buffer_cpu_notify, 0);
 }
 
 EXPORT_SYMBOL(__bforget);
--- diff/fs/compat.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/compat.c	2004-02-18 09:04:01.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/sockios.h>	/* for SIOCDEVPRIVATE */
 #include <linux/smp_lock.h>
+#include <linux/syscalls.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
 #include <net/sock.h>		/* siocdevprivate_ioctl */
@@ -494,8 +495,6 @@
 }
 #endif
 
-extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
-
 asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
 		unsigned long arg)
 {
@@ -559,8 +558,6 @@
 	return compat_sys_fcntl64(fd, cmd, arg);
 }
 
-extern asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
-
 asmlinkage long
 compat_sys_io_setup(unsigned nr_reqs, u32 *ctx32p)
 {
@@ -580,12 +577,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_io_getevents(aio_context_t ctx_id,
-					  long min_nr,
-					  long nr,
-					  struct io_event *events,
-					  struct timespec *timeout);
-
 asmlinkage long
 compat_sys_io_getevents(aio_context_t ctx_id,
 				 unsigned long min_nr,
@@ -614,9 +605,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_io_submit(aio_context_t, long, 
-				struct iocb __user **);
-
 static inline long
 copy_iocb(long nr, u32 *ptr32, u64 *ptr64)
 {
--- diff/fs/compat_ioctl.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/compat_ioctl.c	2004-02-18 09:04:01.000000000 +0000
@@ -62,6 +62,7 @@
 #include <linux/if_tun.h>
 #include <linux/ctype.h>
 #include <linux/ioctl32.h>
+#include <linux/syscalls.h>
 #include <linux/ncp_fs.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
--- diff/fs/dcache.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/dcache.c	2004-02-18 09:04:01.000000000 +0000
@@ -1531,6 +1531,16 @@
 	return ino;
 }
 
+static __initdata unsigned long dhash_entries;
+static int __init set_dhash_entries(char *str)
+{
+	if (!str)
+		return 0;
+	dhash_entries = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("dhash_entries=", set_dhash_entries);
+
 static void __init dcache_init(unsigned long mempages)
 {
 	struct hlist_head *d;
@@ -1556,11 +1566,13 @@
 	
 	set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
 
-#if PAGE_SHIFT < 13
-	mempages >>= (13 - PAGE_SHIFT);
-#endif
-	mempages *= sizeof(struct hlist_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
+	if (!dhash_entries)
+		dhash_entries = PAGE_SHIFT < 13 ?
+				mempages >> (13 - PAGE_SHIFT) :
+				mempages << (PAGE_SHIFT - 13);
+
+	dhash_entries *= sizeof(struct hlist_head);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < dhash_entries; order++)
 		;
 
 	do {
--- diff/fs/devfs/base.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/devfs/base.c	2004-02-18 09:04:01.000000000 +0000
@@ -676,6 +676,7 @@
 #include <linux/smp.h>
 #include <linux/rwsem.h>
 #include <linux/sched.h>
+#include <linux/namei.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -685,9 +686,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#include "internal.h"
-
-#define DEVFS_VERSION            "1.22 (20021013)"
+#define DEVFS_VERSION            "2004-01-31"
 
 #define DEVFS_NAME "devfs"
 
@@ -762,18 +761,6 @@
     unsigned char no_more_additions:1;
 };
 
-struct bdev_type
-{
-    dev_t dev;
-};
-
-struct cdev_type
-{
-    struct file_operations *ops;
-    dev_t dev;
-    unsigned char autogen:1;
-};
-
 struct symlink_type
 {
     unsigned int length;         /*  Not including the NULL-termimator       */
@@ -801,8 +788,7 @@
     union 
     {
 	struct directory_type dir;
-	struct bdev_type bdev;
-	struct cdev_type cdev;
+	dev_t dev;
 	struct symlink_type symlink;
 	const char *name;        /*  Only used for (mode == 0)               */
     }
@@ -813,7 +799,7 @@
     struct devfs_inode inode;
     umode_t mode;
     unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
-    unsigned char vfs_deletable:1;/*  Whether the VFS may delete the entry   */
+    unsigned char vfs:1;/*  Whether the VFS may delete the entry   */
     char name[1];                /*  This is just a dummy: the allocated array
 				     is bigger. This is NULL-terminated      */
 };
@@ -925,8 +911,6 @@
 	     de->name, de, de->parent,
 	     de->parent ? de->parent->name : "no parent");
     if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
-    if ( S_ISCHR (de->mode) && de->u.cdev.autogen )
-	devfs_dealloc_devnum (de->mode, de->u.cdev.dev);
     WRITE_ENTRY_MAGIC (de, 0);
 #ifdef CONFIG_DEVFS_DEBUG
     spin_lock (&stat_lock);
@@ -1063,46 +1047,40 @@
     return retval;
 }   /*  End Function _devfs_append_entry  */
 
-
 /**
  *	_devfs_get_root_entry - Get the root devfs entry.
  *
  *	Returns the root devfs entry on success, else %NULL.
+ *
+ *	TODO it must be called asynchronously due to the fact
+ *	that devfs is initialized relatively late. Proper way
+ *	is to remove module_init from init_devfs_fs and manually
+ *	call it early enough during system init
  */
 
-static struct devfs_entry *_devfs_get_root_entry (void)
+static struct devfs_entry *_devfs_get_root_entry(void)
 {
-    struct devfs_entry *new;
-    static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
+	struct devfs_entry *new;
+	static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
 
-    /*  Always ensure the root is created  */
-    if (root_entry) return root_entry;
-    if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
-    spin_lock (&root_lock);
-    if (root_entry)
-    {
-	spin_unlock (&root_lock);
-	devfs_put (new);
-	return (root_entry);
-    }
-    root_entry = new;
-    spin_unlock (&root_lock);
-    /*  And create the entry for ".devfsd"  */
-    if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
-	 == NULL ) return NULL;
-    new->u.cdev.dev = devfs_alloc_devnum (S_IFCHR |S_IRUSR |S_IWUSR);
-    new->u.cdev.ops = &devfsd_fops;
-    _devfs_append_entry (root_entry, new, NULL);
-#ifdef CONFIG_DEVFS_DEBUG
-    if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
-	 == NULL ) return NULL;
-    new->u.cdev.dev = devfs_alloc_devnum (S_IFCHR | S_IRUGO | S_IWUGO);
-    new->u.cdev.ops = &stat_fops;
-    _devfs_append_entry (root_entry, new, NULL);
-#endif
-    return root_entry;
-}   /*  End Function _devfs_get_root_entry  */
+	if (root_entry)
+		return root_entry;
 
+	new = _devfs_alloc_entry(NULL, 0, MODE_DIR);
+	if (new == NULL )
+		return NULL;
+
+	spin_lock(&root_lock);
+	if (root_entry) {
+		spin_unlock(&root_lock);
+		devfs_put(new);
+		return root_entry;
+	}
+	root_entry = new;
+	spin_unlock(&root_lock);
+
+	return root_entry;
+}   /*  End Function _devfs_get_root_entry  */
 
 /**
  *	_devfs_descend - Descend down a tree using the next component name.
@@ -1237,6 +1215,7 @@
 	}
 	if (S_ISLNK (de->mode) && traverse_symlink)
 	{   /*  Need to follow the link: this is a stack chomper  */
+		/* FIXME what if it puts outside of mounted tree? */
 	    link = _devfs_walk_path (dir, de->u.symlink.linkname,
 				     de->u.symlink.length, TRUE);
 	    devfs_put (de);
@@ -1444,27 +1423,19 @@
 			 current->egid, &fs_info);
 } 
 
-int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args)
 {
 	struct devfs_entry *dir = NULL, *de;
 	char buf[64];
-	va_list args;
 	int error, n;
 
-	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n >= 64 || !buf[0]) {
-		printk(KERN_WARNING "%s: invalid format string\n",
-				__FUNCTION__);
+	n = vsnprintf(buf, sizeof(buf), fmt, args);
+	if (n >= sizeof(buf) || !buf[0]) {
+		printk(KERN_WARNING "%s: invalid format string %s\n",
+				__FUNCTION__, fmt);
 		return -EINVAL;
 	}
 	
-	if (!S_ISBLK(mode)) {
-		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-				__FUNCTION__, mode, buf);
-		return -EINVAL;
-	}
-
 	de = _devfs_prepare_leaf(&dir, buf, mode);
 	if (!de) {
 		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
@@ -1472,7 +1443,7 @@
 		return -ENOMEM;		/* could be more accurate... */
 	}
 
-	de->u.bdev.dev = dev;
+	de->u.dev = dev;
 
 	error = _devfs_append_entry(dir, de, NULL);
 	if (error) {
@@ -1487,50 +1458,35 @@
 	return error;
 }
 
+int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!S_ISBLK(mode)) {
+		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
+				__FUNCTION__, mode, fmt);
+		return -EINVAL;
+	}
+
+	va_start(args, fmt);
+	return devfs_mk_dev(dev, mode, fmt, args);
+}
+
 EXPORT_SYMBOL(devfs_mk_bdev);
 
 
 int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
 {
-	struct devfs_entry *dir = NULL, *de;
-	char buf[64];
 	va_list args;
-	int error, n;
-
-	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n >= 64 || !buf[0]) {
-		printk(KERN_WARNING "%s: invalid format string\n",
-				__FUNCTION__);
-		return -EINVAL;
-	}
 
 	if (!S_ISCHR(mode)) {
 		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-				__FUNCTION__, mode, buf);
+				__FUNCTION__, mode, fmt);
 		return -EINVAL;
 	}
 
-	de = _devfs_prepare_leaf(&dir, buf, mode);
-	if (!de) {
-		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
-				__FUNCTION__, buf);
-		return -ENOMEM;		/* could be more accurate... */
-	}
-
-	de->u.cdev.dev = dev;
-
-	error = _devfs_append_entry(dir, de, NULL);
-	if (error) {
-		printk(KERN_WARNING "%s: could not append to parent for %s\n",
-				__FUNCTION__, buf);
-		goto out;
-	}
-
-	devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
- out:
-	devfs_put(dir);
-	return error;
+	va_start(args, fmt);
+	return devfs_mk_dev(dev, mode, fmt, args);
 }
 
 EXPORT_SYMBOL(devfs_mk_cdev);
@@ -1663,7 +1619,7 @@
 
 	err = devfs_do_symlink(NULL, from, to, &de);
 	if (!err) {
-		de->vfs_deletable = TRUE;
+		de->vfs = TRUE;
 		devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
 	}
 
@@ -1732,8 +1688,8 @@
 	int n;
 
 	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n < 64 && buf[0]) {
+	n = vsnprintf(buf, sizeof(buf), fmt, args);
+	if (n < sizeof(buf) && buf[0]) {
 		devfs_handle_t de = _devfs_find_entry(NULL, buf, 0);
 
 		if (!de) {
@@ -1784,33 +1740,6 @@
     return pos;
 }   /*  End Function devfs_generate_path  */
 
-
-/**
- *	devfs_get_ops - Get the device operations for a devfs entry.
- *	@de: The handle to the device entry.
- *
- *	Returns a pointer to the device operations on success, else NULL.
- *	The use count for the module owning the operations will be incremented.
- */
-
-static struct file_operations *devfs_get_ops (devfs_handle_t de)
-{
-    struct file_operations *ops = de->u.cdev.ops;
-    struct module *owner;
-
-    if (!ops)
-	return NULL;
-    owner = ops->owner;
-    read_lock (&de->parent->u.dir.lock);  /*  Prevent module from unloading  */
-    if ( (de->next == de) || !try_module_get (owner) )
-    {   /*  Entry is already unhooked or module is unloading  */
-	read_unlock (&de->parent->u.dir.lock);
-	return NULL;
-    }
-    read_unlock (&de->parent->u.dir.lock);  /*  Module can continue unloading*/
-    return ops;
-}   /*  End Function devfs_get_ops  */
-
 /**
  *	devfs_setup - Process kernel boot options.
  *	@str: The boot options after the "devfs=".
@@ -1876,7 +1805,6 @@
 
 __setup("devfs=", devfs_setup);
 
-EXPORT_SYMBOL(devfs_put);
 EXPORT_SYMBOL(devfs_mk_symlink);
 EXPORT_SYMBOL(devfs_mk_dir);
 EXPORT_SYMBOL(devfs_remove);
@@ -1996,6 +1924,7 @@
 	iput (inode);
 	return NULL;
     }
+    /* FIXME where is devfs_put? */
     inode->u.generic_ip = devfs_get (de);
     inode->i_ino = de->inode.ino;
     DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",
@@ -2003,26 +1932,25 @@
     inode->i_blocks = 0;
     inode->i_blksize = FAKE_BLOCK_SIZE;
     inode->i_op = &devfs_iops;
-    inode->i_fop = &devfs_fops;
-    if ( S_ISCHR (de->mode) )
-    {
-	inode->i_rdev = de->u.cdev.dev;
-    }
-    else if ( S_ISBLK (de->mode) )
-	init_special_inode(inode, de->mode, de->u.bdev.dev);
-    else if ( S_ISFIFO (de->mode) )
-    	inode->i_fop = &def_fifo_fops;
-    else if ( S_ISDIR (de->mode) )
-    {
-	inode->i_op = &devfs_dir_iops;
-    	inode->i_fop = &devfs_dir_fops;
-    }
-    else if ( S_ISLNK (de->mode) )
-    {
-	inode->i_op = &devfs_symlink_iops;
-	inode->i_size = de->u.symlink.length;
-    }
     inode->i_mode = de->mode;
+	if (S_ISDIR(de->mode)) {
+		inode->i_op = &devfs_dir_iops;
+		inode->i_fop = &devfs_dir_fops;
+	} else if (S_ISLNK(de->mode)) {
+		inode->i_op = &devfs_symlink_iops;
+		inode->i_size = de->u.symlink.length;
+	} else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) {
+		init_special_inode(inode, de->mode, de->u.dev);
+	} else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) {
+		init_special_inode(inode, de->mode, 0);
+	} else {
+		PRINTK("(%s): unknown mode %o de: %p\n",
+			de->name, de->mode, de);
+		iput(inode);
+		devfs_put(de);
+		return NULL;
+	}
+
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     inode->i_atime = de->inode.atime;
@@ -2098,29 +2026,37 @@
     return stored;
 }   /*  End Function devfs_readdir  */
 
+/* Open devfs specific special files */
 static int devfs_open (struct inode *inode, struct file *file)
 {
-    int err = -ENODEV;
-    struct devfs_entry *de;
-    struct file_operations *ops;
+	int err;
+	int minor = MINOR(inode->i_rdev);
+	struct file_operations *old_fops, *new_fops;
 
-    de = get_devfs_entry_from_vfs_inode (inode);
-    if (de == NULL) return -ENODEV;
-    if ( S_ISDIR (de->mode) ) return 0;
-    file->private_data = de->info;
-    if (S_ISCHR(inode->i_mode)) {
-	ops = devfs_get_ops (de);  /*  Now have module refcount  */
-	file->f_op = ops;
-	if (file->f_op)
-	{
-	    lock_kernel ();
-	    err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
-	    unlock_kernel ();
+	switch (minor) {
+	case 0: /* /dev/.devfsd */
+		new_fops = fops_get(&devfsd_fops);
+		break;
+#ifdef CONFIG_DEVFS_DEBUG
+	case 1: /* /dev/.stat */
+		new_fops = fops_get(&stat_fops);
+		break;
+#endif
+	default:
+		return -ENODEV;
 	}
-	else
-	    err = chrdev_open (inode, file);
-    }
-    return err;
+
+	if (new_fops == NULL)
+		return -ENODEV;
+	old_fops = file->f_op;
+	file->f_op = new_fops;
+	err = new_fops->open ? new_fops->open(inode, file) : 0;
+	if (err) {
+		file->f_op = old_fops;
+		fops_put(new_fops);
+	} else
+		fops_put(old_fops);
+	return err;
 }   /*  End Function devfs_open  */
 
 static struct file_operations devfs_fops =
@@ -2132,7 +2068,6 @@
 {
     .read    = generic_read_dir,
     .readdir = devfs_readdir,
-    .open    = devfs_open,
 };
 
 
@@ -2223,6 +2158,34 @@
     devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
     struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
     DECLARE_WAITQUEUE (wait, current);
+    int need_lock;
+
+    /*
+     * FIXME HACK
+     *
+     * make sure that
+     *   d_instantiate always runs under lock
+     *   we release i_sem lock before going to sleep
+     *
+     * unfortunately sometimes d_revalidate is called with
+     * and sometimes without i_sem lock held. The following checks
+     * attempt to deduce when we need to add (and drop resp.) lock
+     * here. This relies on current (2.6.2) calling coventions:
+     *
+     *   lookup_hash is always run under i_sem and is passing NULL
+     *   as nd
+     *
+     *   open(...,O_CREATE,...) calls _lookup_hash under i_sem
+     *   and sets flags to LOOKUP_OPEN|LOOKUP_CREATE
+     *
+     *   all other invocations of ->d_revalidate seem to happen
+     *   outside of i_sem
+     */
+    need_lock = nd &&
+		(!(nd->flags & LOOKUP_CREATE) || (nd->flags & LOOKUP_PARENT));
+
+    if (need_lock)
+	down(&dir->i_sem);
 
     if ( is_devfsd_or_child (fs_info) )
     {
@@ -2233,33 +2196,40 @@
 		 "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
 		 dentry->d_name.name, dentry, dentry->d_inode, de,
 		 current->comm);
-	if (dentry->d_inode) return 1;
+	if (dentry->d_inode)
+	    goto out;
 	if (de == NULL)
 	{
 	    read_lock (&parent->u.dir.lock);
 	    de = _devfs_search_dir (parent, dentry->d_name.name,
 				    dentry->d_name.len);
 	    read_unlock (&parent->u.dir.lock);
-	    if (de == NULL) return 1;
+	    if (de == NULL)
+		goto out;
 	    lookup_info->de = de;
 	}
 	/*  Create an inode, now that the driver information is available  */
 	inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
-	if (!inode) return 1;
+	if (!inode)
+	    goto out;
 	DPRINTK (DEBUG_I_LOOKUP,
 		 "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
 		 de->name, de->inode.ino, inode, de, current->comm);
 	d_instantiate (dentry, inode);
-	return 1;
+	goto out;
     }
-    if (lookup_info == NULL) return 1;  /*  Early termination  */
+    if (lookup_info == NULL)
+	goto out;  /*  Early termination  */
     read_lock (&parent->u.dir.lock);
     if (dentry->d_fsdata)
     {
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	add_wait_queue (&lookup_info->wait_queue, &wait);
 	read_unlock (&parent->u.dir.lock);
+	/* at this point it is always (hopefully) locked */
+	up(&dir->i_sem);
 	schedule ();
+	down(&dir->i_sem);
 	/*
 	 * This does not need nor should remove wait from wait_queue.
 	 * Wait queue head is never reused - nothing is ever added to it
@@ -2271,6 +2241,10 @@
 
     }
     else read_unlock (&parent->u.dir.lock);
+
+out:
+    if (need_lock)
+	up(&dir->i_sem);
     return 1;
 }   /*  End Function devfs_d_revalidate_wait  */
 
@@ -2320,6 +2294,7 @@
 	revalidation  */
     up (&dir->i_sem);
     wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
+    down (&dir->i_sem);      /*  Grab it again because them's the rules  */
     de = lookup_info.de;
     /*  If someone else has been so kind as to make the inode, we go home
 	early  */
@@ -2349,7 +2324,6 @@
     dentry->d_fsdata = NULL;
     wake_up (&lookup_info.wait_queue);
     write_unlock (&parent->u.dir.lock);
-    down (&dir->i_sem);      /*  Grab it again because them's the rules  */
     devfs_put (de);
     return retval;
 }   /*  End Function devfs_lookup  */
@@ -2364,7 +2338,7 @@
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
     if (de == NULL) return -ENOENT;
-    if (!de->vfs_deletable) return -EPERM;
+    if (!de->vfs) return -EPERM;
     write_lock (&de->parent->u.dir.lock);
     unhooked = _devfs_unhook (de);
     write_unlock (&de->parent->u.dir.lock);
@@ -2392,7 +2366,7 @@
     DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
 	     dentry->d_name.name, err);
     if (err < 0) return err;
-    de->vfs_deletable = TRUE;
+    de->vfs = TRUE;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
@@ -2421,7 +2395,7 @@
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
     if (!de) return -ENOMEM;
-    de->vfs_deletable = TRUE;
+    de->vfs = TRUE;
     if ( ( err = _devfs_append_entry (parent, de, NULL) ) != 0 )
 	return err;
     de->inode.uid = current->euid;
@@ -2451,7 +2425,7 @@
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
-    if (!de->vfs_deletable) return -EPERM;
+    if (!de->vfs) return -EPERM;
     /*  First ensure the directory is empty and will stay that way  */
     write_lock (&de->u.dir.lock);
     if (de->u.dir.first) err = -ENOTEMPTY;
@@ -2485,11 +2459,9 @@
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
     if (!de) return -ENOMEM;
-    de->vfs_deletable = TRUE;
-    if (S_ISCHR (mode))
-	de->u.cdev.dev = rdev;
-    else if (S_ISBLK (mode))
-	de->u.bdev.dev = rdev;
+    de->vfs = TRUE;
+    if (S_ISCHR(mode) || S_ISBLK(mode))
+	de->u.dev = rdev;
     if ( ( err = _devfs_append_entry (parent, de, NULL) ) != 0 )
 	return err;
     de->inode.uid = current->euid;
@@ -2642,12 +2614,9 @@
     info->uid = entry->uid;
     info->gid = entry->gid;
     de = entry->de;
-    if (S_ISCHR(de->mode)) {
-	info->major = MAJOR(de->u.cdev.dev);
-	info->minor = MINOR(de->u.cdev.dev);
-    } else if (S_ISBLK (de->mode)) {
-	info->major = MAJOR(de->u.bdev.dev);
-	info->minor = MINOR(de->u.bdev.dev);
+    if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) {
+	info->major = MAJOR(de->u.dev);
+	info->minor = MINOR(de->u.dev);
     }
     pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
     if (pos < 0) return pos;
@@ -2809,30 +2778,53 @@
 }   /*  End Function stat_read  */
 #endif
 
-
-static int __init init_devfs_fs (void)
+static int __init init_devfs_fs(void)
 {
-    int err;
+	int err;
+	int major;
+	struct devfs_entry *devfsd;
+#ifdef CONFIG_DEVFS_DEBUG
+	struct devfs_entry *stat;
+#endif
 
-    printk (KERN_INFO "%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
-	    DEVFS_NAME, DEVFS_VERSION);
-    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
+	if (_devfs_get_root_entry() == NULL)
+		return -ENOMEM;
+
+	printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n",
+	       DEVFS_NAME, DEVFS_VERSION);
+	devfsd_buf_cache = kmem_cache_create("devfsd_event",
 					  sizeof (struct devfsd_buf_entry),
 					  0, 0, NULL, NULL);
-    if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
+	if (!devfsd_buf_cache)
+		OOPS("(): unable to allocate event slab\n");
 #ifdef CONFIG_DEVFS_DEBUG
-    devfs_debug = devfs_debug_init;
-    printk (KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
+	devfs_debug = devfs_debug_init;
+	printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
 #endif
-    printk (KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
-    err = register_filesystem (&devfs_fs_type);
-    if (!err)
-    {
-	struct vfsmount *devfs_mnt = kern_mount (&devfs_fs_type);
-	err = PTR_ERR (devfs_mnt);
-	if ( !IS_ERR (devfs_mnt) ) err = 0;
-    }
-    return err;
+	printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
+
+	/* register special device for devfsd communication */
+	major = register_chrdev(0, "devfs", &devfs_fops);
+	if (major < 0)
+		return major;
+
+	/*  And create the entry for ".devfsd"  */
+	devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR|S_IRUSR|S_IWUSR);
+	if (devfsd == NULL )
+		return -ENOMEM;
+	devfsd->u.dev = MKDEV(major, 0);
+	_devfs_append_entry(root_entry, devfsd, NULL);
+
+#ifdef CONFIG_DEVFS_DEBUG
+	stat = _devfs_alloc_entry(".stat", 0, S_IFCHR|S_IRUGO);
+	if (stat == NULL )
+		return -ENOMEM;
+	stat->u.dev = MKDEV(major, 1);
+	_devfs_append_entry (root_entry, stat, NULL);
+#endif
+
+	err = register_filesystem(&devfs_fs_type);
+	return err;
 }   /*  End Function init_devfs_fs  */
 
 void __init mount_devfs_fs (void)
--- diff/fs/devfs/util.c	2003-05-21 11:50:16.000000000 +0100
+++ source/fs/devfs/util.c	2004-02-18 09:04:01.000000000 +0000
@@ -72,7 +72,6 @@
 #include <linux/vmalloc.h>
 #include <linux/genhd.h>
 #include <asm/bitops.h>
-#include "internal.h"
 
 
 int devfs_register_tape(const char *name)
@@ -96,161 +95,3 @@
 }
 
 EXPORT_SYMBOL(devfs_unregister_tape);
-
-struct major_list
-{
-    spinlock_t lock;
-    unsigned long bits[256 / BITS_PER_LONG];
-};
-#if BITS_PER_LONG == 32
-#  define INITIALISER64(low,high) (low), (high)
-#else
-#  define INITIALISER64(low,high) ( (unsigned long) (high) << 32 | (low) )
-#endif
-
-/*  Block majors already assigned:
-    0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
-    Total free: 122
-*/
-static struct major_list block_major_list =
-{SPIN_LOCK_UNLOCKED,
-    {INITIALISER64 (0xfffffb8f, 0xffffffff),  /*  Majors 0-31,    32-63    */
-     INITIALISER64 (0xfffffffe, 0xff03ffef),  /*  Majors 64-95,   96-127   */
-     INITIALISER64 (0x00000000, 0x00000000),  /*  Majors 128-159, 160-191  */
-     INITIALISER64 (0x00000280, 0xffff0000),  /*  Majors 192-223, 224-255  */
-    }
-};
-
-/*  Char majors already assigned:
-    0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
-    Total free: 19
-*/
-static struct major_list char_major_list =
-{SPIN_LOCK_UNLOCKED,
-    {INITIALISER64 (0xfffffeff, 0xffffffff),  /*  Majors 0-31,    32-63    */
-     INITIALISER64 (0xffffffff, 0xffffffff),  /*  Majors 64-95,   96-127   */
-     INITIALISER64 (0x7cffffff, 0xffffffff),  /*  Majors 128-159, 160-191  */
-     INITIALISER64 (0x3f0fffff, 0xffff007f),  /*  Majors 192-223, 224-255  */
-    }
-};
-
-
-/**
- *	devfs_alloc_major - Allocate a major number.
- *	@mode: The file mode (must be block device or character device).
- *	Returns the allocated major, else -1 if none are available.
- *	This routine is thread safe and does not block.
- */
-
-
-struct minor_list
-{
-    int major;
-    unsigned long bits[256 / BITS_PER_LONG];
-    struct minor_list *next;
-};
-
-static struct device_list {
-	struct minor_list	*first;
-	struct minor_list	*last;
-	int			none_free;
-} block_list, char_list;
-
-static DECLARE_MUTEX(device_list_mutex);
-
-
-/**
- *	devfs_alloc_devnum - Allocate a device number.
- *	@mode: The file mode (must be block device or character device).
- *
- *	Returns the allocated device number, else NODEV if none are available.
- *	This routine is thread safe and may block.
- */
-
-dev_t devfs_alloc_devnum(umode_t mode)
-{
-	struct device_list *list;
-	struct major_list *major_list;
-	struct minor_list *entry;
-	int minor;
-
-	if (S_ISCHR(mode)) {
-		major_list = &char_major_list;
-		list = &char_list;
-	} else {
-		major_list = &block_major_list;
-		list = &block_list;
-	}
-
-	down(&device_list_mutex);
-	if (list->none_free)
-		goto out_unlock;
-
-	for (entry = list->first; entry; entry = entry->next) {
-		minor = find_first_zero_bit (entry->bits, 256);
-		if (minor >= 256)
-			continue;
-		goto out_done;
-	}
-	
-	/*  Need to allocate a new major  */
-	entry = kmalloc (sizeof *entry, GFP_KERNEL);
-	if (!entry)
-		goto out_full;
-	memset(entry, 0, sizeof *entry);
-
-	spin_lock(&major_list->lock);
-	entry->major = find_first_zero_bit(major_list->bits, 256);
-	if (entry->major >= 256) {
-		spin_unlock(&major_list->lock);
-		kfree(entry);
-		goto out_full;
-	}
-	__set_bit(entry->major, major_list->bits);
-	spin_unlock(&major_list->lock);
-
-	if (!list->first)
-		list->first = entry;
-	else
-		list->last->next = entry;
-	list->last = entry;
-
-	minor = 0;
- out_done:
-	__set_bit(minor, entry->bits);
-	up(&device_list_mutex);
-	return MKDEV(entry->major, minor);
- out_full:
-	list->none_free = 1;
- out_unlock:
-	up(&device_list_mutex);
-	return 0;
-}
-
-
-/**
- *	devfs_dealloc_devnum - Dellocate a device number.
- *	@mode: The file mode (must be block device or character device).
- *	@devnum: The device number.
- *
- *	This routine is thread safe and may block.
- */
-
-void devfs_dealloc_devnum(umode_t mode, dev_t devnum)
-{
-	struct device_list *list = S_ISCHR(mode) ? &char_list : &block_list;
-	struct minor_list *entry;
-
-	if (!devnum)
-		return;
-
-	down(&device_list_mutex);
-	for (entry = list->first; entry; entry = entry->next) {
-		if (entry->major == MAJOR(devnum)) {
-			if (__test_and_clear_bit(MINOR(devnum), entry->bits))
-				list->none_free = 0;
-			break;
-		}
-	}
-	up(&device_list_mutex);
-}
--- diff/fs/devpts/Makefile	2003-08-20 14:16:13.000000000 +0100
+++ source/fs/devpts/Makefile	2004-02-18 09:04:01.000000000 +0000
@@ -2,8 +2,8 @@
 # Makefile for the Linux /dev/pts virtual filesystem.
 #
 
-obj-$(CONFIG_DEVPTS_FS) += devpts.o
+obj-$(CONFIG_UNIX98_PTYS)		+= devpts.o
 
-devpts-y := inode.o
+devpts-$(CONFIG_UNIX98_PTYS)		:= inode.o
 devpts-$(CONFIG_DEVPTS_FS_XATTR)	+= xattr.o 
 devpts-$(CONFIG_DEVPTS_FS_SECURITY)	+= xattr_security.o
--- diff/fs/devpts/inode.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/devpts/inode.c	2004-02-18 09:04:01.000000000 +0000
@@ -2,7 +2,7 @@
  *
  * linux/fs/devpts/inode.c
  *
- *  Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *  Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -16,6 +16,8 @@
 #include <linux/sched.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/tty.h>
+#include <linux/devpts_fs.h>
 #include "xattr.h"
 
 #define DEVPTS_SUPER_MAGIC 0x1cd1
@@ -126,7 +128,7 @@
 
 static struct dentry *get_node(int num)
 {
-	char s[10];
+	char s[12];
 	struct dentry *root = devpts_root;
 	down(&root->d_inode->i_sem);
 	return lookup_one_len(s, root, sprintf(s, "%d", num));
@@ -139,12 +141,21 @@
 	.removexattr	= devpts_removexattr,
 };
 
-void devpts_pty_new(int number, dev_t device)
+int devpts_pty_new(struct tty_struct *tty)
 {
+	int number = tty->index;
+	struct tty_driver *driver = tty->driver;
+	dev_t device = MKDEV(driver->major, driver->minor_start+number);
 	struct dentry *dentry;
 	struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+
+	/* We're supposed to be given the slave end of a pty */
+	BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
+	BUG_ON(driver->subtype != PTY_TYPE_SLAVE);
+
 	if (!inode)
-		return;
+		return -ENOMEM;
+
 	inode->i_ino = number+2;
 	inode->i_blksize = 1024;
 	inode->i_uid = config.setuid ? config.uid : current->fsuid;
@@ -152,11 +163,28 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	inode->i_op = &devpts_file_inode_operations;
+	inode->u.generic_ip = tty;
 
 	dentry = get_node(number);
 	if (!IS_ERR(dentry) && !dentry->d_inode)
 		d_instantiate(dentry, inode);
+
+	up(&devpts_root->d_inode->i_sem);
+
+	return 0;
+}
+
+struct tty_struct *devpts_get_tty(int number)
+{
+	struct dentry *dentry = get_node(number);
+	struct tty_struct *tty;
+
+	tty = (IS_ERR(dentry) || !dentry->d_inode) ? NULL :
+			dentry->d_inode->u.generic_ip;
+
 	up(&devpts_root->d_inode->i_sem);
+
+	return tty;
 }
 
 void devpts_pty_kill(int number)
--- diff/fs/direct-io.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/direct-io.c	2004-02-18 09:04:01.000000000 +0000
@@ -52,6 +52,10 @@
  *
  * If blkfactor is zero then the user's request was aligned to the filesystem's
  * blocksize.
+ *
+ * needs_locking is set for regular files on direct-IO-naive filesystems.  It
+ * determines whether we need to do the fancy locking which prevents direct-IO
+ * from being able to read uninitialised disk blocks.
  */
 
 struct dio {
@@ -59,6 +63,7 @@
 	struct bio *bio;		/* bio under assembly */
 	struct inode *inode;
 	int rw;
+	int needs_locking;		/* doesn't change */
 	unsigned blkbits;		/* doesn't change */
 	unsigned blkfactor;		/* When we're using an alignment which
 					   is finer than the filesystem's soft
@@ -69,6 +74,7 @@
 					   been performed at the start of a
 					   write */
 	int pages_in_io;		/* approximate total IO pages */
+	size_t	size;			/* total request size (doesn't change)*/
 	sector_t block_in_file;		/* Current offset into the underlying
 					   file in dio_block units. */
 	unsigned blocks_available;	/* At block_in_file.  changes */
@@ -110,9 +116,9 @@
 	int page_errors;		/* errno from get_user_pages() */
 
 	/* BIO completion state */
-	atomic_t bio_count;		/* nr bios to be completed */
-	atomic_t bios_in_flight;	/* nr bios in flight */
-	spinlock_t bio_list_lock;	/* protects bio_list */
+	spinlock_t bio_lock;		/* protects BIO fields below */
+	int bio_count;			/* nr bios to be completed */
+	int bios_in_flight;		/* nr bios in flight */
 	struct bio *bio_list;		/* singly linked via bi_private */
 	struct task_struct *waiter;	/* waiting task (NULL if none) */
 
@@ -204,8 +210,10 @@
  */
 static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
 {
-	if (dio->end_io)
+	if (dio->end_io && dio->result)
 		dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private);
+	if (dio->needs_locking)
+		up_read(&dio->inode->i_alloc_sem);
 }
 
 /*
@@ -214,14 +222,38 @@
  */
 static void finished_one_bio(struct dio *dio)
 {
-	if (atomic_dec_and_test(&dio->bio_count)) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&dio->bio_lock, flags);
+	if (dio->bio_count == 1) {
 		if (dio->is_async) {
+			/*
+			 * Last reference to the dio is going away.
+			 * Drop spinlock and complete the DIO.
+			 */
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			dio_complete(dio, dio->block_in_file << dio->blkbits,
 					dio->result);
-			aio_complete(dio->iocb, dio->result, 0);
-			kfree(dio);
+			/* Complete AIO later if falling back to buffered i/o */
+			if (dio->result == dio->size || dio->rw == READ) {
+				aio_complete(dio->iocb, dio->result, 0);
+				kfree(dio);
+				return;
+			} else {
+				/*
+				 * Falling back to buffered
+				 */
+				spin_lock_irqsave(&dio->bio_lock, flags);
+				dio->bio_count--;
+				if (dio->waiter)
+					wake_up_process(dio->waiter);
+				spin_unlock_irqrestore(&dio->bio_lock, flags);
+				return;
+			}
 		}
 	}
+	dio->bio_count--;
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 }
 
 static int dio_bio_complete(struct dio *dio, struct bio *bio);
@@ -255,13 +287,13 @@
 	if (bio->bi_size)
 		return 1;
 
-	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	spin_lock_irqsave(&dio->bio_lock, flags);
 	bio->bi_private = dio->bio_list;
 	dio->bio_list = bio;
-	atomic_dec(&dio->bios_in_flight);
-	if (dio->waiter && atomic_read(&dio->bios_in_flight) == 0)
+	dio->bios_in_flight--;
+	if (dio->waiter && dio->bios_in_flight == 0)
 		wake_up_process(dio->waiter);
-	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	return 0;
 }
 
@@ -294,10 +326,13 @@
 static void dio_bio_submit(struct dio *dio)
 {
 	struct bio *bio = dio->bio;
+	unsigned long flags;
 
 	bio->bi_private = dio;
-	atomic_inc(&dio->bio_count);
-	atomic_inc(&dio->bios_in_flight);
+	spin_lock_irqsave(&dio->bio_lock, flags);
+	dio->bio_count++;
+	dio->bios_in_flight++;
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	if (dio->is_async && dio->rw == READ)
 		bio_set_pages_dirty(bio);
 	submit_bio(dio->rw, bio);
@@ -323,22 +358,22 @@
 	unsigned long flags;
 	struct bio *bio;
 
-	spin_lock_irqsave(&dio->bio_list_lock, flags);
+	spin_lock_irqsave(&dio->bio_lock, flags);
 	while (dio->bio_list == NULL) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		if (dio->bio_list == NULL) {
 			dio->waiter = current;
-			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			blk_run_queues();
 			io_schedule();
-			spin_lock_irqsave(&dio->bio_list_lock, flags);
+			spin_lock_irqsave(&dio->bio_lock, flags);
 			dio->waiter = NULL;
 		}
 		set_current_state(TASK_RUNNING);
 	}
 	bio = dio->bio_list;
 	dio->bio_list = bio->bi_private;
-	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	spin_unlock_irqrestore(&dio->bio_lock, flags);
 	return bio;
 }
 
@@ -380,7 +415,12 @@
 	if (dio->bio)
 		dio_bio_submit(dio);
 
-	while (atomic_read(&dio->bio_count)) {
+	/*
+	 * The bio_lock is not held for the read of bio_count.
+	 * This is ok since it is the dio_bio_complete() that changes
+	 * bio_count.
+	 */
+	while (dio->bio_count) {
 		struct bio *bio = dio_await_one(dio);
 		int ret2;
 
@@ -407,10 +447,10 @@
 			unsigned long flags;
 			struct bio *bio;
 
-			spin_lock_irqsave(&dio->bio_list_lock, flags);
+			spin_lock_irqsave(&dio->bio_lock, flags);
 			bio = dio->bio_list;
 			dio->bio_list = bio->bi_private;
-			spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
 			ret = dio_bio_complete(dio, bio);
 		}
 		dio->reap_counter = 0;
@@ -449,6 +489,7 @@
 	unsigned long fs_count;	/* Number of filesystem-sized blocks */
 	unsigned long dio_count;/* Number of dio_block-sized blocks */
 	unsigned long blkmask;
+	int beyond_eof = 0;
 
 	/*
 	 * If there was a memory error and we've overwritten all the
@@ -466,8 +507,19 @@
 		if (dio_count & blkmask)	
 			fs_count++;
 
+		if (dio->needs_locking) {
+			if (dio->block_in_file >= (i_size_read(dio->inode) >>
+							dio->blkbits))
+				beyond_eof = 1;
+		}
+		/*
+		 * For writes inside i_size we forbid block creations: only
+		 * overwrites are permitted.  We fall back to buffered writes
+		 * at a higher level for inside-i_size block-instantiating
+		 * writes.
+		 */
 		ret = (*dio->get_blocks)(dio->inode, fs_startblk, fs_count,
-				map_bh, dio->rw == WRITE);
+				map_bh, (dio->rw == WRITE) && beyond_eof);
 	}
 	return ret;
 }
@@ -774,6 +826,10 @@
 			if (!buffer_mapped(map_bh)) {
 				char *kaddr;
 
+				/* AKPM: eargh, -ENOTBLK is a hack */
+				if (dio->rw == WRITE)
+					return -ENOTBLK;
+
 				if (dio->block_in_file >=
 					i_size_read(dio->inode)>>blkbits) {
 					/* We hit eof */
@@ -839,32 +895,30 @@
 	return ret;
 }
 
+/*
+ * Releases both i_sem and i_alloc_sem
+ */
 static int
 direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, 
 	const struct iovec *iov, loff_t offset, unsigned long nr_segs, 
-	unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io)
+	unsigned blkbits, get_blocks_t get_blocks, dio_iodone_t end_io,
+	struct dio *dio)
 {
 	unsigned long user_addr; 
 	int seg;
 	int ret = 0;
 	int ret2;
-	struct dio *dio;
 	size_t bytes;
 
-	dio = kmalloc(sizeof(*dio), GFP_KERNEL);
-	if (!dio)
-		return -ENOMEM;
-	dio->is_async = !is_sync_kiocb(iocb);
-
 	dio->bio = NULL;
 	dio->inode = inode;
 	dio->rw = rw;
 	dio->blkbits = blkbits;
 	dio->blkfactor = inode->i_blkbits - blkbits;
 	dio->start_zero_done = 0;
+	dio->size = 0;
 	dio->block_in_file = offset >> blkbits;
 	dio->blocks_available = 0;
-
 	dio->cur_page = NULL;
 
 	dio->boundary = 0;
@@ -887,9 +941,9 @@
 	 * (or synchronous) device could take the count to zero while we're
 	 * still submitting BIOs.
 	 */
-	atomic_set(&dio->bio_count, 1);
-	atomic_set(&dio->bios_in_flight, 0);
-	spin_lock_init(&dio->bio_list_lock);
+	dio->bio_count = 1;
+	dio->bios_in_flight = 0;
+	spin_lock_init(&dio->bio_lock);
 	dio->bio_list = NULL;
 	dio->waiter = NULL;
 
@@ -899,7 +953,7 @@
 
 	for (seg = 0; seg < nr_segs; seg++) {
 		user_addr = (unsigned long)iov[seg].iov_base;
-		bytes = iov[seg].iov_len;
+		dio->size += bytes = iov[seg].iov_len;
 
 		/* Index into the first page of the first block */
 		dio->first_block_in_page = (user_addr & ~PAGE_MASK) >> blkbits;
@@ -930,6 +984,13 @@
 		}
 	} /* end iovec loop */
 
+	if (ret == -ENOTBLK && rw == WRITE) {
+		/*
+		 * The remaining part of the request will be
+		 * be handled by buffered I/O when we return
+		 */
+		ret = 0;
+	}
 	/*
 	 * There may be some unwritten disk at the end of a part-written
 	 * fs-block-sized block.  Go zero that now.
@@ -953,14 +1014,48 @@
 	dio_cleanup(dio);
 
 	/*
+	 * All block lookups have been performed. For READ requests
+	 * we can let i_sem go now that its achieved its purpose
+	 * of protecting us from looking up uninitialized blocks.
+	 */
+	if ((rw == READ) && dio->needs_locking)
+		up(&dio->inode->i_sem);
+
+	/*
 	 * OK, all BIOs are submitted, so we can decrement bio_count to truly
 	 * reflect the number of to-be-processed BIOs.
 	 */
 	if (dio->is_async) {
+		int should_wait = 0;
+
+		if (dio->result < dio->size && rw == WRITE) {
+			dio->waiter = current;
+			should_wait = 1;
+		}
 		if (ret == 0)
-			ret = dio->result;	/* Bytes written */
+			ret = dio->result;
 		finished_one_bio(dio);		/* This can free the dio */
 		blk_run_queues();
+		if (should_wait) {
+			unsigned long flags;
+			/*
+			 * Wait for already issued I/O to drain out and
+			 * release its references to user-space pages
+			 * before returning to fallback on buffered I/O
+			 */
+
+			spin_lock_irqsave(&dio->bio_lock, flags);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			while (dio->bio_count) {
+				spin_unlock_irqrestore(&dio->bio_lock, flags);
+				io_schedule();
+				spin_lock_irqsave(&dio->bio_lock, flags);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+			}
+			spin_unlock_irqrestore(&dio->bio_lock, flags);
+			set_current_state(TASK_RUNNING);
+			kfree(dio);
+		}
 	} else {
 		finished_one_bio(dio);
 		ret2 = dio_await_completion(dio);
@@ -980,6 +1075,10 @@
 				ret = i_size - offset;
 		}
 		dio_complete(dio, offset, ret);
+		/* We could have also come here on an AIO file extend */
+		if (!is_sync_kiocb(iocb) && !(rw == WRITE && ret >= 0 &&
+			dio->result < dio->size))
+			aio_complete(iocb, ret, 0);
 		kfree(dio);
 	}
 	return ret;
@@ -987,11 +1086,17 @@
 
 /*
  * This is a library function for use by filesystem drivers.
+ *
+ * For writes to S_ISREG files, we are called under i_sem and return with i_sem
+ * held, even though it is internally dropped.
+ *
+ * For writes to S_ISBLK files, i_sem is not held on entry; it is never taken.
  */
 int
-blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io)
+	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	int needs_special_locking)
 {
 	int seg;
 	size_t size;
@@ -1000,6 +1105,9 @@
 	unsigned bdev_blkbits = 0;
 	unsigned blocksize_mask = (1 << blkbits) - 1;
 	ssize_t retval = -EINVAL;
+	loff_t end = offset;
+	struct dio *dio;
+	int needs_locking;
 
 	if (bdev)
 		bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));
@@ -1016,6 +1124,7 @@
 	for (seg = 0; seg < nr_segs; seg++) {
 		addr = (unsigned long)iov[seg].iov_base;
 		size = iov[seg].iov_len;
+		end += size;
 		if ((addr & blocksize_mask) || (size & blocksize_mask))  {
 			if (bdev)
 				 blkbits = bdev_blkbits;
@@ -1025,10 +1134,46 @@
 		}
 	}
 
-	retval = direct_io_worker(rw, iocb, inode, iov, offset, 
-				nr_segs, blkbits, get_blocks, end_io);
+	dio = kmalloc(sizeof(*dio), GFP_KERNEL);
+	retval = -ENOMEM;
+	if (!dio)
+		goto out;
+
+	/*
+	 * For regular files,
+	 *	readers need to grab i_sem and i_alloc_sem
+	 *	writers need to grab i_alloc_sem only (i_sem is already held)
+	 */
+	needs_locking = 0;
+	if (S_ISREG(inode->i_mode) && needs_special_locking) {
+		needs_locking = 1;
+		if (rw == READ) {
+			struct address_space *mapping;
+
+			mapping = iocb->ki_filp->f_mapping;
+			down(&inode->i_sem);
+			retval = filemap_write_and_wait(mapping);
+			if (retval) {
+				up(&inode->i_sem);
+				kfree(dio);
+				goto out;
+			}
+		}
+		down_read(&inode->i_alloc_sem);
+	}
+	dio->needs_locking = needs_locking;
+	/*
+	 * For file extending writes updating i_size before data
+	 * writeouts complete can expose uninitialized blocks. So
+	 * even for AIO, we need to wait for i/o to complete before
+	 * returning in this case.
+	 */
+	dio->is_async = !is_sync_kiocb(iocb) && !((rw == WRITE) &&
+		(end > i_size_read(inode)));
+
+	retval = direct_io_worker(rw, iocb, inode, iov, offset,
+				nr_segs, blkbits, get_blocks, end_io, dio);
 out:
 	return retval;
 }
-
-EXPORT_SYMBOL(blockdev_direct_IO);
+EXPORT_SYMBOL(__blockdev_direct_IO);
--- diff/fs/dquot.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/dquot.c	2004-02-18 09:04:01.000000000 +0000
@@ -261,6 +261,25 @@
 	up(&dquot->dq_lock);
 }
 
+#define mark_dquot_dirty(dquot) ((dquot)->dq_sb->dq_op->mark_dirty(dquot))
+
+int dquot_mark_dquot_dirty(struct dquot *dquot)
+{
+	spin_lock(&dq_data_lock);
+	set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->info[(dquot)->dq_type].dqi_flags));
+	set_bit(DQ_MOD_B, &(dquot)->dq_flags);
+	spin_unlock(&dq_data_lock);
+	return 0;
+}
+
+void mark_info_dirty(struct super_block *sb, int type)
+{
+	spin_lock(&dq_data_lock);
+	set_bit(DQF_INFO_DIRTY_B, &sb_dqopt(sb)->info[type].dqi_flags);
+	spin_unlock(&dq_data_lock);
+}
+
+
 static int read_dqblk(struct dquot *dquot)
 {
 	int ret;
@@ -274,14 +293,21 @@
 	return ret;
 }
 
-static int commit_dqblk(struct dquot *dquot)
+/*
+ *	Write dquot to disk
+ */
+int dquot_commit(struct dquot *dquot, int init)
 {
-	int ret;
+	int ret = 0;
 	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
 	down(&dqopt->dqio_sem);
-	ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+	clear_bit(DQ_MOD_B, &dquot->dq_flags);
+	if (!init || !dquot->dq_off)	/* Isn't dquot already allocated? */
+		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot, init);
 	up(&dqopt->dqio_sem);
+	if (info_dirty(&dqopt->info[dquot->dq_type]))
+		dquot->dq_sb->dq_op->write_info(dquot->dq_sb, dquot->dq_type);
 	return ret;
 }
 
@@ -316,7 +342,7 @@
 	spin_unlock(&dq_list_lock);
 }
 
-static int vfs_quota_sync(struct super_block *sb, int type)
+int vfs_quota_sync(struct super_block *sb, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
@@ -327,9 +353,11 @@
 restart:
 	/* At this point any dirty dquot will definitely be written so we can clear
 	   dirty flag from info */
+	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt))
 			clear_bit(DQF_ANY_DQUOT_DIRTY_B, &dqopt->info[cnt].dqi_flags);
+	spin_unlock(&dq_data_lock);
 	spin_lock(&dq_list_lock);
 	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
@@ -344,18 +372,15 @@
 		atomic_inc(&dquot->dq_count);
 		dqstats.lookups++;
 		spin_unlock(&dq_list_lock);
-		sb->dq_op->write_dquot(dquot);
+		sb->dq_op->write_dquot(dquot, 0);
 		dqput(dquot);
 		goto restart;
 	}
 	spin_unlock(&dq_list_lock);
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) {
-			down(&dqopt->dqio_sem);
-			dqopt->ops[cnt]->write_file_info(sb, cnt);
-			up(&dqopt->dqio_sem);
-		}
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt]))
+			sb->dq_op->write_info(sb, cnt);
 	spin_lock(&dq_list_lock);
 	dqstats.syncs++;
 	spin_unlock(&dq_list_lock);
@@ -430,9 +455,10 @@
 		spin_unlock(&dq_list_lock);
 		return;
 	}
+	/* This should never happen when we are journalling quota */
 	if (dquot_dirty(dquot)) {
 		spin_unlock(&dq_list_lock);
-		dquot->dq_sb->dq_op->write_dquot(dquot);
+		dquot->dq_sb->dq_op->write_dquot(dquot, 0);
 		goto we_slept;
 	}
 	atomic_dec(&dquot->dq_count);
@@ -539,12 +565,10 @@
 		struct file *filp = list_entry(p, struct file, f_list);
 		struct inode *inode = filp->f_dentry->d_inode;
 		if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
-			struct vfsmount *mnt = mntget(filp->f_vfsmnt);
 			struct dentry *dentry = dget(filp->f_dentry);
 			file_list_unlock();
 			sb->dq_op->initialize(inode, type);
 			dput(dentry);
-			mntput(mnt);
 			/* As we may have blocked we had better restart... */
 			goto restart;
 		}
@@ -612,13 +636,11 @@
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
 	dquot->dq_dqb.dqb_curinodes += number;
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
 {
 	dquot->dq_dqb.dqb_curspace += number;
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
@@ -630,7 +652,6 @@
 	if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
 		dquot->dq_dqb.dqb_itime = (time_t) 0;
 	clear_bit(DQ_INODES_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
@@ -642,7 +663,6 @@
 	if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
 		dquot->dq_dqb.dqb_btime = (time_t) 0;
 	clear_bit(DQ_BLKS_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 }
 
 static inline int need_print_warning(struct dquot *dquot)
@@ -799,17 +819,19 @@
  *
  * Note: this is a blocking operation.
  */
-void dquot_initialize(struct inode *inode, int type)
+int dquot_initialize(struct inode *inode, int type)
 {
 	unsigned int id = 0;
-	int cnt;
+	int cnt, ret = 0;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return 0;
 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	/* Having dqptr_sem we know NOQUOTA flags can't be altered... */
-	if (IS_NOQUOTA(inode)) {
-		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-		return;
-	}
+	if (IS_NOQUOTA(inode))
+		goto out_err;
 	/* Build list of quotas to initialize... */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (type != -1 && cnt != type)
@@ -824,18 +846,23 @@
 					break;
 			}
 			inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt);
-			if (inode->i_dquot[cnt])
+			if (inode->i_dquot[cnt]) {
 				inode->i_flags |= S_QUOTA;
+				/* Write dquot to allocate space in file if it's not allocated yet */
+				inode->i_sb->dq_op->write_dquot(inode->i_dquot[cnt], 1);
+			}
 		}
 	}
+out_err:
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return ret;
 }
 
 /*
  *	Remove references to quota from inode
  *	This function needs dqptr_sem for writing
  */
-static void dquot_drop_iupdate(struct inode *inode, struct dquot **to_drop)
+static int dquot_drop_iupdate(struct inode *inode, struct dquot **to_drop)
 {
 	int cnt;
 
@@ -844,22 +871,24 @@
 		to_drop[cnt] = inode->i_dquot[cnt];
 		inode->i_dquot[cnt] = NODQUOT;
 	}
+	return 0;
 }
 
 /*
  * 	Release all quotas referenced by inode
  */
-void dquot_drop(struct inode *inode)
+int dquot_drop(struct inode *inode)
 {
 	struct dquot *to_drop[MAXQUOTAS];
-	int cnt;
+	int cnt, ret;
 
 	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-	dquot_drop_iupdate(inode, to_drop);
+	ret = dquot_drop_iupdate(inode, to_drop);
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (to_drop[cnt] != NODQUOT)
 			dqput(to_drop[cnt]);
+	return ret;
 }
 
 /*
@@ -878,6 +907,15 @@
 }
 
 /*
+ * Following four functions update i_blocks+i_bytes fields and
+ * quota information (togethter with appropriate checks)
+ * NOTE: We absolutely rely on the fact that caller dirtifies
+ * the inode (usually macros in quotaops.h care about this) and
+ * holds a handle for the current transaction so that dquot write and
+ * inode write go into the same transaction.
+ */
+
+/*
  * This operation can block, but only after everything is updated
  */
 int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
@@ -885,13 +923,22 @@
 	int cnt, ret = NO_QUOTA;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode)) {
+out_add:
+		inode_add_bytes(inode, number);
+		return QUOTA_OK;
+	}
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = NOWARN;
 
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	if (IS_NOQUOTA(inode)) {	/* Now we can do reliable test... */
+		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+		goto out_add;
+	}
 	spin_lock(&dq_data_lock);
-	if (IS_NOQUOTA(inode))
-		goto add_bytes;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (inode->i_dquot[cnt] == NODQUOT)
 			continue;
@@ -903,11 +950,15 @@
 			continue;
 		dquot_incr_space(inode->i_dquot[cnt], number);
 	}
-add_bytes:
 	inode_add_bytes(inode, number);
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	if (ret == QUOTA_OK)
+		/* Dirtify all the dquots - this can block when journalling */
+		for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+			if (inode->i_dquot[cnt])
+				mark_dquot_dirty(inode->i_dquot[cnt]);
 	flush_warnings(inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	return ret;
@@ -921,6 +972,10 @@
 	int cnt, ret = NO_QUOTA;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		warntype[cnt] = NOWARN;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -944,6 +999,11 @@
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	if (ret == QUOTA_OK)
+		/* Dirtify all the dquots - this can block when journalling */
+		for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+			if (inode->i_dquot[cnt])
+				mark_dquot_dirty(inode->i_dquot[cnt]);
 	flush_warnings((struct dquot **)inode->i_dquot, warntype);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	return ret;
@@ -952,36 +1012,53 @@
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_space(struct inode *inode, qsize_t number)
+int dquot_free_space(struct inode *inode, qsize_t number)
 {
 	unsigned int cnt;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode)) {
+out_sub:
+		inode_sub_bytes(inode, number);
+		return QUOTA_OK;
+	}
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	if (IS_NOQUOTA(inode)) {
+		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+		goto out_sub;
+	}
 	spin_lock(&dq_data_lock);
-	if (IS_NOQUOTA(inode))
-		goto sub_bytes;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (inode->i_dquot[cnt] == NODQUOT)
 			continue;
 		dquot_decr_space(inode->i_dquot[cnt], number);
 	}
-sub_bytes:
 	inode_sub_bytes(inode, number);
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (inode->i_dquot[cnt])
+			mark_dquot_dirty(inode->i_dquot[cnt]);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return QUOTA_OK;
 }
 
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_inode(const struct inode *inode, unsigned long number)
+int dquot_free_inode(const struct inode *inode, unsigned long number)
 {
 	unsigned int cnt;
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	if (IS_NOQUOTA(inode)) {
 		up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-		return;
+		return QUOTA_OK;
 	}
 	spin_lock(&dq_data_lock);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -990,7 +1067,12 @@
 		dquot_decr_inodes(inode->i_dquot[cnt], number);
 	}
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (inode->i_dquot[cnt])
+			mark_dquot_dirty(inode->i_dquot[cnt]);
 	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return QUOTA_OK;
 }
 
 /*
@@ -1007,6 +1089,10 @@
 	    chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid;
 	char warntype[MAXQUOTAS];
 
+	/* First test before acquiring semaphore - solves deadlocks when we
+         * re-enter the quota code and are already holding the semaphore */
+	if (IS_NOQUOTA(inode))
+		return QUOTA_OK;
 	/* Clear the arrays */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		transfer_to[cnt] = transfer_from[cnt] = NODQUOT;
@@ -1065,6 +1151,13 @@
 	ret = QUOTA_OK;
 warn_put_all:
 	spin_unlock(&dq_data_lock);
+	/* Dirtify all the dquots - this can block when journalling */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (transfer_from[cnt])
+			mark_dquot_dirty(transfer_from[cnt]);
+		if (transfer_to[cnt])
+			mark_dquot_dirty(transfer_to[cnt]);
+	}
 	flush_warnings(transfer_to, warntype);
 	
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1078,25 +1171,35 @@
 }
 
 /*
+ * Write info of quota file to disk
+ */
+int dquot_commit_info(struct super_block *sb, int type)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(sb);
+
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[type]->write_file_info(sb, type);
+	up(&dqopt->dqio_sem);
+	return ret;
+}
+
+/*
  * Definitions of diskquota operations.
  */
 struct dquot_operations dquot_operations = {
-	.initialize	= dquot_initialize,		/* mandatory */
-	.drop		= dquot_drop,			/* mandatory */
+	.initialize	= dquot_initialize,
+	.drop		= dquot_drop,
 	.alloc_space	= dquot_alloc_space,
 	.alloc_inode	= dquot_alloc_inode,
 	.free_space	= dquot_free_space,
 	.free_inode	= dquot_free_inode,
 	.transfer	= dquot_transfer,
-	.write_dquot	= commit_dqblk
+	.write_dquot	= dquot_commit,
+	.mark_dirty	= dquot_mark_dquot_dirty,
+	.write_info	= dquot_commit_info
 };
 
-/* Function used by filesystems for initializing the dquot_operations structure */
-void init_dquot_operations(struct dquot_operations *fsdqops)
-{
-	memcpy(fsdqops, &dquot_operations, sizeof(dquot_operations));
-}
-
 static inline void set_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
@@ -1127,7 +1230,7 @@
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int vfs_quota_off(struct super_block *sb, int type)
+static int __vfs_quota_off(struct super_block *sb, int type, int onmount)
 {
 	int cnt;
 	struct quota_info *dqopt = sb_dqopt(sb);
@@ -1152,17 +1255,14 @@
 		 * Now all dquots should be invalidated, all writes done so we should be only
 		 * users of the info. No locks needed.
 		 */
-		if (info_dirty(&dqopt->info[cnt])) {
-			down(&dqopt->dqio_sem);
-			dqopt->ops[cnt]->write_file_info(sb, cnt);
-			up(&dqopt->dqio_sem);
-		}
+		if (info_dirty(&dqopt->info[cnt]))
+			sb->dq_op->write_info(sb, cnt);
 		if (dqopt->ops[cnt]->free_file_info)
 			dqopt->ops[cnt]->free_file_info(sb, cnt);
 		put_quota_format(dqopt->info[cnt].dqi_format);
 
 		fput(dqopt->files[cnt]);
-		dqopt->files[cnt] = (struct file *)NULL;
+		dqopt->files[cnt] = NULL;
 		dqopt->info[cnt].dqi_flags = 0;
 		dqopt->info[cnt].dqi_igrace = 0;
 		dqopt->info[cnt].dqi_bgrace = 0;
@@ -1174,32 +1274,39 @@
 	return 0;
 }
 
-int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+int vfs_quota_off(struct super_block *sb, int type)
 {
-	struct file *f;
+	return __vfs_quota_off(sb, type, 0);
+}
+
+int vfs_quota_off_mount(struct super_block *sb, int type)
+{
+	return __vfs_quota_off(sb, type, 1);
+}
+
+/*
+ *	Turn quotas on on a device
+ */
+
+/* Helper function when we already have file open */
+static int vfs_quota_on_file(struct file *f, int type, int format_id)
+{
+	struct quota_format_type *fmt = find_quota_format(format_id);
 	struct inode *inode;
+	struct super_block *sb = f->f_dentry->d_sb;
 	struct quota_info *dqopt = sb_dqopt(sb);
-	struct quota_format_type *fmt = find_quota_format(format_id);
 	int error;
 	unsigned int oldflags;
 
 	if (!fmt)
 		return -ESRCH;
-	f = filp_open(path, O_RDWR, 0600);
-	if (IS_ERR(f)) {
-		error = PTR_ERR(f);
-		goto out_fmt;
-	}
 	error = -EIO;
 	if (!f->f_op || !f->f_op->read || !f->f_op->write)
-		goto out_f;
-	error = security_quota_on(f);
-	if (error)
-		goto out_f;
+		goto out_fmt;
 	inode = f->f_dentry->d_inode;
 	error = -EACCES;
 	if (!S_ISREG(inode->i_mode))
-		goto out_f;
+		goto out_fmt;
 
 	down(&dqopt->dqonoff_sem);
 	down_write(&dqopt->dqptr_sem);
@@ -1238,14 +1345,57 @@
 out_lock:
 	up_write(&dqopt->dqptr_sem);
 	up(&dqopt->dqonoff_sem);
-out_f:
-	filp_close(f, NULL);
 out_fmt:
 	put_quota_format(fmt);
 
 	return error; 
 }
 
+/* Actual function called from quotactl() */
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+{
+	struct file *f;
+	int error;
+
+	f = filp_open(path, O_RDWR, 0600);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+	error = security_quota_on(f);
+	if (error)
+		goto out_f;
+	error = vfs_quota_on_file(f, type, format_id);
+	if (!error)
+		return 0;
+out_f:
+	filp_close(f, NULL);
+	return error;
+}
+
+/*
+ * Function used by filesystems when filp_open() would fail (filesystem is being mounted now)
+ * We will use a private file structure. Caller is responsible that it's IO functions won't
+ * need vfsmnt structure or some dentry tricks...
+ */
+int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry)
+{
+	struct file *f;
+	int error;
+
+	dget(dentry);	/* Get a reference for struct file */
+	f = dentry_open(dentry, NULL, O_RDWR);
+	if (IS_ERR(f)) {
+		error = PTR_ERR(f);
+		goto out_dentry;
+	}
+	error = vfs_quota_on_file(f, type, format_id);
+	if (!error)
+		return 0;
+	fput(f);
+out_dentry:
+	dput(dentry);
+	return error;
+}
+
 /* Generic routine for getting common part of quota structure */
 static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
 {
@@ -1329,8 +1479,8 @@
 		clear_bit(DQ_FAKE_B, &dquot->dq_flags);
 	else
 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
-	mark_dquot_dirty(dquot);
 	spin_unlock(&dq_data_lock);
+	mark_dquot_dirty(dquot);
 }
 
 int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
@@ -1387,9 +1537,11 @@
 		mi->dqi_igrace = ii->dqi_igrace;
 	if (ii->dqi_valid & IIF_FLAGS)
 		mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK);
-	mark_info_dirty(mi);
 	spin_unlock(&dq_data_lock);
 	up_read(&sb_dqopt(sb)->dqptr_sem);
+	mark_info_dirty(sb, type);
+	/* Force write to disk */
+	sb->dq_op->write_info(sb, type);
 	return 0;
 }
 
@@ -1520,4 +1672,3 @@
 EXPORT_SYMBOL(dqstats);
 EXPORT_SYMBOL(dq_list_lock);
 EXPORT_SYMBOL(dq_data_lock);
-EXPORT_SYMBOL(init_dquot_operations);
--- diff/fs/eventpoll.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/eventpoll.c	2004-02-18 09:04:01.000000000 +0000
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/hash.h>
 #include <linux/spinlock.h>
+#include <linux/syscalls.h>
 #include <linux/rwsem.h>
 #include <linux/wait.h>
 #include <linux/eventpoll.h>
@@ -1155,8 +1156,7 @@
 				if (waitqueue_active(&ep->poll_wait))
 					pwake++;
 			}
-		} else if (EP_IS_LINKED(&epi->rdllink))
-			EP_LIST_DEL(&epi->rdllink);
+		}
 	}
 
 	write_unlock_irqrestore(&ep->lock, flags);
--- diff/fs/exec.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/exec.c	2004-02-18 09:04:01.000000000 +0000
@@ -44,6 +44,7 @@
 #include <linux/ptrace.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 #include <linux/rmap-locking.h>
 
 #include <asm/uaccess.h>
@@ -326,7 +327,7 @@
 	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot))));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
 	pte_unmap(pte);
-	tsk->mm->rss++;
+	inc_rss(tsk->mm, page);
 	spin_unlock(&tsk->mm->page_table_lock);
 
 	/* no need for flush_tlb */
@@ -832,7 +833,8 @@
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL))
+	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+	    (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP))
 		current->mm->dumpable = 0;
 
 	/* An exec changes our domain. We are no longer part of the thread
@@ -1105,6 +1107,7 @@
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.interp = filename;
+	bprm.interp_flags = 0;
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
@@ -1386,7 +1389,7 @@
 		goto fail_unlock;
 
  	format_corename(corename, core_pattern, signr);
-	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
+	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600);
 	if (IS_ERR(file))
 		goto fail_unlock;
 	inode = file->f_dentry->d_inode;
--- diff/fs/ext2/acl.c	2003-10-27 09:20:38.000000000 +0000
+++ source/fs/ext2/acl.c	2004-02-18 09:04:01.000000000 +0000
@@ -322,7 +322,8 @@
 
 check_capabilities:
 	/* Allowed to override Discretionary Access Control? */
-	if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO))
+	if (!(mask & MAY_EXEC) ||
+	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
 		if (capable(CAP_DAC_OVERRIDE))
 			return 0;
 	/* Read and search granted if capable(CAP_DAC_READ_SEARCH) */
--- diff/fs/ext3/acl.c	2003-10-27 09:20:38.000000000 +0000
+++ source/fs/ext3/acl.c	2004-02-18 09:04:01.000000000 +0000
@@ -327,7 +327,8 @@
 
 check_capabilities:
 	/* Allowed to override Discretionary Access Control? */
-	if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO))
+	if (!(mask & MAY_EXEC) ||
+	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
 		if (capable(CAP_DAC_OVERRIDE))
 			return 0;
 	/* Read and search granted if capable(CAP_DAC_READ_SEARCH) */
--- diff/fs/ext3/inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext3/inode.c	2004-02-18 09:04:01.000000000 +0000
@@ -2772,9 +2772,25 @@
 
 	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
 		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+		handle_t *handle;
+
+		handle = ext3_journal_start(inode, 2*EXT3_QUOTA_TRANS_BLOCKS+3);
+		if (IS_ERR(handle)) {
+			error = PTR_ERR(handle);
+			goto err_out;
+		}
 		error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
-		if (error)
+		if (error) {
+			ext3_journal_stop(handle);
 			return error;
+		}
+		/* Update corresponding info in inode so that everything is in one transaction */
+		if (attr->ia_valid & ATTR_UID)
+			inode->i_uid = attr->ia_uid;
+		if (attr->ia_valid & ATTR_GID)
+			inode->i_gid = attr->ia_gid;
+		error = ext3_mark_inode_dirty(handle, inode);
+		ext3_journal_stop(handle);
 	}
 
 	if (S_ISREG(inode->i_mode) &&
@@ -2853,7 +2869,9 @@
 		ret = 2 * (bpp + indirects) + 2;
 
 #ifdef CONFIG_QUOTA
-	ret += 2 * EXT3_SINGLEDATA_TRANS_BLOCKS;
+	/* We know that structure was already allocated during DQUOT_INIT so
+	 * we will be updating only the data blocks + inodes */
+	ret += 2*EXT3_QUOTA_TRANS_BLOCKS;
 #endif
 
 	return ret;
--- diff/fs/ext3/namei.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/ext3/namei.c	2004-02-18 09:04:01.000000000 +0000
@@ -1974,6 +1974,8 @@
 	struct ext3_dir_entry_2 * de;
 	handle_t *handle;
 
+	/* Initialize quotas before so that eventual writes goes in separate transaction */
+	DQUOT_INIT(dentry->d_inode);
 	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
@@ -1987,7 +1989,6 @@
 		handle->h_sync = 1;
 
 	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
 
 	retval = -EIO;
 	if (le32_to_cpu(de->inode) != inode->i_ino)
@@ -2031,6 +2032,8 @@
 	struct ext3_dir_entry_2 * de;
 	handle_t *handle;
 
+	/* Initialize quotas before so that eventual writes goes in separate transaction */
+	DQUOT_INIT(dentry->d_inode);
 	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
@@ -2044,7 +2047,6 @@
 		goto end_unlink;
 
 	inode = dentry->d_inode;
-	DQUOT_INIT(inode);
 
 	retval = -EIO;
 	if (le32_to_cpu(de->inode) != inode->i_ino)
@@ -2172,6 +2174,9 @@
 
 	old_bh = new_bh = dir_bh = NULL;
 
+	/* Initialize quotas before so that eventual writes goes in separate transaction */
+	if (new_dentry->d_inode)
+		DQUOT_INIT(new_dentry->d_inode);
 	handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
 	if (IS_ERR(handle))
@@ -2198,8 +2203,6 @@
 		if (!new_inode) {
 			brelse (new_bh);
 			new_bh = NULL;
-		} else {
-			DQUOT_INIT(new_inode);
 		}
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
--- diff/fs/ext3/super.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/ext3/super.c	2004-02-18 09:04:01.000000000 +0000
@@ -32,6 +32,9 @@
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
 #include <linux/random.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/quotaops.h>
 #include <asm/uaccess.h>
 #include "xattr.h"
 #include "acl.h"
@@ -504,7 +507,41 @@
 # define ext3_clear_inode NULL
 #endif
 
-static struct dquot_operations ext3_qops;
+#ifdef CONFIG_QUOTA
+
+#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
+#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
+
+static int ext3_write_dquot(struct dquot *dquot, int init);
+static int ext3_mark_dquot_dirty(struct dquot *dquot);
+static int ext3_write_info(struct super_block *sb, int type);
+static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path);
+static int ext3_quota_on_mount(struct super_block *sb, int type);
+static int ext3_quota_off_mount(struct super_block *sb, int type);
+
+static struct dquot_operations ext3_quota_operations = {
+	.initialize	= dquot_initialize,
+	.drop		= dquot_drop,
+	.alloc_space	= dquot_alloc_space,
+	.alloc_inode	= dquot_alloc_inode,
+	.free_space	= dquot_free_space,
+	.free_inode	= dquot_free_inode,
+	.transfer	= dquot_transfer,
+	.write_dquot	= ext3_write_dquot,
+	.mark_dirty	= ext3_mark_dquot_dirty,
+	.write_info	= ext3_write_info
+};
+
+static struct quotactl_ops ext3_qctl_operations = {
+	.quota_on	= ext3_quota_on,
+	.quota_off	= vfs_quota_off,
+	.quota_sync	= vfs_quota_sync,
+	.get_info	= vfs_get_dqinfo,
+	.set_info	= vfs_set_dqinfo,
+	.get_dqblk	= vfs_get_dqblk,
+	.set_dqblk	= vfs_set_dqblk
+};
+#endif
 
 static struct super_operations ext3_sops = {
 	.alloc_inode	= ext3_alloc_inode,
@@ -536,6 +573,8 @@
 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
 	Opt_ignore, Opt_err,
 };
 
@@ -571,6 +610,12 @@
 	{Opt_data_journal, "data=journal"},
 	{Opt_data_ordered, "data=ordered"},
 	{Opt_data_writeback, "data=writeback"},
+	{Opt_offusrjquota, "usrjquota="},
+	{Opt_usrjquota, "usrjquota=%s"},
+	{Opt_offgrpjquota, "grpjquota="},
+	{Opt_grpjquota, "grpjquota=%s"},
+	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
+	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
 	{Opt_ignore, "grpquota"},
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
@@ -598,13 +643,17 @@
 	return sb_block;
 }
 
-static int parse_options (char * options, struct ext3_sb_info *sbi,
+static int parse_options (char * options, struct super_block *sb,
 			  unsigned long * inum, int is_remount)
 {
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	char * p;
 	substring_t args[MAX_OPT_ARGS];
 	int data_opt = 0;
 	int option;
+#ifdef CONFIG_QUOTA
+	int qtype;
+#endif
 
 	if (!options)
 		return 1;
@@ -759,6 +808,64 @@
 				sbi->s_mount_opt |= data_opt;
 			}
 			break;
+#ifdef CONFIG_QUOTA
+		case Opt_usrjquota:
+			qtype = USRQUOTA;
+			goto set_qf_name;
+		case Opt_grpjquota:
+			qtype = GRPQUOTA;
+set_qf_name:
+			if (sb_any_quota_enabled(sb)) {
+				printk(KERN_ERR "EXT3-fs: Cannot change journalled quota options when quota turned on.\n");
+				return 0;
+			}
+			if (sbi->s_qf_names[qtype]) {
+				printk(KERN_ERR "EXT3-fs: %s quota file already specified.\n", QTYPE2NAME(qtype));
+				return 0;
+			}
+			sbi->s_qf_names[qtype] = match_strdup(&args[0]);
+			if (!sbi->s_qf_names[qtype]) {
+				printk(KERN_ERR "EXT3-fs: not enough memory for storing quotafile name.\n");
+				return 0;
+			}
+			if (strchr(sbi->s_qf_names[qtype], '/')) {
+				printk(KERN_ERR "EXT3-fs: quotafile must be on filesystem root.\n");
+				kfree(sbi->s_qf_names[qtype]);
+				sbi->s_qf_names[qtype] = NULL;
+				return 0;
+			}
+			break;
+		case Opt_offusrjquota:
+			qtype = USRQUOTA;
+			goto clear_qf_name;
+		case Opt_offgrpjquota:
+			qtype = GRPQUOTA;
+clear_qf_name:
+			if (sb_any_quota_enabled(sb)) {
+				printk(KERN_ERR "EXT3-fs: Cannot change journalled quota options when quota turned on.\n");
+				return 0;
+			}
+			if (sbi->s_qf_names[qtype]) {
+				kfree(sbi->s_qf_names[qtype]);
+				sbi->s_qf_names[qtype] = NULL;
+			}
+			break;
+		case Opt_jqfmt_vfsold:
+			sbi->s_jquota_fmt = QFMT_VFS_OLD;
+			break;
+		case Opt_jqfmt_vfsv0:
+			sbi->s_jquota_fmt = QFMT_VFS_V0;
+			break;
+#else
+		case Opt_usrjquota:
+		case Opt_grpjquota:
+		case Opt_offusrjquota:
+		case Opt_offgrpjquota:
+		case Opt_jqfmt_vfsold:
+		case Opt_jqfmt_vfsv0:
+			printk (KERN_ERR "EXT3-fs: journalled quota options not supported.\n");
+			break;
+#endif
 		case Opt_abort:
 			set_opt(sbi->s_mount_opt, ABORT);
 			break;
@@ -771,6 +878,12 @@
 			return 0;
 		}
 	}
+#ifdef CONFIG_QUOTA
+	if (!sbi->s_jquota_fmt && (sbi->s_qf_names[0] || sbi->s_qf_names[1])) {
+		printk(KERN_ERR "EXT3-fs: journalled quota format not specified.\n");
+		return 0;
+	}
+#endif
 
 	return 1;
 }
@@ -929,7 +1042,12 @@
 				 struct ext3_super_block * es)
 {
 	unsigned int s_flags = sb->s_flags;
-	int nr_orphans = 0, nr_truncates = 0;
+	int nr_orphans = 0;
+	int nr_truncates = 0;
+#ifdef CONFIG_QUOTA
+	int i;
+#endif
+
 	if (!es->s_last_orphan) {
 		jbd_debug(4, "no orphan inodes to clean up\n");
 		return;
@@ -949,6 +1067,19 @@
 		       sb->s_id);
 		sb->s_flags &= ~MS_RDONLY;
 	}
+#ifdef CONFIG_QUOTA
+	sb->s_flags |= MS_ACTIVE;	/* Needed for iput() to work correctly
+					   and not trash data */
+	/* Turn on quotas so that they are updated correctly */
+	for (i = 0; i < MAXQUOTAS; i++) {
+		if (EXT3_SB(sb)->s_qf_names[i]) {
+			int ret = ext3_quota_on_mount(sb, i);
+			if (ret < 0)
+				printk(KERN_ERR "EXT3-fs: Cannot turn on "
+					"journalled quota: error %d\n", ret);
+		}
+	}
+#endif
 
 	while (es->s_last_orphan) {
 		struct inode *inode;
@@ -960,6 +1091,7 @@
 		}
 
 		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
+		DQUOT_INIT(inode);
 		if (inode->i_nlink) {
 			printk(KERN_DEBUG
 				"%s: truncating inode %ld to %Ld bytes\n",
@@ -987,6 +1119,13 @@
 	if (nr_truncates)
 		printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n",
 		       sb->s_id, PLURAL(nr_truncates));
+#ifdef CONFIG_QUOTA
+	/* Turn quotas off */
+	for (i = 0; i < MAXQUOTAS; i++) {
+		if (sb_dqopt(sb)->files[i])
+			ext3_quota_off_mount(sb, i);
+	}
+#endif
 	sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
 
@@ -1116,7 +1255,7 @@
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
-	if (!parse_options ((char *) data, sbi, &journal_inum, 0))
+	if (!parse_options ((char *) data, sb, &journal_inum, 0))
 		goto failed_mount;
 
 	sb->s_flags |= MS_ONE_SECOND;
@@ -1295,7 +1434,10 @@
 	 */
 	sb->s_op = &ext3_sops;
 	sb->s_export_op = &ext3_export_ops;
-	sb->dq_op = &ext3_qops;
+#ifdef CONFIG_QUOTA
+	sb->s_qcop = &ext3_qctl_operations;
+	sb->dq_op = &ext3_quota_operations;
+#endif
 	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
 
 	sb->s_root = 0;
@@ -1404,6 +1546,11 @@
 		brelse(sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
 failed_mount:
+#ifdef CONFIG_QUOTA
+	for (i = 0; i < MAXQUOTAS; i++)
+		if (sbi->s_qf_names[i])
+			kfree(sbi->s_qf_names[i]);
+#endif
 	ext3_blkdev_remove(sbi);
 	brelse(bh);
 out_fail:
@@ -1830,7 +1977,7 @@
 	/*
 	 * Allow the "check" option to be passed as a remount option.
 	 */
-	if (!parse_options(data, sbi, &tmp, 1))
+	if (!parse_options(data, sb, &tmp, 1))
 		return -EINVAL;
 
 	if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
@@ -1938,8 +2085,9 @@
 	return 0;
 }
 
-/* Helper function for writing quotas on sync - we need to start transaction before quota file
- * is locked for write. Otherwise the are possible deadlocks:
+/*
+ * Helper function for writing quotas on sync - we need to start transaction
+ * before quota file is locked for write. Otherwise the are possible deadlocks:
  * Process 1                         Process 2
  * ext3_create()                     quota_sync()
  *   journal_start()                   write_dquot()
@@ -1950,45 +2098,128 @@
 
 #ifdef CONFIG_QUOTA
 
-/* Blocks: (2 data blocks) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
-#define EXT3_OLD_QFMT_BLOCKS 11
-/* Blocks: quota info + (4 pointer blocks + 1 entry block) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
-#define EXT3_V0_QFMT_BLOCKS 27
+static inline int writes_to_blocks(int writes)
+{
+	return writes*5+2;
+}
 
-static int (*old_write_dquot)(struct dquot *dquot);
+static inline struct inode *dquot_to_inode(struct dquot *dquot)
+{
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]->f_dentry->d_inode;
+}
 
-static int ext3_write_dquot(struct dquot *dquot)
+static int ext3_write_dquot(struct dquot *dquot, int init)
 {
-	int nblocks;
-	int ret;
-	int err;
+	int ret, err;
 	handle_t *handle;
-	struct quota_info *dqops = sb_dqopt(dquot->dq_sb);
-	struct inode *qinode;
 
-	switch (dqops->info[dquot->dq_type].dqi_format->qf_fmt_id) {
-		case QFMT_VFS_OLD:
-			nblocks = EXT3_OLD_QFMT_BLOCKS;
-			break;
-		case QFMT_VFS_V0:
-			nblocks = EXT3_V0_QFMT_BLOCKS;
-			break;
-		default:
-			nblocks = EXT3_MAX_TRANS_DATA;
+	handle = ext3_journal_start(dquot_to_inode(dquot),
+		init ? EXT3_QUOTA_INIT_BLOCKS : EXT3_QUOTA_TRANS_BLOCKS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		goto out;
 	}
-	qinode = dqops->files[dquot->dq_type]->f_dentry->d_inode;
-	handle = ext3_journal_start(qinode, nblocks);
+	ret = dquot_commit(dquot, init);
+	err = ext3_journal_stop(handle);
+	if (!ret)
+		ret = err;
+out:
+	return ret;
+}
+
+static int ext3_mark_dquot_dirty(struct dquot * dquot)
+{
+	/* Are we journalling quotas? */
+	if (EXT3_SB(dquot->dq_sb)->s_qf_names[0] ||
+			EXT3_SB(dquot->dq_sb)->s_qf_names[1])
+		return ext3_write_dquot(dquot, 0);
+	else
+		return dquot_mark_dquot_dirty(dquot);
+}
+
+static int ext3_write_info(struct super_block *sb, int type)
+{
+	int ret, err;
+	handle_t *handle;
+
+	handle = ext3_journal_start(sb->s_root->d_inode, writes_to_blocks(1));
 	if (IS_ERR(handle)) {
 		ret = PTR_ERR(handle);
 		goto out;
 	}
-	ret = old_write_dquot(dquot);
+	ret = dquot_commit_info(sb, type);
 	err = ext3_journal_stop(handle);
-	if (ret == 0)
+	if (!ret)
 		ret = err;
 out:
 	return ret;
 }
+
+/*
+ * Turn on quotas during mount time - we need to find the quota file and such.
+ */
+static int ext3_quota_on_mount(struct super_block *sb, int type)
+{
+	int err;
+	struct dentry *dentry;
+	struct qstr name = { .name = EXT3_SB(sb)->s_qf_names[type],
+			     .hash = 0,
+			     .len = strlen(EXT3_SB(sb)->s_qf_names[type])};
+
+	dentry = lookup_hash(&name, sb->s_root);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+	err = vfs_quota_on_mount(type, EXT3_SB(sb)->s_jquota_fmt, dentry);
+	if (err)
+		dput(dentry);
+	/*
+	 * We keep the dentry reference if everything went ok - we drop it on
+	 * quota_off time
+	 */
+	return err;
+}
+
+/* Turn quotas off during mount time */
+static int ext3_quota_off_mount(struct super_block *sb, int type)
+{
+	int err;
+	struct dentry *dentry;
+
+	dentry = sb_dqopt(sb)->files[type]->f_dentry;
+	err = vfs_quota_off_mount(sb, type);
+
+	/* We invalidate dentry - it has at least wrong hash... */
+	d_invalidate(dentry);
+	dput(dentry);
+	return err;
+}
+
+static int
+ext3_quota_on(struct super_block *sb, int type, int format_id, char *path)
+{
+	int err;
+	struct nameidata nd;
+
+	if (!EXT3_SB(sb)->s_qf_names[0] && !EXT3_SB(sb)->s_qf_names[1]) {
+		/* Not journalling quota? */
+		return vfs_quota_on(sb, type, format_id, path);
+	}
+	err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+	if (err)
+		return err;
+	if (nd.mnt->mnt_sb != sb)	/* Quotafile not on the same fs? */
+		return -EXDEV;
+	if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
+		/* Quotafile not of fs root? */
+		printk(KERN_WARNING "EXT3-fs: Quota file not on filesystem "
+				"root. Journalled quota will not work\n");
+	if (!ext3_should_journal_data(nd.dentry->d_inode))
+		printk(KERN_WARNING "EXT3-fs: Quota file does not have "
+			"data-journalling. Journalled quota will not work\n");
+	path_release(&nd);
+	return vfs_quota_on(sb, type, format_id, path);
+}
+
 #endif
 
 static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
@@ -2013,11 +2244,6 @@
 	err = init_inodecache();
 	if (err)
 		goto out1;
-#ifdef CONFIG_QUOTA
-	init_dquot_operations(&ext3_qops);
-	old_write_dquot = ext3_qops.write_dquot;
-	ext3_qops.write_dquot = ext3_write_dquot;
-#endif
         err = register_filesystem(&ext3_fs_type);
 	if (err)
 		goto out;
--- diff/fs/hugetlbfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/hugetlbfs/inode.c	2004-02-18 09:04:01.000000000 +0000
@@ -194,6 +194,7 @@
 
 	hlist_del_init(&inode->i_hash);
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -236,6 +237,7 @@
 	hlist_del_init(&inode->i_hash);
 out_truncate:
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
--- diff/fs/inode.c	2003-10-27 09:20:38.000000000 +0000
+++ source/fs/inode.c	2004-02-18 09:04:01.000000000 +0000
@@ -183,6 +183,7 @@
 	INIT_LIST_HEAD(&inode->i_dentry);
 	INIT_LIST_HEAD(&inode->i_devices);
 	sema_init(&inode->i_sem, 1);
+	init_rwsem(&inode->i_alloc_sem);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
 	spin_lock_init(&inode->i_data.page_lock);
 	init_MUTEX(&inode->i_data.i_shared_sem);
@@ -193,6 +194,7 @@
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
 	spin_lock_init(&inode->i_lock);
 	i_size_ordered_init(inode);
+	init_rwsem(&inode->i_data.wb_rwsema);
 }
 
 EXPORT_SYMBOL(inode_init_once);
@@ -285,7 +287,7 @@
 /*
  * Invalidate all inodes for a device.
  */
-static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
+static int invalidate_list(struct list_head *head, struct list_head *dispose)
 {
 	struct list_head *next;
 	int busy = 0, count = 0;
@@ -298,13 +300,12 @@
 		next = next->next;
 		if (tmp == head)
 			break;
-		inode = list_entry(tmp, struct inode, i_list);
-		if (inode->i_sb != sb)
-			continue;
+		inode = list_entry(tmp, struct inode, i_sb_list);
 		invalidate_inode_buffers(inode);
 		if (!atomic_read(&inode->i_count)) {
 			hlist_del_init(&inode->i_hash);
 			list_del(&inode->i_list);
+			list_del(&inode->i_sb_list);
 			list_add(&inode->i_list, dispose);
 			inode->i_state |= I_FREEING;
 			count++;
@@ -340,10 +341,7 @@
 
 	down(&iprune_sem);
 	spin_lock(&inode_lock);
-	busy = invalidate_list(&inode_in_use, sb, &throw_away);
-	busy |= invalidate_list(&inode_unused, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_io, sb, &throw_away);
+	busy = invalidate_list(&sb->s_inodes, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
@@ -443,6 +441,7 @@
 				continue;
 		}
 		hlist_del_init(&inode->i_hash);
+		list_del_init(&inode->i_sb_list);
 		list_move(&inode->i_list, &freeable);
 		inode->i_state |= I_FREEING;
 		nr_pruned++;
@@ -553,6 +552,7 @@
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_sb_list, &sb->s_inodes);
 		inode->i_ino = ++last_ino;
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
@@ -601,6 +601,7 @@
 
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -649,6 +650,7 @@
 			inode->i_ino = ino;
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -984,6 +986,7 @@
 	struct super_operations *op = inode->i_sb->s_op;
 
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1031,6 +1034,7 @@
 		hlist_del_init(&inode->i_hash);
 	}
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1178,6 +1182,8 @@
 	struct timespec now;
 	int sync_it = 0;
 
+	if (IS_NOCMTIME(inode))
+		return;
 	if (IS_RDONLY(inode))
 		return;
 
@@ -1221,34 +1227,17 @@
 void remove_dquot_ref(struct super_block *sb, int type)
 {
 	struct inode *inode;
-	struct list_head *act_head;
 	LIST_HEAD(tofree_head);
 
 	if (!sb->dq_op)
 		return;	/* nothing to do */
 	spin_lock(&inode_lock);	/* This lock is for inodes code */
 	/* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */
- 
-	list_for_each(act_head, &inode_in_use) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &inode_unused) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &sb->s_dirty) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &sb->s_io) {
-		inode = list_entry(act_head, struct inode, i_list);
+
+	list_for_each_entry(inode, &sb->s_inodes, i_sb_list)
 		if (IS_QUOTAINIT(inode))
 			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
+
 	spin_unlock(&inode_lock);
 
 	put_dquot_list(&tofree_head);
@@ -1327,6 +1316,16 @@
 		wake_up_all(wq);
 }
 
+static __initdata unsigned long ihash_entries;
+static int __init set_ihash_entries(char *str)
+{
+	if (!str)
+		return 0;
+	ihash_entries = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("ihash_entries=", set_ihash_entries);
+
 /*
  * Initialize the waitqueues and inode hash table.
  */
@@ -1340,9 +1339,13 @@
 	for (i = 0; i < ARRAY_SIZE(i_wait_queue_heads); i++)
 		init_waitqueue_head(&i_wait_queue_heads[i].wqh);
 
-	mempages >>= (14 - PAGE_SHIFT);
-	mempages *= sizeof(struct hlist_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
+	if (!ihash_entries)
+		ihash_entries = PAGE_SHIFT < 14 ?
+				mempages >> (14 - PAGE_SHIFT) :
+				mempages << (PAGE_SHIFT - 14);
+
+	ihash_entries *= sizeof(struct hlist_head);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < ihash_entries; order++)
 		;
 
 	do {
--- diff/fs/jfs/acl.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/jfs/acl.c	2004-02-18 09:04:01.000000000 +0000
@@ -191,7 +191,8 @@
 	 * Read/write DACs are always overridable.
 	 * Executable DACs are overridable if at least one exec bit is set.
 	 */
-	if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO))
+	if (!(mask & MAY_EXEC) ||
+	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
 		if (capable(CAP_DAC_OVERRIDE))
 			return 0;
 
--- diff/fs/jfs/jfs_unicode.c	2003-07-11 09:39:50.000000000 +0100
+++ source/fs/jfs/jfs_unicode.c	2004-02-18 09:04:01.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2004
  *
  *   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
@@ -18,7 +18,7 @@
 
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include "jfs_types.h"
+#include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_unicode.h"
 #include "jfs_debug.h"
@@ -35,16 +35,22 @@
 	int i;
 	int outlen = 0;
 
-	for (i = 0; (i < len) && from[i]; i++) {
-		int charlen;
-		charlen =
-		    codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
-				       NLS_MAX_CHARSET_SIZE);
-		if (charlen > 0) {
-			outlen += charlen;
-		} else {
-			to[outlen++] = '?';
+	if (codepage) {
+		for (i = 0; (i < len) && from[i]; i++) {
+			int charlen;
+			charlen =
+			    codepage->uni2char(le16_to_cpu(from[i]),
+					       &to[outlen],
+					       NLS_MAX_CHARSET_SIZE);
+			if (charlen > 0)
+				outlen += charlen;
+			else
+				to[outlen++] = '?';
 		}
+	} else {
+		for (i = 0; (i < len) && from[i]; i++)
+			to[i] = (char) (le16_to_cpu(from[i]));
+		outlen = i;
 	}
 	to[outlen] = 0;
 	return outlen;
@@ -62,14 +68,22 @@
 	int charlen;
 	int i;
 
-	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
-		charlen = codepage->char2uni(from, len, &to[i]);
-		if (charlen < 1) {
-			jfs_err("jfs_strtoUCS: char2uni returned %d.", charlen);
-			jfs_err("charset = %s, char = 0x%x",
-				codepage->charset, (unsigned char) *from);
-			return charlen;
+	if (codepage) {
+		for (i = 0; len && *from; i++, from += charlen, len -= charlen)
+		{
+			charlen = codepage->char2uni(from, len, &to[i]);
+			if (charlen < 1) {
+				jfs_err("jfs_strtoUCS: char2uni returned %d.",
+					charlen);
+				jfs_err("charset = %s, char = 0x%x",
+					codepage->charset,
+					(unsigned char) *from);
+				return charlen;
+			}
 		}
+	} else {
+		for (i = 0; (i < len) && from[i]; i++)
+			to[i] = (wchar_t) from[i];
 	}
 
 	to[i] = 0;
@@ -82,9 +96,9 @@
  * FUNCTION:	Allocate and translate to unicode string
  *
  */
-int get_UCSname(struct component_name * uniName, struct dentry *dentry,
-		struct nls_table *nls_tab)
+int get_UCSname(struct component_name * uniName, struct dentry *dentry)
 {
+	struct nls_table *nls_tab = JFS_SBI(dentry->d_sb)->nls_tab;
 	int length = dentry->d_name.len;
 
 	if (length > JFS_NAME_MAX)
--- diff/fs/jfs/jfs_unicode.h	2002-10-16 04:27:08.000000000 +0100
+++ source/fs/jfs/jfs_unicode.h	2004-02-18 09:04:01.000000000 +0000
@@ -30,8 +30,7 @@
 
 extern signed char UniUpperTable[512];
 extern UNICASERANGE UniUpperRange[];
-extern int get_UCSname(struct component_name *, struct dentry *,
-		       struct nls_table *);
+extern int get_UCSname(struct component_name *, struct dentry *);
 extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
 
 #define free_UCSname(COMP) kfree((COMP)->name)
--- diff/fs/jfs/namei.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/jfs/namei.c	2004-02-18 09:04:01.000000000 +0000
@@ -78,7 +78,7 @@
 	 * search parent directory for entry/freespace
 	 * (dtSearch() returns parent directory page pinned)
 	 */
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out1;
 
 	/*
@@ -204,7 +204,7 @@
 	 * search parent directory for entry/freespace
 	 * (dtSearch() returns parent directory page pinned)
 	 */
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out1;
 
 	/*
@@ -332,7 +332,7 @@
 		goto out;
 	}
 
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) {
+	if ((rc = get_UCSname(&dname, dentry))) {
 		goto out;
 	}
 
@@ -451,7 +451,7 @@
 
 	jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
 
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out;
 
 	IWRITE_LOCK(ip);
@@ -786,7 +786,7 @@
 	/*
 	 * scan parent directory for entry/freespace
 	 */
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(ip->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out;
 
 	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
@@ -866,7 +866,7 @@
 	 * (dtSearch() returns parent directory page pinned)
 	 */
 
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out1;
 
 	/*
@@ -1069,12 +1069,10 @@
 	old_ip = old_dentry->d_inode;
 	new_ip = new_dentry->d_inode;
 
-	if ((rc = get_UCSname(&old_dname, old_dentry,
-			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&old_dname, old_dentry)))
 		goto out1;
 
-	if ((rc = get_UCSname(&new_dname, new_dentry,
-			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&new_dname, new_dentry)))
 		goto out2;
 
 	/*
@@ -1329,7 +1327,7 @@
 
 	jfs_info("jfs_mknod: %s", dentry->d_name.name);
 
-	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab)))
+	if ((rc = get_UCSname(&dname, dentry)))
 		goto out;
 
 	ip = ialloc(dir, mode);
@@ -1411,8 +1409,7 @@
 	else if (strcmp(name, "..") == 0)
 		inum = PARENT(dip);
 	else {
-		if ((rc =
-		     get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		if ((rc = get_UCSname(&key, dentry)))
 			return ERR_PTR(rc);
 		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
 		free_UCSname(&key);
--- diff/fs/jfs/super.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/jfs/super.c	2004-02-18 09:04:01.000000000 +0000
@@ -195,7 +195,8 @@
 	rc = jfs_umount(sb);
 	if (rc)
 		jfs_err("jfs_umount failed with return code %d", rc);
-	unload_nls(sbi->nls_tab);
+	if (sbi->nls_tab)
+		unload_nls(sbi->nls_tab);
 	sbi->nls_tab = NULL;
 
 	kfree(sbi);
@@ -435,9 +436,6 @@
 	if (!sb->s_root)
 		goto out_no_root;
 
-	if (!sbi->nls_tab)
-		sbi->nls_tab = load_nls_default();
-
 	/* logical blocks are represented by 40 bits in pxd_t, etc. */
 	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
 #if BITS_PER_LONG == 32
--- diff/fs/namei.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/namei.c	2004-02-18 09:04:01.000000000 +0000
@@ -190,7 +190,8 @@
 	 * Read/write DACs are always overridable.
 	 * Executable DACs are overridable if at least one exec bit is set.
 	 */
-	if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO))
+	if (!(mask & MAY_EXEC) ||
+	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
 		if (capable(CAP_DAC_OVERRIDE))
 			return 0;
 
--- diff/fs/namespace.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/namespace.c	2004-02-18 09:04:01.000000000 +0000
@@ -24,7 +24,15 @@
 #include <asm/uaccess.h>
 
 extern int __init init_rootfs(void);
+
+#ifdef CONFIG_SYSFS
 extern int __init sysfs_init(void);
+#else
+static inline int sysfs_init(void)
+{
+	return 0;
+}
+#endif
 
 /* spinlock for vfsmount related operations, inplace of dcache_lock */
 spinlock_t vfsmount_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
--- diff/fs/nfs/dir.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/dir.c	2004-02-18 09:04:02.000000000 +0000
@@ -139,11 +139,13 @@
 	struct file	*file = desc->file;
 	struct inode	*inode = file->f_dentry->d_inode;
 	struct rpc_cred	*cred = nfs_file_cred(file);
+	unsigned long	timestamp;
 	int		error;
 
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
+	timestamp = jiffies;
 	error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	if (error < 0) {
@@ -157,18 +159,21 @@
 		goto error;
 	}
 	SetPageUptodate(page);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 	/* Ensure consistent page alignment of the data.
 	 * Note: assumes we have exclusive access to this mapping either
 	 *	 throught inode->i_sem or some other mechanism.
 	 */
-	if (page->index == 0)
+	if (page->index == 0) {
 		invalidate_inode_pages(inode->i_mapping);
+		NFS_I(inode)->readdir_timestamp = timestamp;
+	}
 	unlock_page(page);
 	return 0;
  error:
 	SetPageError(page);
 	unlock_page(page);
-	invalidate_inode_pages(inode->i_mapping);
+	nfs_zap_caches(inode);
 	desc->error = error;
 	return -EIO;
 }
@@ -381,6 +386,7 @@
 						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 	desc->page = page;
 	desc->ptr = kmap(page);		/* matching kunmap in nfs_do_filldir */
 	if (desc->error >= 0) {
@@ -459,7 +465,15 @@
 			}
 			res = 0;
 			break;
-		} else if (res < 0)
+		}
+		if (res == -ETOOSMALL && desc->plus) {
+			NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+			nfs_zap_caches(inode);
+			desc->plus = 0;
+			desc->entry->eof = 0;
+			continue;
+		}
+		if (res < 0)
 			break;
 
 		res = nfs_do_filldir(desc, dirent, filldir);
@@ -481,14 +495,19 @@
  * In the case it has, we assume that the dentries are untrustworthy
  * and may need to be looked up again.
  */
-static inline
-int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
+static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
 	if (IS_ROOT(dentry))
 		return 1;
-	if (nfs_revalidate_inode(NFS_SERVER(dir), dir))
+	if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0
+			|| nfs_attribute_timeout(dir))
 		return 0;
-	return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir));
+	return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
+}
+
+static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
+{
+	dentry->d_fsdata = (void *)verf;
 }
 
 /*
@@ -528,9 +547,7 @@
 	/* Don't revalidate a negative dentry if we're creating a new file */
 	if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
 		return 0;
-	if (!nfs_check_verifier(dir, dentry))
-		return 1;
-	return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
+	return !nfs_check_verifier(dir, dentry);
 }
 
 /*
@@ -552,6 +569,7 @@
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
+	unsigned long verifier;
 	int isopen = 0;
 
 	parent = dget_parent(dentry);
@@ -574,6 +592,9 @@
 		goto out_bad;
 	}
 
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+
 	/* Force a full look up iff the parent directory has changed */
 	if (nfs_check_verifier(dir, dentry)) {
 		if (nfs_lookup_verify_inode(inode, isopen))
@@ -581,6 +602,12 @@
 		goto out_valid;
 	}
 
+	/*
+	 * Note: we're not holding inode->i_sem and so may be racing with
+	 * operations that change the directory. We therefore save the
+	 * change attribute *before* we do the RPC call.
+	 */
+	verifier = nfs_save_change_attribute(dir);
 	error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
 	if (!error) {
 		if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
@@ -603,6 +630,7 @@
 
  out_valid_renew:
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, verifier);
  out_valid:
 	unlock_kernel();
 	dput(parent);
@@ -693,6 +721,8 @@
 	dentry->d_op = NFS_PROTO(dir)->dentry_ops;
 
 	lock_kernel();
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
 
 	/* If we're doing an exclusive create, optimize away the lookup */
 	if (nfs_is_exclusive_create(dir, nd))
@@ -715,6 +745,7 @@
 	error = 0;
 	d_add(dentry, inode);
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out_unlock:
 	unlock_kernel();
 out:
@@ -768,7 +799,15 @@
 
 	/* Open the file on the server */
 	lock_kernel();
-	inode = nfs4_atomic_open(dir, dentry, nd);
+	/* Revalidate parent directory attribute cache */
+	nfs_revalidate_inode(NFS_SERVER(dir), dir);
+
+	if (nd->intent.open.flags & O_CREAT) {
+		nfs_begin_data_update(dir);
+		inode = nfs4_atomic_open(dir, dentry, nd);
+		nfs_end_data_update(dir);
+	} else
+		inode = nfs4_atomic_open(dir, dentry, nd);
 	unlock_kernel();
 	if (IS_ERR(inode)) {
 		error = PTR_ERR(inode);
@@ -790,6 +829,7 @@
 no_entry:
 	d_add(dentry, inode);
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out:
 	BUG_ON(error > 0);
 	return ERR_PTR(error);
@@ -801,13 +841,16 @@
 {
 	struct dentry *parent = NULL;
 	struct inode *inode = dentry->d_inode;
+	struct inode *dir;
+	unsigned long verifier;
 	int openflags, ret = 0;
 
 	/* NFS only supports OPEN for regular files */
 	if (inode && !S_ISREG(inode->i_mode))
 		goto no_open;
 	parent = dget_parent(dentry);
-	if (!is_atomic_open(parent->d_inode, nd))
+	dir = parent->d_inode;
+	if (!is_atomic_open(dir, nd))
 		goto no_open;
 	openflags = nd->intent.open.flags;
 	if (openflags & O_CREAT) {
@@ -821,8 +864,16 @@
 	/* We can't create new files, or truncate existing ones here */
 	openflags &= ~(O_CREAT|O_TRUNC);
 
+	/*
+	 * Note: we're not holding inode->i_sem and so may be racing with
+	 * operations that change the directory. We therefore save the
+	 * change attribute *before* we do the RPC call.
+	 */
 	lock_kernel();
-	ret = nfs4_open_revalidate(parent->d_inode, dentry, openflags);
+	verifier = nfs_save_change_attribute(dir);
+	ret = nfs4_open_revalidate(dir, dentry, openflags);
+	if (!ret)
+		nfs_set_verifier(dentry, verifier);
 	unlock_kernel();
 out:
 	dput(parent);
@@ -869,15 +920,20 @@
 	struct nfs_server *server;
 	struct nfs_entry entry;
 	struct page *page;
-	unsigned long timestamp = NFS_MTIME_UPDATE(dir);
+	unsigned long timestamp;
 	int res;
 
 	if (!NFS_USE_READDIRPLUS(dir))
 		return -ENOENT;
 	server = NFS_SERVER(dir);
-	if (server->flags & NFS_MOUNT_NOAC)
+	/* Don't use readdirplus unless the cache is stable */
+	if ((server->flags & NFS_MOUNT_NOAC) != 0
+			|| nfs_caches_unstable(dir)
+			|| nfs_attribute_timeout(dir))
 		return -ENOENT;
-	nfs_revalidate_inode(server, dir);
+	if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0)
+		return -ENOENT;
+	timestamp = NFS_I(dir)->readdir_timestamp;
 
 	entry.fh = fh;
 	entry.fattr = fattr;
@@ -931,9 +987,10 @@
 	if (inode) {
 		d_instantiate(dentry, inode);
 		nfs_renew_times(dentry);
-		error = 0;
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));
+		return 0;
 	}
-	return error;
+	error = -ENOMEM;
 out_err:
 	d_drop(dentry);
 	return error;
@@ -969,11 +1026,13 @@
 	 * does not pass the create flags.
 	 */
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);
+	nfs_end_data_update(dir);
 	if (!IS_ERR(inode)) {
 		d_instantiate(dentry, inode);
 		nfs_renew_times(dentry);
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 		error = 0;
 	} else {
 		error = PTR_ERR(inode);
@@ -1004,9 +1063,10 @@
 	attr.ia_valid = ATTR_MODE;
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
 					&fhandle, &fattr);
+	nfs_end_data_update(dir);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	else
@@ -1041,9 +1101,10 @@
 	 */
 	d_drop(dentry);
 #endif
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
 					&fattr);
+	nfs_end_data_update(dir);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	else
@@ -1060,10 +1121,12 @@
 		dir->i_ino, dentry->d_name.name);
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
-	if (!error)
+	/* Ensure the VFS deletes this inode */
+	if (error == 0 && dentry->d_inode != NULL)
 		dentry->d_inode->i_nlink = 0;
+	nfs_end_data_update(dir);
 	unlock_kernel();
 
 	return error;
@@ -1119,12 +1182,21 @@
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	nfs_zap_caches(dir);
 	qsilly.name = silly;
 	qsilly.len  = strlen(silly);
-	error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
+	nfs_begin_data_update(dir);
+	if (dentry->d_inode) {
+		nfs_begin_data_update(dentry->d_inode);
+		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
+				dir, &qsilly);
+		nfs_end_data_update(dentry->d_inode);
+	} else
+		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
+				dir, &qsilly);
+	nfs_end_data_update(dir);
 	if (!error) {
 		nfs_renew_times(dentry);
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 		d_move(dentry, sdentry);
 		error = nfs_async_unlink(dentry);
  		/* If we return 0 we don't unlink */
@@ -1156,14 +1228,17 @@
 		goto out;
 	}
 
-	nfs_zap_caches(dir);
-	if (inode)
-		NFS_CACHEINV(inode);
-	error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-	if (error < 0)
-		goto out;
-	if (inode)
-		inode->i_nlink--;
+	nfs_begin_data_update(dir);
+	if (inode != NULL) {
+		nfs_begin_data_update(inode);
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+		/* The VFS may want to delete this inode */
+		if (error == 0)
+			inode->i_nlink--;
+		nfs_end_data_update(inode);
+	} else
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+	nfs_end_data_update(dir);
 out:
 	return error;
 }
@@ -1198,9 +1273,10 @@
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dcache_lock);
 	error = nfs_safe_remove(dentry);
-	if (!error)
+	if (!error) {
 		nfs_renew_times(dentry);
-	else if (need_rehash)
+		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+	} else if (need_rehash)
 		d_rehash(dentry);
 	unlock_kernel();
 	return error;
@@ -1247,9 +1323,10 @@
 	qsymname.len  = strlen(symname);
 
 	lock_kernel();
-	nfs_zap_caches(dir);
+	nfs_begin_data_update(dir);
 	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
 					  &attr, &sym_fh, &sym_attr);
+	nfs_end_data_update(dir);
 	if (!error) {
 		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
 	} else {
@@ -1281,9 +1358,12 @@
 	 */
 	lock_kernel();
 	d_drop(dentry);
-	nfs_zap_caches(dir);
-	NFS_CACHEINV(inode);
+
+	nfs_begin_data_update(dir);
+	nfs_begin_data_update(inode);
 	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
+	nfs_end_data_update(inode);
+	nfs_end_data_update(dir);
 	unlock_kernel();
 	return error;
 }
@@ -1388,16 +1468,23 @@
 	if (new_inode)
 		d_delete(new_dentry);
 
-	nfs_zap_caches(new_dir);
-	nfs_zap_caches(old_dir);
+	nfs_begin_data_update(old_dir);
+	nfs_begin_data_update(new_dir);
+	nfs_begin_data_update(old_inode);
 	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
 					   new_dir, &new_dentry->d_name);
+	nfs_end_data_update(old_inode);
+	nfs_end_data_update(new_dir);
+	nfs_end_data_update(old_dir);
 out:
 	if (rehash)
 		d_rehash(rehash);
-	if (!error && !S_ISDIR(old_inode->i_mode))
-		d_move(old_dentry, new_dentry);
-	nfs_renew_times(new_dentry);
+	if (!error) {
+		if (!S_ISDIR(old_inode->i_mode))
+			d_move(old_dentry, new_dentry);
+		nfs_renew_times(new_dentry);
+		nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+	}
 
 	/* new dentry created? */
 	if (dentry)
@@ -1451,7 +1538,8 @@
 
 	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
 	if (cache->cred == cred
-	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) {
+	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
+	    && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) {
 		if (!(res = cache->err)) {
 			/* Is the mask a subset of an accepted mask? */
 			if ((cache->mask & mask) == mask)
--- diff/fs/nfs/direct.c	2003-10-27 09:20:39.000000000 +0000
+++ source/fs/nfs/direct.c	2004-02-18 09:04:02.000000000 +0000
@@ -269,6 +269,7 @@
 	if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
 		wdata.args.stable = NFS_FILE_SYNC;
 
+	nfs_begin_data_update(inode);
 retry:
 	need_commit = 0;
 	tot_bytes = 0;
@@ -334,6 +335,8 @@
 						VERF_SIZE) != 0)
 			goto sync_retry;
 	}
+	nfs_end_data_update(inode);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
 
 	return tot_bytes;
 
--- diff/fs/nfs/file.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/file.c	2004-02-18 09:04:02.000000000 +0000
@@ -104,11 +104,16 @@
 
 	dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
+	if ((file->f_mode & FMODE_WRITE) == 0)
+		return 0;
 	lock_kernel();
-	status = nfs_wb_file(inode, file);
+	/* Ensure that data+attribute caches are up to date after close() */
+	status = nfs_wb_all(inode);
 	if (!status) {
 		status = file->f_error;
 		file->f_error = 0;
+		if (!status)
+			__nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	}
 	unlock_kernel();
 	return status;
--- diff/fs/nfs/inode.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/inode.c	2004-02-18 09:04:02.000000000 +0000
@@ -53,8 +53,8 @@
  */
 #define NFS_MAX_READAHEAD	RPC_MAXREQS
 
-void nfs_zap_caches(struct inode *);
 static void nfs_invalidate_inode(struct inode *);
+static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long);
 
 static struct inode *nfs_alloc_inode(struct super_block *sb);
 static void nfs_destroy_inode(struct inode *);
@@ -151,6 +151,7 @@
 	cred = nfsi->cache_access.cred;
 	if (cred)
 		put_rpccred(cred);
+	BUG_ON(atomic_read(&nfsi->data_updates) != 0);
 }
 
 void
@@ -311,6 +312,8 @@
 	/* Get some general file system info */
         if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
 		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+		dput(sb->s_root);
+		root_inode = NULL;
 		goto out_no_root;
         }
 	if (server->namelen == 0 &&
@@ -627,13 +630,17 @@
 void
 nfs_zap_caches(struct inode *inode)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
+	int mode = inode->i_mode;
+
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
-	invalidate_remote_inode(inode);
-
 	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
-	NFS_CACHEINV(inode);
+	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
+		nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+	else
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
 }
 
 /*
@@ -673,9 +680,6 @@
 		return 0;
 	if (is_bad_inode(inode))
 		return 0;
-	/* Force an attribute cache update if inode->i_count == 0 */
-	if (!atomic_read(&inode->i_count))
-		NFS_CACHEINV(inode);
 	return 1;
 }
 
@@ -729,7 +733,7 @@
 		inode->i_ino = hash;
 
 		/* We can't support update_atime(), since the server will reset it */
-		inode->i_flags |= S_NOATIME;
+		inode->i_flags |= S_NOATIME|S_NOCMTIME;
 		inode->i_mode = fattr->mode;
 		/* Why so? Because we want revalidate for devices/FIFOs, and
 		 * that's precisely what we have in nfs_file_inode_operations.
@@ -754,10 +758,6 @@
 		inode->i_atime = fattr->atime;
 		inode->i_mtime = fattr->mtime;
 		inode->i_ctime = fattr->ctime;
-		nfsi->read_cache_ctime = fattr->ctime;
-		nfsi->read_cache_mtime = fattr->mtime;
-		nfsi->cache_mtime_jiffies = fattr->timestamp;
-		nfsi->read_cache_isize = fattr->size;
 		if (fattr->valid & NFS_ATTR_FATTR_V4)
 			nfsi->change_attr = fattr->change_attr;
 		inode->i_size = nfs_size_to_loff_t(fattr->size);
@@ -804,70 +804,50 @@
 	struct nfs_fattr fattr;
 	int error;
 
+	if (attr->ia_valid & ATTR_SIZE) {
+		if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
+			attr->ia_valid &= ~ATTR_SIZE;
+	}
+
 	/* Optimization: if the end result is no change, don't RPC */
 	attr->ia_valid &= NFS_VALID_ATTRS;
 	if (attr->ia_valid == 0)
 		return 0;
 
 	lock_kernel();
-
-	/*
-	 * Make sure the inode is up-to-date.
-	 */
-	error = nfs_revalidate_inode(NFS_SERVER(inode),inode);
-	if (error) {
-#ifdef NFS_PARANOIA
-printk("nfs_setattr: revalidate failed, error=%d\n", error);
-#endif
-		goto out;
+	nfs_begin_data_update(inode);
+	/* Write all dirty data if we're changing file permissions or size */
+	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
+		if (filemap_fdatawrite(inode->i_mapping) == 0)
+			filemap_fdatawait(inode->i_mapping);
+		nfs_wb_all(inode);
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
-		attr->ia_valid &= ~ATTR_SIZE;
-		if (attr->ia_valid == 0)
-			goto out;
-	} else {
-		filemap_fdatawrite(inode->i_mapping);
-		error = nfs_wb_all(inode);
-		filemap_fdatawait(inode->i_mapping);
-		if (error)
-			goto out;
-		/* Optimize away unnecessary truncates */
-		if ((attr->ia_valid & ATTR_SIZE) && i_size_read(inode) == attr->ia_size)
-			attr->ia_valid &= ~ATTR_SIZE;
-	}
-	if (!attr->ia_valid)
-		goto out;
-
 	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
-	if (error)
-		goto out;
-	/*
-	 * If we changed the size or mtime, update the inode
-	 * now to avoid invalidating the page cache.
-	 */
-	if (attr->ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != fattr.size)
-			printk("nfs_setattr: attr=%Ld, fattr=%Ld??\n",
-			       (long long) attr->ia_size, (long long)fattr.size);
-		vmtruncate(inode, attr->ia_size);
+	if (error == 0) {
+		nfs_refresh_inode(inode, &fattr);
+		if ((attr->ia_valid & ATTR_MODE) != 0) {
+			int mode;
+			mode = inode->i_mode & ~S_IALLUGO;
+			mode |= attr->ia_mode & S_IALLUGO;
+			inode->i_mode = mode;
+		}
+		if ((attr->ia_valid & ATTR_UID) != 0)
+			inode->i_uid = attr->ia_uid;
+		if ((attr->ia_valid & ATTR_GID) != 0)
+			inode->i_gid = attr->ia_gid;
+		if ((attr->ia_valid & ATTR_SIZE) != 0) {
+			inode->i_size = attr->ia_size;
+			vmtruncate(inode, attr->ia_size);
+		}
 	}
-
-	/*
-	 * If we changed the size or mtime, update the inode
-	 * now to avoid invalidating the page cache.
-	 */
-	if (!(fattr.valid & NFS_ATTR_WCC)) {
-		struct nfs_inode *nfsi = NFS_I(inode);
-		fattr.pre_size = nfsi->read_cache_isize;
-		fattr.pre_mtime = nfsi->read_cache_mtime;
-		fattr.pre_ctime = nfsi->read_cache_ctime;
-		fattr.valid |= NFS_ATTR_WCC;
-	}
-	/* Force an attribute cache update */
-	NFS_CACHEINV(inode);
-	error = nfs_refresh_inode(inode, &fattr);
-out:
+	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
+		struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
+		if (*cred) {
+			put_rpccred(*cred);
+			*cred = NULL;
+		}
+	}
+	nfs_end_data_update(inode);
 	unlock_kernel();
 	return error;
 }
@@ -895,7 +875,19 @@
 int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
 	struct inode *inode = dentry->d_inode;
-	int err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+	int need_atime = nfsi->flags & NFS_INO_INVALID_ATIME;
+	int err;
+
+	if (__IS_FLG(inode, MS_NOATIME))
+		need_atime = 0;
+	else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+		need_atime = 0;
+	/* We may force a getattr if the user cares about atime */
+	if (need_atime)
+		err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	else
+		err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!err)
 		generic_fillattr(inode, stat);
 	return err;
@@ -930,8 +922,10 @@
 	auth = NFS_CLIENT(inode)->cl_auth;
 	cred = rpcauth_lookupcred(auth, 0);
 	filp->private_data = cred;
-	if (filp->f_mode & FMODE_WRITE)
+	if ((filp->f_mode & FMODE_WRITE) != 0) {
 		nfs_set_mmcred(inode, cred);
+		nfs_begin_data_update(inode);
+	}
 	return 0;
 }
 
@@ -940,6 +934,8 @@
 	struct rpc_cred *cred;
 
 	lock_kernel();
+	if ((filp->f_mode & FMODE_WRITE) != 0)
+		nfs_end_data_update(inode);
 	cred = nfs_file_cred(filp);
 	if (cred)
 		put_rpccred(cred);
@@ -956,6 +952,9 @@
 {
 	int		 status = -ESTALE;
 	struct nfs_fattr fattr;
+	struct nfs_inode *nfsi = NFS_I(inode);
+	unsigned long verifier;
+	unsigned int flags;
 
 	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
 		inode->i_sb->s_id, (long long)NFS_FILEID(inode));
@@ -965,23 +964,16 @@
  		goto out_nowait;
 	if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
  		goto out_nowait;
-	if (NFS_FAKE_ROOT(inode)) {
-		dfprintk(VFS, "NFS: not revalidating fake root\n");
-		status = 0;
-		goto out_nowait;
-	}
 
 	while (NFS_REVALIDATING(inode)) {
 		status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
 		if (status < 0)
 			goto out_nowait;
-		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
-			status = NFS_STALE(inode) ? -ESTALE : 0;
-			goto out_nowait;
-		}
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
+	/* Protect against RPC races by saving the change attribute */
+	verifier = nfs_save_change_attribute(inode);
 	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -995,13 +987,34 @@
 		goto out;
 	}
 
-	status = nfs_refresh_inode(inode, &fattr);
+	status = nfs_update_inode(inode, &fattr, verifier);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
 			 inode->i_sb->s_id,
 			 (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
+	flags = nfsi->flags;
+	/*
+	 * We may need to keep the attributes marked as invalid if
+	 * we raced with nfs_end_attr_update().
+	 */
+	if (verifier == nfsi->cache_change_attribute)
+		nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
+	/* Do the page cache invalidation */
+	if (flags & NFS_INO_INVALID_DATA) {
+		if (S_ISREG(inode->i_mode)) {
+			if (filemap_fdatawrite(inode->i_mapping) == 0)
+				filemap_fdatawait(inode->i_mapping);
+			nfs_wb_all(inode);
+		}
+		nfsi->flags &= ~NFS_INO_INVALID_DATA;
+		invalidate_inode_pages2(inode->i_mapping);
+		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+		dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
+				inode->i_sb->s_id,
+				(long long)NFS_FILEID(inode));
+	}
 	dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode));
@@ -1009,41 +1022,104 @@
 	NFS_FLAGS(inode) &= ~NFS_INO_STALE;
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
-	wake_up(&NFS_I(inode)->nfs_i_wait);
+	wake_up(&nfsi->nfs_i_wait);
  out_nowait:
 	unlock_kernel();
 	return status;
 }
 
-/*
- * nfs_fattr_obsolete - Test if attribute data is newer than cached data
- * @inode: inode
- * @fattr: attributes to test
+/**
+ * nfs_begin_data_update
+ * @inode - pointer to inode
+ * Declare that a set of operations will update file data on the server
+ */
+void nfs_begin_data_update(struct inode *inode)
+{
+	atomic_inc(&NFS_I(inode)->data_updates);
+}
+
+/**
+ * nfs_end_data_update
+ * @inode - pointer to inode
+ * Declare end of the operations that will update file data
+ */
+void nfs_end_data_update(struct inode *inode)
+{
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	if (atomic_dec_and_test(&nfsi->data_updates)) {
+		nfsi->cache_change_attribute ++;
+		/* Mark the attribute cache for revalidation */
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
+		/* Directories and symlinks: invalidate page cache too */
+		if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+			nfsi->flags |= NFS_INO_INVALID_DATA;
+	}
+}
+
+/**
+ * nfs_refresh_inode - verify consistency of the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
  *
- * Avoid stuffing the attribute cache with obsolete information.
- * We always accept updates if the attribute cache timed out, or if
- * fattr->ctime is newer than our cached value.
- * If fattr->ctime matches the cached value, we still accept the update
- * if it increases the file size.
+ * Verifies the attribute cache. If we have just changed the attributes,
+ * so that fattr carries weak cache consistency data, then it may
+ * also update the ctime/mtime/change_attribute.
  */
-static inline
-int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	long cdif;
+	loff_t cur_size, new_isize;
+	int data_unstable;
+
+	/* Are we in the process of updating data on the server? */
+	data_unstable = nfs_caches_unstable(inode);
+
+	if (fattr->valid & NFS_ATTR_FATTR_V4) {
+		if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
+				&& nfsi->change_attr == fattr->pre_change_attr)
+			nfsi->change_attr = fattr->change_attr;
+		if (!data_unstable && nfsi->change_attr != fattr->change_attr)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+	}
+
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		return 0;
 
-	if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo))
-		goto out_valid;
-	cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec;
-	if (cdif == 0)
-		cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec;
-	if (cdif > 0)
-		goto out_valid;
-	/* Ugh... */
-	if (cdif == 0 && fattr->size > nfsi->read_cache_isize)
-		goto out_valid;
-	return -1;
- out_valid:
+	/* Has the inode gone and changed behind our back? */
+	if (nfsi->fileid != fattr->fileid
+			|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
+		return -EIO;
+
+	cur_size = i_size_read(inode);
+ 	new_isize = nfs_size_to_loff_t(fattr->size);
+
+	/* If we have atomic WCC data, we may update some attributes */
+	if ((fattr->valid & NFS_ATTR_WCC) != 0) {
+		if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
+			memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+		if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
+			memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+	}
+
+	/* Verify a few of the more important attributes */
+	if (!data_unstable) {
+		if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
+				|| cur_size != new_isize)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+	} else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
+			nfsi->flags |= NFS_INO_INVALID_ATTR;
+
+	/* Have any file permissions changed? */
+	if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
+			|| inode->i_uid != fattr->uid
+			|| inode->i_gid != fattr->gid)
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
+
+	if (!timespec_equal(&inode->i_atime, &fattr->atime))
+		nfsi->flags |= NFS_INO_INVALID_ATIME;
+
+	nfsi->read_cache_jiffies = fattr->timestamp;
 	return 0;
 }
 
@@ -1059,20 +1135,22 @@
  *
  * A very similar scenario holds for the dir cache.
  */
-int
-__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	__u64		new_size;
 	loff_t		new_isize;
-	int		invalid = 0;
-	int		mtime_update = 0;
+	unsigned int	invalid = 0;
 	loff_t		cur_isize;
+	int data_unstable;
 
-	dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n",
-			inode->i_sb->s_id, inode->i_ino,
+	dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
+			__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		return 0;
+
 	/* First successful call after mount, fill real data. */
 	if (NFS_FAKE_ROOT(inode)) {
 		dfprintk(VFS, "NFS: updating fake root\n");
@@ -1081,43 +1159,49 @@
 	}
 
 	if (nfsi->fileid != fattr->fileid) {
-		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+		printk(KERN_ERR "%s: inode number mismatch\n"
 		       "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
+		       __FUNCTION__,
 		       inode->i_sb->s_id, (long long)nfsi->fileid,
 		       inode->i_sb->s_id, (long long)fattr->fileid);
 		goto out_err;
 	}
 
-	/* Throw out obsolete READDIRPLUS attributes */
-	if (time_before(fattr->timestamp, NFS_READTIME(inode)))
-		return 0;
 	/*
 	 * Make sure the inode's type hasn't changed.
 	 */
 	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
 		goto out_changed;
 
-	new_size = fattr->size;
- 	new_isize = nfs_size_to_loff_t(fattr->size);
-
-	/* Avoid races */
-	if (nfs_fattr_obsolete(inode, fattr))
-		goto out_nochange;
-
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
 	nfsi->read_cache_jiffies = fattr->timestamp;
 
-	/*
-	 * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
-	 *       NOT inode->i_size!!!
-	 */
-	if (nfsi->read_cache_isize != new_size) {
+	/* Are we racing with known updates of the metadata on the server? */
+	data_unstable = ! nfs_verify_change_attribute(inode, verifier);
+
+	/* Check if the file size agrees */
+	new_size = fattr->size;
+ 	new_isize = nfs_size_to_loff_t(fattr->size);
+	cur_isize = i_size_read(inode);
+	if (cur_isize != new_size) {
 #ifdef NFS_DEBUG_VERBOSE
 		printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
+		/*
+		 * If we have pending writebacks, things can get
+		 * messy.
+		 */
+		if (S_ISREG(inode->i_mode) && data_unstable) {
+			if (new_isize > cur_isize) {
+				inode->i_size = new_isize;
+				invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+			}
+		} else {
+			inode->i_size = new_isize;
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+		}
 	}
 
 	/*
@@ -1125,12 +1209,13 @@
 	 *       can change this value in VFS without requiring a
 	 *	 cache revalidation.
 	 */
-	if (!timespec_equal(&nfsi->read_cache_mtime, &fattr->mtime)) {
+	if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
+		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
 #ifdef NFS_DEBUG_VERBOSE
 		printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
-		mtime_update = 1;
+		if (!data_unstable)
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
 	}
 
 	if ((fattr->valid & NFS_ATTR_FATTR_V4)
@@ -1139,47 +1224,15 @@
 		printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
 		       inode->i_sb->s_id, inode->i_ino);
 #endif
-		invalid = 1;
-	}
-
-	/* Check Weak Cache Consistency data.
-	 * If size and mtime match the pre-operation values, we can
-	 * assume that any attribute changes were caused by our NFS
-         * operation, so there's no need to invalidate the caches.
-         */
-	if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
-	    && nfsi->change_attr == fattr->pre_change_attr) {
-		invalid = 0;
-	}
-	else if ((fattr->valid & NFS_ATTR_WCC)
-	    && nfsi->read_cache_isize == fattr->pre_size
-	    && timespec_equal(&nfsi->read_cache_mtime, &fattr->pre_mtime)) {
-		invalid = 0;
-	}
-
-	/*
-	 * If we have pending writebacks, things can get
-	 * messy.
-	 */
-	cur_isize = i_size_read(inode);
-	if (nfs_have_writebacks(inode) && new_isize < cur_isize)
-		new_isize = cur_isize;
-
-	nfsi->read_cache_ctime = fattr->ctime;
-	inode->i_ctime = fattr->ctime;
-	inode->i_atime = fattr->atime;
-
-	if (mtime_update) {
-		if (invalid)
-			nfsi->cache_mtime_jiffies = fattr->timestamp;
-		nfsi->read_cache_mtime = fattr->mtime;
-		inode->i_mtime = fattr->mtime;
+		nfsi->change_attr = fattr->change_attr;
+		if (!data_unstable)
+			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
 	}
 
-	nfsi->read_cache_isize = new_size;
-	i_size_write(inode, new_isize);
+	memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+	memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
-	if (inode->i_mode != fattr->mode ||
+	if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
 	    inode->i_uid != fattr->uid ||
 	    inode->i_gid != fattr->gid) {
 		struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
@@ -1187,11 +1240,9 @@
 			put_rpccred(*cred);
 			*cred = NULL;
 		}
+		invalid |= NFS_INO_INVALID_ATTR;
 	}
 
-	if (fattr->valid & NFS_ATTR_FATTR_V4)
-		nfsi->change_attr = fattr->change_attr;
-
 	inode->i_mode = fattr->mode;
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
@@ -1207,31 +1258,30 @@
  		inode->i_blocks = fattr->du.nfs2.blocks;
  		inode->i_blksize = fattr->du.nfs2.blocksize;
  	}
- 
-	/* Update attrtimeo value */
-	if (invalid) {
+
+	/* Update attrtimeo value if we're out of the unstable period */
+	if (invalid & NFS_INO_INVALID_ATTR) {
 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
 		nfsi->attrtimeo_timestamp = jiffies;
-		invalidate_remote_inode(inode);
-		memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
 	} else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
 		if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
 			nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
 		nfsi->attrtimeo_timestamp = jiffies;
 	}
+	/* Don't invalidate the data if we were to blame */
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
+				|| S_ISLNK(inode->i_mode)))
+		invalid &= ~NFS_INO_INVALID_DATA;
+	nfsi->flags |= invalid;
 
 	return 0;
- out_nochange:
-	if (!timespec_equal(&fattr->atime, &inode->i_atime))
-		inode->i_atime = fattr->atime;
-	return 0;
  out_changed:
 	/*
 	 * Big trouble! The inode has become a different object.
 	 */
 #ifdef NFS_PARANOIA
-	printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-	       inode->i_ino, inode->i_mode, fattr->mode);
+	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
+			__FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
 #endif
 	/*
 	 * No need to worry about unhashing the dentry, as the
@@ -1718,6 +1768,7 @@
 		INIT_LIST_HEAD(&nfsi->dirty);
 		INIT_LIST_HEAD(&nfsi->commit);
 		INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
+		atomic_set(&nfsi->data_updates, 0);
 		nfsi->ndirty = 0;
 		nfsi->ncommit = 0;
 		nfsi->npages = 0;
--- diff/fs/nfs/nfs3proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs3proc.c	2004-02-18 09:04:02.000000000 +0000
@@ -68,20 +68,6 @@
 	return 1;
 }
 
-static void
-nfs3_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	if (fattr->valid & NFS_ATTR_FATTR) {
-		if (!(fattr->valid & NFS_ATTR_WCC)) {
-			fattr->pre_size  = NFS_CACHE_ISIZE(inode);
-			fattr->pre_mtime = NFS_CACHE_MTIME(inode);
-			fattr->pre_ctime = NFS_CACHE_CTIME(inode);
-			fattr->valid |= NFS_ATTR_WCC;
-		}
-		nfs_refresh_inode(inode, fattr);
-	}
-}
-
 static struct rpc_cred *
 nfs_cred(struct inode *inode, struct file *filp)
 {
@@ -280,7 +266,7 @@
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
 	if (status >= 0)
-		nfs3_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply write: %d\n", status);
 	return status < 0? status : wdata->res.count;
 }
@@ -303,7 +289,7 @@
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
 	if (status >= 0)
-		nfs3_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply commit: %d\n", status);
 	return status;
 }
@@ -777,12 +763,13 @@
 static void
 nfs3_write_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
@@ -835,12 +822,13 @@
 static void
 nfs3_commit_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_commit_done(task);
 }
 
--- diff/fs/nfs/nfs4proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/nfs4proc.c	2004-02-18 09:04:02.000000000 +0000
@@ -1088,12 +1088,8 @@
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, flags);
-	if (!status) {
+	if (!status)
 		renew_lease(server, timestamp);
-		/* Check cache consistency */
-		if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
-			nfs_zap_caches(inode);
-	}
 	dprintk("NFS reply read: %d\n", status);
 	return status;
 }
@@ -1130,7 +1126,6 @@
 
 	fattr->valid = 0;
 	status = rpc_call_sync(server->client, &msg, rpcflags);
-	NFS_CACHEINV(inode);
 	dprintk("NFS reply write: %d\n", status);
 	return status;
 }
@@ -1517,7 +1512,6 @@
 {
 	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode *inode = data->inode;
-	struct nfs_fattr *fattr = data->res.fattr;
 
 	if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
 		task->tk_action = nfs4_restart_read;
@@ -1525,11 +1519,6 @@
 	}
 	if (task->tk_status > 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	/* Check cache consistency */
-	if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_ACCESS)
-		inode->i_atime = fattr->atime;
 	/* Call back common NFS readpage processing */
 	nfs_readpage_result(task);
 }
@@ -1577,21 +1566,6 @@
 }
 
 static void
-nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	/* Check cache consistency */
-	if (fattr->pre_change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	NFS_CHANGE_ATTR(inode) = fattr->change_attr;
-	if (fattr->bitmap[1] & FATTR4_WORD1_SPACE_USED)
-		inode->i_blocks = (fattr->du.nfs3.used + 511) >> 9;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_METADATA)
-		inode->i_ctime = fattr->ctime;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_MODIFY)
-		inode->i_mtime = fattr->mtime;
-}
-
-static void
 nfs4_restart_write(struct rpc_task *task)
 {
 	struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
@@ -1617,7 +1591,6 @@
 	}
 	if (task->tk_status >= 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_writeback_done(task);
 }
@@ -1684,7 +1657,6 @@
 		task->tk_action = nfs4_restart_write;
 		return;
 	}
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_commit_done(task);
 }
@@ -1807,6 +1779,7 @@
 	if (filp->f_mode & FMODE_WRITE) {
 		lock_kernel();
 		nfs_set_mmcred(inode, state->owner->so_cred);
+		nfs_begin_data_update(inode);
 		unlock_kernel();
 	}
 	filp->private_data = state;
@@ -1823,6 +1796,11 @@
 
 	if (state)
 		nfs4_close_state(state, filp->f_mode);
+	if (filp->f_mode & FMODE_WRITE) {
+		lock_kernel();
+		nfs_end_data_update(inode);
+		unlock_kernel();
+	}
 	return 0;
 }
 
--- diff/fs/nfs/nfsroot.c	2003-08-26 10:00:54.000000000 +0100
+++ source/fs/nfs/nfsroot.c	2004-02-18 09:04:02.000000000 +0000
@@ -166,37 +166,6 @@
 
 
 /*
- *  Extract IP address from the parameter string if needed. Note that we
- *  need to have root_server_addr set _before_ IPConfig gets called as it
- *  can override it.
- */
-static void __init root_nfs_parse_addr(char *name)
-{
-	int octets = 0;
-	char *cp, *cq;
-
-	cp = cq = name;
-	while (octets < 4) {
-		while (*cp >= '0' && *cp <= '9')
-			cp++;
-		if (cp == cq || cp - cq > 3)
-			break;
-		if (*cp == '.' || octets == 3)
-			octets++;
-		if (octets < 4)
-			cp++;
-		cq = cp;
-	}
-	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
-		if (*cp == ':')
-			*cp++ = '\0';
-		root_server_addr = in_aton(name);
-		strcpy(name, cp);
-	}
-}
-
-
-/*
  *  Parse option string.
  */
 static void __init root_nfs_parse(char *name, char *buf)
@@ -345,7 +314,7 @@
 			line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
 		sprintf(nfs_root_name, NFS_ROOT, line);
 	}
-	root_nfs_parse_addr(nfs_root_name);
+	root_server_addr = root_nfs_parse_addr(nfs_root_name);
 	return 1;
 }
 
--- diff/fs/nfs/proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/nfs/proc.c	2004-02-18 09:04:02.000000000 +0000
@@ -49,18 +49,6 @@
 
 extern struct rpc_procinfo nfs_procedures[];
 
-static void
-nfs_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	if (!(fattr->valid & NFS_ATTR_WCC)) {
-		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
-		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
-		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
-		fattr->valid |= NFS_ATTR_WCC;
-	}
-	nfs_refresh_inode(inode, fattr);
-}
-
 static struct rpc_cred *
 nfs_cred(struct inode *inode, struct file *filp)
 {
@@ -205,7 +193,7 @@
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 	if (status >= 0) {
-		nfs_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 		wdata->res.count = wdata->args.count;
 		wdata->verf.committed = NFS_FILE_SYNC;
 	}
@@ -331,10 +319,8 @@
 {
 	struct rpc_message *msg = &task->tk_msg;
 	
-	if (msg->rpc_argp) {
-		NFS_CACHEINV(dir->d_inode);
+	if (msg->rpc_argp)
 		kfree(msg->rpc_argp);
-	}
 	return 0;
 }
 
@@ -584,7 +570,7 @@
 	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
 
 	if (task->tk_status >= 0)
-		nfs_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
--- diff/fs/nfs/read.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/nfs/read.c	2004-02-18 09:04:02.000000000 +0000
@@ -124,6 +124,7 @@
 		if (result < rdata.args.count)	/* NFSv2ism */
 			break;
 	} while (count);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 
 	if (count)
 		memclear_highpage_flush(page, rdata.args.pgbase, count);
@@ -266,6 +267,7 @@
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
+	NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
 		struct page *page = req->wb_page;
--- diff/fs/nfs/unlink.c	2003-06-30 10:07:24.000000000 +0100
+++ source/fs/nfs/unlink.c	2004-02-18 09:04:02.000000000 +0000
@@ -104,6 +104,7 @@
 	status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
 	if (status < 0)
 		goto out_err;
+	nfs_begin_data_update(dir->d_inode);
 	rpc_call_setup(task, &msg, 0);
 	return;
  out_err:
@@ -126,7 +127,7 @@
 	if (!dir)
 		return;
 	dir_i = dir->d_inode;
-	nfs_zap_caches(dir_i);
+	nfs_end_data_update(dir_i);
 	if (NFS_PROTO(dir_i)->unlink_done(dir, task))
 		return;
 	put_rpccred(data->cred);
--- diff/fs/nfs/write.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/nfs/write.c	2004-02-18 09:04:02.000000000 +0000
@@ -157,6 +157,7 @@
 		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
+	nfs_begin_data_update(inode);
 	do {
 		if (count < wsize && !swapfile)
 			wdata.args.count = count;
@@ -185,6 +186,7 @@
 		if (wdata.args.offset > i_size_read(inode))
 			i_size_write(inode, wdata.args.offset);
 	} while (count);
+	nfs_end_data_update(inode);
 
 	if (PageError(page))
 		ClearPageError(page);
@@ -204,6 +206,7 @@
 	loff_t		end;
 	int		status;
 
+	nfs_begin_data_update(inode);
 	req = nfs_update_request(file, inode, page, offset, count);
 	status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
 	if (status < 0)
@@ -213,6 +216,7 @@
 	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
 	if (i_size_read(inode) < end)
 		i_size_write(inode, end);
+	nfs_end_data_update(inode);
 
  out:
 	return status;
@@ -312,8 +316,10 @@
 	BUG_ON(error == -EEXIST);
 	if (error)
 		return error;
-	if (!nfsi->npages)
+	if (!nfsi->npages) {
 		igrab(inode);
+		nfs_begin_data_update(inode);
+	}
 	nfsi->npages++;
 	req->wb_count++;
 	return 0;
@@ -336,6 +342,7 @@
 	nfsi->npages--;
 	if (!nfsi->npages) {
 		spin_unlock(&nfs_wreq_lock);
+		nfs_end_data_update(inode);
 		iput(inode);
 	} else
 		spin_unlock(&nfs_wreq_lock);
@@ -696,6 +703,7 @@
 		return status;
 	}
 
+	nfs_begin_data_update(inode);
 	/*
 	 * Try to find an NFS request corresponding to this page
 	 * and update it.
@@ -729,6 +737,7 @@
 	} else
 		nfs_unlock_request(req);
 done:
+	nfs_end_data_update(inode);
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
 			status, (long long)i_size_read(inode));
 	if (status < 0)
@@ -891,10 +900,7 @@
 #endif
 
 	/*
-	 * Update attributes as result of writeback.
-	 * FIXME: There is an inherent race with invalidate_inode_pages and
-	 *	  writebacks since the page->count is kept > 1 for as long
-	 *	  as the page has a write request pending.
+	 * Process the nfs_page list
 	 */
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
--- diff/fs/nfsd/auth.c	2003-10-09 09:47:17.000000000 +0100
+++ source/fs/nfsd/auth.c	2004-02-18 09:04:01.000000000 +0000
@@ -11,11 +11,26 @@
 #include <linux/nfsd/nfsd.h>
 
 #define	CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
-void
-nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
+
+int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
 	struct svc_cred	*cred = &rqstp->rq_cred;
-	int		i;
+	struct group_info *group_info;
+	int ngroups;
+	int i;
+	int ret;
+
+	ngroups = 0;
+	if (!(exp->ex_flags & NFSEXP_ALLSQUASH)) {
+		for (i = 0; i < SVC_CRED_NGROUPS; i++) {
+			if (cred->cr_groups[i] == (gid_t)NOGROUP)
+				break;
+			ngroups++;
+		}
+	}
+	group_info = groups_alloc(ngroups);
+	if (group_info == NULL)
+		return -ENOMEM;
 
 	if (exp->ex_flags & NFSEXP_ALLSQUASH) {
 		cred->cr_uid = exp->ex_anon_uid;
@@ -26,7 +41,7 @@
 			cred->cr_uid = exp->ex_anon_uid;
 		if (!cred->cr_gid)
 			cred->cr_gid = exp->ex_anon_gid;
-		for (i = 0; i < NGROUPS; i++)
+		for (i = 0; i < SVC_CRED_NGROUPS; i++)
 			if (!cred->cr_groups[i])
 				cred->cr_groups[i] = exp->ex_anon_gid;
 	}
@@ -39,19 +54,24 @@
 		current->fsgid = cred->cr_gid;
 	else
 		current->fsgid = exp->ex_anon_gid;
-	for (i = 0; i < NGROUPS; i++) {
+
+	for (i = 0; i < SVC_CRED_NGROUPS; i++) {
 		gid_t group = cred->cr_groups[i];
 		if (group == (gid_t) NOGROUP)
 			break;
-		current->groups[i] = group;
+		GROUP_AT(group_info, i) = group;
 	}
-	current->ngroups = i;
 
-	if ((cred->cr_uid)) {
-		cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
-	} else {
-		cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
-						  current->cap_permitted);
+	ret = set_current_groups(group_info);
+	if (ret == 0) {
+		if ((cred->cr_uid)) {
+			cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
+		} else {
+			cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
+							current->cap_permitted);
+		}
 	}
+	put_group_info(group_info);
 
+	return ret;
 }
--- diff/fs/nfsd/export.c	2003-09-30 15:46:18.000000000 +0100
+++ source/fs/nfsd/export.c	2004-02-18 09:04:02.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/stat.h>
 #include <linux/in.h>
 #include <linux/seq_file.h>
+#include <linux/syscalls.h>
 #include <linux/rwsem.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
--- diff/fs/nfsd/nfs3proc.c	2003-02-26 16:01:09.000000000 +0000
+++ source/fs/nfsd/nfs3proc.c	2004-02-18 09:04:02.000000000 +0000
@@ -595,10 +595,10 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: COMMIT(3)   %s %d@%ld\n",
+	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
 				SVCFH_fmt(&argp->fh),
 				argp->count,
-				(unsigned long) argp->offset);
+				(unsigned long long) argp->offset);
 
 	if (argp->offset > NFS_OFFSET_MAX)
 		RETURN_STATUS(nfserr_inval);
--- diff/fs/nfsd/nfs4state.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/nfsd/nfs4state.c	2004-02-18 09:04:02.000000000 +0000
@@ -244,7 +244,7 @@
 
 	target->cr_uid = source->cr_uid;
 	target->cr_gid = source->cr_gid;
-	for(i = 0; i < NGROUPS; i++)
+	for(i = 0; i < SVC_CRED_NGROUPS; i++)
 		target->cr_groups[i] = source->cr_groups[i];
 }
 
--- diff/fs/nfsd/nfsctl.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/nfsd/nfsctl.c	2004-02-18 09:04:02.000000000 +0000
@@ -16,6 +16,7 @@
 #include <linux/fcntl.h>
 #include <linux/net.h>
 #include <linux/in.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
--- diff/fs/nfsd/stats.c	2002-11-11 11:09:30.000000000 +0000
+++ source/fs/nfsd/stats.c	2004-02-18 09:04:02.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/stat.h>
 #include <linux/module.h>
 
@@ -39,14 +40,11 @@
 	.program	= &nfsd_program,
 };
 
-static int
-nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
-				int *eof, void *data)
+static int nfsd_proc_show(struct seq_file *seq, void *v)
 {
-	int	len;
-	int	i;
+	int i;
 
-	len = sprintf(buffer, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
+	seq_printf(seq, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
 		      nfsdstats.rchits,
 		      nfsdstats.rcmisses,
 		      nfsdstats.rcnocache,
@@ -58,57 +56,42 @@
 		      nfsdstats.io_read,
 		      nfsdstats.io_write);
 	/* thread usage: */
-	len += sprintf(buffer+len, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
+	seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
 	for (i=0; i<10; i++) {
 		unsigned int jifs = nfsdstats.th_usage[i];
 		unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
-		len += sprintf(buffer+len, " %u.%03u", sec, msec);
+		seq_printf(seq, " %u.%03u", sec, msec);
 	}
 
 	/* newline and ra-cache */
-	len += sprintf(buffer+len, "\nra %u", nfsdstats.ra_size);
+	seq_printf(seq, "\nra %u", nfsdstats.ra_size);
 	for (i=0; i<11; i++)
-		len += sprintf(buffer+len, " %u", nfsdstats.ra_depth[i]);
-	len += sprintf(buffer+len, "\n");
+		seq_printf(seq, " %u", nfsdstats.ra_depth[i]);
+	seq_putc(seq, '\n');
 	
+	/* show my rpc info */
+	svc_seq_show(seq, &nfsd_svcstats);
 
-	/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
-	*eof = 0;
-
-	/*
-	 * Append generic nfsd RPC statistics if there's room for it.
-	 */
-	if (len <= offset) {
-		len = svc_proc_read(buffer, start, offset - len, count,
-				    eof, data);
-		return len;
-	}
-
-	if (len < count) {
-		len += svc_proc_read(buffer + len, start, 0, count - len,
-				     eof, data);
-	}
-
-	if (offset >= len) {
-		*start = buffer;
-		return 0;
-	}
+	return 0;
+}
 
-	*start = buffer + offset;
-	if ((len -= offset) > count)
-		return count;
-	return len;
+static int nfsd_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, nfsd_proc_show, NULL);
 }
 
+static struct file_operations nfsd_proc_fops = {
+	.owner = THIS_MODULE,
+	.open = nfsd_proc_open,
+	.read  = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 void
 nfsd_stat_init(void)
 {
-	struct proc_dir_entry	*ent;
-
-	if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
-		ent->read_proc = nfsd_proc_read;
-		ent->owner = THIS_MODULE;
-	}
+	svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
 }
 
 void
--- diff/fs/nfsd/vfs.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/nfsd/vfs.c	2004-02-18 09:04:02.000000000 +0000
@@ -823,7 +823,7 @@
  */
 int
 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               off_t offset, unsigned long count)
+               loff_t offset, unsigned long count)
 {
 	struct file	file;
 	int		err;
--- diff/fs/open.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/open.c	2004-02-18 09:04:02.000000000 +0000
@@ -192,7 +192,9 @@
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 	down(&dentry->d_inode->i_sem);
+	down_write(&dentry->d_inode->i_alloc_sem);
 	err = notify_change(dentry, &newattrs);
+	up_write(&dentry->d_inode->i_alloc_sem);
 	up(&dentry->d_inode->i_sem);
 	return err;
 }
--- diff/fs/proc/array.c	2003-10-27 09:20:39.000000000 +0000
+++ source/fs/proc/array.c	2004-02-18 09:04:02.000000000 +0000
@@ -176,8 +176,10 @@
 		p->files ? p->files->max_fds : 0);
 	task_unlock(p);
 
-	for (g = 0; g < p->ngroups; g++)
-		buffer += sprintf(buffer, "%d ", p->groups[g]);
+	get_group_info(p->group_info);
+	for (g = 0; g < min(p->group_info->ngroups,NGROUPS_SMALL); g++)
+		buffer += sprintf(buffer, "%d ", GROUP_AT(p->group_info,g));
+	put_group_info(p->group_info);
 
 	buffer += sprintf(buffer, "\n");
 	return buffer;
--- diff/fs/proc/base.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/proc/base.c	2004-02-18 09:04:02.000000000 +0000
@@ -1582,14 +1582,13 @@
 	read_unlock(&tasklist_lock);
 	if (!task)
 		goto out;
+	if (!thread_group_leader(task))
+		goto out_drop_task;
 
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
 
-
-	if (!inode) {
-		put_task_struct(task);
-		goto out;
-	}
+	if (!inode)
+		goto out_drop_task;
 	inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
 	inode->i_op = &proc_tgid_base_inode_operations;
 	inode->i_fop = &proc_tgid_base_operations;
@@ -1614,6 +1613,8 @@
 		goto out;
 	}
 	return NULL;
+out_drop_task:
+	put_task_struct(task);
 out:
 	return ERR_PTR(-ENOENT);
 }
@@ -1622,6 +1623,7 @@
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
 	struct task_struct *task;
+	struct task_struct *leader = proc_task(dir);
 	struct inode *inode;
 	unsigned tid;
 
@@ -1636,14 +1638,14 @@
 	read_unlock(&tasklist_lock);
 	if (!task)
 		goto out;
+	if (leader->tgid != task->tgid)
+		goto out_drop_task;
 
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
 
 
-	if (!inode) {
-		put_task_struct(task);
-		goto out;
-	}
+	if (!inode)
+		goto out_drop_task;
 	inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
 	inode->i_op = &proc_tid_base_inode_operations;
 	inode->i_fop = &proc_tid_base_operations;
@@ -1656,6 +1658,8 @@
 
 	put_task_struct(task);
 	return NULL;
+out_drop_task:
+	put_task_struct(task);
 out:
 	return ERR_PTR(-ENOENT);
 }
--- diff/fs/proc/proc_misc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/proc/proc_misc.c	2004-02-18 09:04:02.000000000 +0000
@@ -389,7 +389,7 @@
 		jiffies_to_clock_t(iowait),
 		jiffies_to_clock_t(irq),
 		jiffies_to_clock_t(softirq));
-	for_each_online_cpu(i) {
+	for_each_cpu(i) {
 		seq_printf(p, "cpu%d %u %u %u %u %u %u %u\n",
 			i,
 			jiffies_to_clock_t(kstat_cpu(i).cpustat.user),
@@ -424,7 +424,7 @@
 
 static int stat_open(struct inode *inode, struct file *file)
 {
-	unsigned size = 4096 * (1 + num_online_cpus() / 32);
+	unsigned size = 4096 * (1 + num_possible_cpus() / 32);
 	char *buf;
 	struct seq_file *m;
 	int res;
@@ -641,6 +641,36 @@
 		entry->proc_fops = f;
 }
 
+#ifdef CONFIG_LOCKMETER
+extern ssize_t get_lockmeter_info(char *, size_t, loff_t *);
+extern ssize_t put_lockmeter_info(const char *, size_t);
+extern int get_lockmeter_info_size(void);
+
+/*
+ * This function accesses lock metering information.
+ */
+static ssize_t read_lockmeter(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	return get_lockmeter_info(buf, count, ppos);
+}
+
+/*
+ * Writing to /proc/lockmeter resets the counters
+ */
+static ssize_t write_lockmeter(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
+{
+	return put_lockmeter_info(buf, count);
+}
+
+static struct file_operations proc_lockmeter_operations = {
+	NULL,           /* lseek */
+	read:		read_lockmeter,
+	write:		write_lockmeter,
+};
+#endif  /* CONFIG_LOCKMETER */
+
 void __init proc_misc_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -708,6 +738,13 @@
 	if (entry)
 		entry->proc_fops = &proc_sysrq_trigger_operations;
 #endif
+#ifdef CONFIG_LOCKMETER
+	entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL);
+	if (entry) {
+		entry->proc_fops = &proc_lockmeter_operations;
+		entry->size = get_lockmeter_info_size();
+	}
+#endif
 #ifdef CONFIG_PPC32
 	{
 		extern struct file_operations ppc_htab_operations;
--- diff/fs/proc/task_mmu.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/proc/task_mmu.c	2004-02-18 09:04:02.000000000 +0000
@@ -4,6 +4,22 @@
 #include <asm/elf.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_NUMA
+char *task_mem_pernode(struct mm_struct *mm, char *buffer)
+{
+	int nid;
+
+	for (nid = 0; nid < MAX_NUMNODES; nid++){
+		buffer += sprintf(buffer, "VmRSS-node_%d:\t%8lu kb\n",
+			nid, mm->pernode_rss[nid] << (PAGE_SHIFT-10));
+	}
+
+	return buffer;
+}
+#else /* !CONFIG_NUMA */
+#define task_mem_pernode(mm, buffer)	(buffer)
+#endif /* CONFIG_NUMA */
+
 char *task_mem(struct mm_struct *mm, char *buffer)
 {
 	unsigned long data = 0, stack = 0, exec = 0, lib = 0;
@@ -40,6 +56,7 @@
 		mm->rss << (PAGE_SHIFT-10),
 		data - stack, stack,
 		exec - lib, lib);
+	buffer = task_mem_pernode(mm, buffer);
 	up_read(&mm->mmap_sem);
 	return buffer;
 }
--- diff/fs/quota_v1.c	2003-10-09 09:47:34.000000000 +0100
+++ source/fs/quota_v1.c	2004-02-18 09:04:02.000000000 +0000
@@ -60,13 +60,13 @@
 	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
 	    dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0)
-		dquot->dq_flags |= DQ_FAKE;
+		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 	dqstats.reads++;
 
 	return 0;
 }
 
-static int v1_commit_dqblk(struct dquot *dquot)
+static int v1_commit_dqblk(struct dquot *dquot, int init)
 {
 	short type = dquot->dq_type;
 	struct file *filp;
@@ -80,12 +80,7 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	/*
-	 * Note: clear the DQ_MOD flag unconditionally,
-	 * so we don't loop forever on failure.
-	 */
 	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
-	dquot->dq_flags &= ~DQ_MOD;
 	if (dquot->dq_id == 0) {
 		dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
 		dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
--- diff/fs/quota_v2.c	2003-05-21 11:50:00.000000000 +0100
+++ source/fs/quota_v2.c	2004-02-18 09:04:02.000000000 +0000
@@ -65,7 +65,7 @@
 	set_fs(fs);
 	if (size != sizeof(struct v2_disk_dqinfo)) {
 		printk(KERN_WARNING "Can't read info structure on device %s.\n",
-			f->f_vfsmnt->mnt_sb->s_id);
+			f->f_dentry->d_sb->s_id);
 		return -1;
 	}
 	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
@@ -87,10 +87,12 @@
 	ssize_t size;
 	loff_t offset = V2_DQINFOOFF;
 
+	spin_lock(&dq_data_lock);
 	info->dqi_flags &= ~DQF_INFO_DIRTY;
 	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
 	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
 	dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+	spin_unlock(&dq_data_lock);
 	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
 	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
 	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
@@ -100,7 +102,7 @@
 	set_fs(fs);
 	if (size != sizeof(struct v2_disk_dqinfo)) {
 		printk(KERN_WARNING "Can't write info structure on device %s.\n",
-			f->f_vfsmnt->mnt_sb->s_id);
+			f->f_dentry->d_sb->s_id);
 		return -1;
 	}
 	return 0;
@@ -173,9 +175,10 @@
 }
 
 /* Remove empty block from list and return it */
-static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info)
+static int get_free_dqblk(struct file *filp, int type)
 {
 	dqbuf_t buf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int ret, blk;
 
@@ -193,7 +196,7 @@
 			goto out_buf;
 		blk = info->u.v2_i.dqi_blocks++;
 	}
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	ret = blk;
 out_buf:
 	freedqbuf(buf);
@@ -201,8 +204,9 @@
 }
 
 /* Insert empty block to the list */
-static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int put_free_dqblk(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int err;
 
@@ -210,16 +214,17 @@
 	dh->dqdh_prev_free = cpu_to_le32(0);
 	dh->dqdh_entries = cpu_to_le16(0);
 	info->u.v2_i.dqi_free_blk = blk;
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	if ((err = write_blk(filp, blk, buf)) < 0)	/* Some strange block. We had better leave it... */
 		return err;
 	return 0;
 }
 
 /* Remove given block from the list of blocks with free entries */
-static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int remove_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
 	dqbuf_t tmpbuf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
 	int err;
@@ -242,7 +247,7 @@
 	}
 	else {
 		info->u.v2_i.dqi_free_entry = nextblk;
-		mark_info_dirty(info);
+		mark_info_dirty(filp->f_dentry->d_sb, type);
 	}
 	freedqbuf(tmpbuf);
 	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
@@ -255,9 +260,10 @@
 }
 
 /* Insert given block to the beginning of list with free entries */
-static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int insert_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
 {
 	dqbuf_t tmpbuf = getdqbuf();
+	struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
 	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
 	int err;
 
@@ -276,7 +282,7 @@
 	}
 	freedqbuf(tmpbuf);
 	info->u.v2_i.dqi_free_entry = blk;
-	mark_info_dirty(info);
+	mark_info_dirty(filp->f_dentry->d_sb, type);
 	return 0;
 out_buf:
 	freedqbuf(tmpbuf);
@@ -307,7 +313,7 @@
 			goto out_buf;
 	}
 	else {
-		blk = get_free_dqblk(filp, info);
+		blk = get_free_dqblk(filp, dquot->dq_type);
 		if ((int)blk < 0) {
 			*err = blk;
 			freedqbuf(buf);
@@ -315,10 +321,10 @@
 		}
 		memset(buf, 0, V2_DQBLKSIZE);
 		info->u.v2_i.dqi_free_entry = blk;	/* This is enough as block is already zeroed and entry list is empty... */
-		mark_info_dirty(info);
+		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
 	}
 	if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)	/* Block will be full? */
-		if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
+		if ((*err = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
 			printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
 			goto out_buf;
 		}
@@ -349,7 +355,6 @@
 static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	dqbuf_t buf;
 	int ret = 0, newson = 0, newact = 0;
 	u32 *ref;
@@ -358,7 +363,7 @@
 	if (!(buf = getdqbuf()))
 		return -ENOMEM;
 	if (!*treeblk) {
-		ret = get_free_dqblk(filp, info);
+		ret = get_free_dqblk(filp, dquot->dq_type);
 		if (ret < 0)
 			goto out_buf;
 		*treeblk = ret;
@@ -392,7 +397,7 @@
 		ret = write_blk(filp, *treeblk, buf);
 	}
 	else if (newact && ret < 0)
-		put_free_dqblk(filp, info, buf, *treeblk);
+		put_free_dqblk(filp, dquot->dq_type, buf, *treeblk);
 out_buf:
 	freedqbuf(buf);
 	return ret;
@@ -417,6 +422,7 @@
 	ssize_t ret;
 	struct v2_disk_dqblk ddquot;
 
+	/* dq_off is guarded by dqio_sem */
 	if (!dquot->dq_off)
 		if ((ret = dq_insert_tree(dquot)) < 0) {
 			printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
@@ -424,7 +430,9 @@
 		}
 	filp = sb_dqopt(dquot->dq_sb)->files[type];
 	offset = dquot->dq_off;
+	spin_lock(&dq_data_lock);
 	mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+	spin_unlock(&dq_data_lock);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
@@ -445,7 +453,6 @@
 static int free_dqentry(struct dquot *dquot, uint blk)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	struct v2_disk_dqdbheader *dh;
 	dqbuf_t buf = getdqbuf();
 	int ret = 0;
@@ -463,8 +470,8 @@
 	dh = (struct v2_disk_dqdbheader *)buf;
 	dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
 	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
-		if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
-		    (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
+		if ((ret = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0 ||
+		    (ret = put_free_dqblk(filp, dquot->dq_type, buf, blk)) < 0) {
 			printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
 			goto out_buf;
 		}
@@ -473,7 +480,7 @@
 		memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
 		if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
 			/* Insert will write block itself */
-			if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
+			if ((ret = insert_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
 				printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
 				goto out_buf;
 			}
@@ -494,7 +501,6 @@
 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
 {
 	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
 	dqbuf_t buf = getdqbuf();
 	int ret = 0;
 	uint newblk;
@@ -518,7 +524,7 @@
 		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
 		for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);	/* Block got empty? */
 		if (i == V2_DQBLKSIZE) {
-			put_free_dqblk(filp, info, buf, *blk);
+			put_free_dqblk(filp, dquot->dq_type, buf, *blk);
 			*blk = 0;
 		}
 		else
@@ -632,7 +638,7 @@
 		if (offset < 0)
 			printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
 		dquot->dq_off = 0;
-		dquot->dq_flags |= DQ_FAKE;
+		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
 		ret = offset;
 	}
@@ -650,6 +656,9 @@
 			ret = 0;
 		set_fs(fs);
 		disk2memdqb(&dquot->dq_dqb, &ddquot);
+		if (!dquot->dq_dqb.dqb_bhardlimit && !dquot->dq_dqb.dqb_bsoftlimit && !dquot->dq_dqb.dqb_ihardlimit &&
+		    !dquot->dq_dqb.dqb_isoftlimit)
+			set_bit(DQ_FAKE_B, &dquot->dq_flags);
 	}
 	dqstats.reads++;
 
@@ -657,11 +666,14 @@
 }
 
 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */
-static int v2_commit_dquot(struct dquot *dquot)
+static int v2_commit_dquot(struct dquot *dquot, int init)
 {
-	/* We clear the flag everytime so we don't loop when there was an IO error... */
-	dquot->dq_flags &= ~DQ_MOD;
-	if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
+	int test;
+
+	spin_lock(&dq_data_lock);
+	test = !init && test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace);
+	spin_unlock(&dq_data_lock);
+	if (test)
 		return v2_delete_dquot(dquot);
 	else
 		return v2_write_dquot(dquot);
--- diff/fs/smbfs/file.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/smbfs/file.c	2004-02-18 09:04:02.000000000 +0000
@@ -257,6 +257,27 @@
 	return status;
 }
 
+static ssize_t
+smb_file_sendfile(struct file *file, loff_t *ppos,
+		  size_t count, read_actor_t actor, void __user *target)
+{
+	struct dentry *dentry = file->f_dentry;
+	ssize_t status;
+
+	VERBOSE("file %s/%s, pos=%Ld, count=%d\n",
+		DENTRY_PATH(dentry), *ppos, count);
+
+	status = smb_revalidate_inode(dentry);
+	if (status) {
+		PARANOIA("%s/%s validation failed, error=%d\n",
+			 DENTRY_PATH(dentry), status);
+		goto out;
+	}
+	status = generic_file_sendfile(file, ppos, count, actor, target);
+out:
+	return status;
+}
+
 /*
  * This does the "real" work of the write. The generic routine has
  * allocated the page, locked it, done all the page alignment stuff
@@ -388,6 +409,7 @@
 	.open		= smb_file_open,
 	.release	= smb_file_release,
 	.fsync		= smb_fsync,
+	.sendfile	= smb_file_sendfile,
 };
 
 struct inode_operations smb_file_inode_operations =
--- diff/fs/smbfs/proc.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/smbfs/proc.c	2004-02-18 09:04:02.000000000 +0000
@@ -1015,12 +1015,6 @@
 	p += 19;
 	p += 8;
 
-	/* FIXME: the request will fail if the 'tid' is changed. This
-	   should perhaps be set just before transmitting ... */
-	WSET(req->rq_header, smb_tid, server->opt.tid);
-	WSET(req->rq_header, smb_pid, 1);
-	WSET(req->rq_header, smb_uid, server->opt.server_uid);
-
 	if (server->opt.protocol > SMB_PROTOCOL_CORE) {
 		int flags = SMB_FLAGS_CASELESS_PATHNAMES;
 		int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS |
--- diff/fs/smbfs/request.c	2003-08-20 14:16:33.000000000 +0100
+++ source/fs/smbfs/request.c	2004-02-18 09:04:02.000000000 +0000
@@ -384,6 +384,12 @@
 	struct smb_sb_info *server = req->rq_server;
 	int result;
 
+	if (req->rq_bytes_sent == 0) {
+		WSET(req->rq_header, smb_tid, server->opt.tid);
+		WSET(req->rq_header, smb_pid, 1);
+		WSET(req->rq_header, smb_uid, server->opt.server_uid);
+	}
+
 	result = smb_send_request(req);
 	if (result < 0 && result != -EAGAIN)
 		goto out;
--- diff/fs/smbfs/smbiod.c	2003-09-30 15:46:19.000000000 +0100
+++ source/fs/smbfs/smbiod.c	2004-02-18 09:04:02.000000000 +0000
@@ -161,6 +161,9 @@
 	while (head != &server->xmitq) {
 		req = list_entry(head, struct smb_request, rq_queue);
 		head = head->next;
+
+		WSET(req->rq_header, smb_uid, -1);
+		req->rq_bytes_sent = 0;
 		if (req->rq_flags & SMB_REQ_NORETRY) {
 			VERBOSE("aborting request %p on xmitq\n", req);
 			req->rq_errno = -EIO;
--- diff/fs/stat.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/stat.c	2004-02-18 09:04:02.000000000 +0000
@@ -397,6 +397,7 @@
 
 void inode_set_bytes(struct inode *inode, loff_t bytes)
 {
+	/* Caller is here resposible for sufficient locking (ie. inode->i_lock) */
 	inode->i_blocks = bytes >> 9;
 	inode->i_bytes = bytes & 511;
 }
--- diff/fs/super.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/super.c	2004-02-18 09:04:02.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
@@ -33,6 +34,7 @@
 #include <linux/security.h>
 #include <linux/vfs.h>
 #include <linux/writeback.h>		/* for the emergency remount stuff */
+#include <linux/idr.h>
 #include <asm/uaccess.h>
 
 
@@ -66,6 +68,7 @@
 		INIT_LIST_HEAD(&s->s_files);
 		INIT_LIST_HEAD(&s->s_instances);
 		INIT_HLIST_HEAD(&s->s_anon);
+		INIT_LIST_HEAD(&s->s_inodes);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		down_write(&s->s_umount);
@@ -535,22 +538,26 @@
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-enum {Max_anon = 256};
-static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))];
+static struct idr unnamed_dev_idr;
 static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */
 
 int set_anon_super(struct super_block *s, void *data)
 {
 	int dev;
+
 	spin_lock(&unnamed_dev_lock);
-	dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
-	if (dev == Max_anon) {
+	if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0) {
 		spin_unlock(&unnamed_dev_lock);
-		return -EMFILE;
+		return -ENOMEM;
 	}
-	set_bit(dev, unnamed_dev_in_use);
+	dev = idr_get_new(&unnamed_dev_idr, NULL);
 	spin_unlock(&unnamed_dev_lock);
-	s->s_dev = MKDEV(0, dev);
+
+	if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
+		idr_remove(&unnamed_dev_idr, dev);
+		return -EMFILE;
+	}
+	s->s_dev = MKDEV(0, dev & MINORMASK);
 	return 0;
 }
 
@@ -559,14 +566,20 @@
 void kill_anon_super(struct super_block *sb)
 {
 	int slot = MINOR(sb->s_dev);
+
 	generic_shutdown_super(sb);
 	spin_lock(&unnamed_dev_lock);
-	clear_bit(slot, unnamed_dev_in_use);
+	idr_remove(&unnamed_dev_idr, slot);
 	spin_unlock(&unnamed_dev_lock);
 }
 
 EXPORT_SYMBOL(kill_anon_super);
 
+void __init unnamed_dev_init(void)
+{
+	idr_init(&unnamed_dev_idr);
+}
+
 void kill_litter_super(struct super_block *sb)
 {
 	if (sb->s_root)
--- diff/fs/sysfs/dir.c	2004-01-19 10:22:59.000000000 +0000
+++ source/fs/sysfs/dir.c	2004-02-18 09:04:02.000000000 +0000
@@ -96,6 +96,8 @@
 void sysfs_remove_subdir(struct dentry * d)
 {
 	remove_dir(d);
+	/* release the "extra" ref taken during sysfs_create() */
+	dput(d);
 }
 
 
@@ -120,13 +122,14 @@
 	down(&dentry->d_inode->i_sem);
 
 	spin_lock(&dcache_lock);
+restart:
 	node = dentry->d_subdirs.next;
 	while (node != &dentry->d_subdirs) {
 		struct dentry * d = list_entry(node,struct dentry,d_child);
-		list_del_init(node);
 
+		node = node->next;
 		pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count));
-		if (d->d_inode) {
+		if (!d_unhashed(d) && (d->d_inode)) {
 			d = dget_locked(d);
 			pr_debug("removing");
 
@@ -137,12 +140,12 @@
 			d_delete(d);
 			simple_unlink(dentry->d_inode,d);
 			dput(d);
+			pr_debug(" done\n");
 			spin_lock(&dcache_lock);
+			/* re-acquired dcache_lock, need to restart */
+			goto restart;
 		}
-		pr_debug(" done\n");
-		node = dentry->d_subdirs.next;
 	}
-	list_del_init(&dentry->d_child);
 	spin_unlock(&dcache_lock);
 	up(&dentry->d_inode->i_sem);
 
--- diff/fs/sysfs/group.c	2003-09-30 15:46:19.000000000 +0100
+++ source/fs/sysfs/group.c	2004-02-18 09:04:02.000000000 +0000
@@ -68,12 +68,13 @@
 	if (grp->name)
 		dir = sysfs_get_dentry(kobj->dentry,grp->name);
 	else
-		dir = kobj->dentry;
+		dir = dget(kobj->dentry);
 
 	remove_files(dir,grp);
-	dput(dir);
 	if (grp->name)
 		sysfs_remove_subdir(dir);
+	/* release the ref. taken in this routine */
+	dput(dir);
 }
 
 
--- diff/fs/xfs/linux/xfs_aops.c	2004-02-18 08:54:12.000000000 +0000
+++ source/fs/xfs/linux/xfs_aops.c	2004-02-18 09:04:02.000000000 +0000
@@ -988,7 +988,8 @@
 	if (error)
 		return -error;
 
-	return blockdev_direct_IO(rw, iocb, inode, iomap.iomap_target->pbr_bdev,
+	return blockdev_direct_IO_no_locking(rw, iocb, inode,
+		iomap.iomap_target->pbr_bdev,
 		iov, offset, nr_segs,
 		linvfs_get_blocks_direct,
 		linvfs_unwritten_convert_direct);
--- diff/fs/xfs/xfs_inode.c	2004-02-09 10:36:12.000000000 +0000
+++ source/fs/xfs/xfs_inode.c	2004-02-18 09:04:02.000000000 +0000
@@ -3707,7 +3707,8 @@
 	 * Read/write DACs are always overridable.
 	 * Executable DACs are overridable if at least one exec bit is set.
 	 */
-	if ((orgmode & (S_IRUSR|S_IWUSR)) || (inode->i_mode & S_IXUGO))
+	if (!(orgmode & S_IXUSR) || (inode->i_mode & S_IXUGO) ||
+	    (ip->i_d.di_mode & S_IFMT) == S_IFDIR)
 		if (capable_cred(cr, CAP_DAC_OVERRIDE))
 			return 0;
 
--- diff/include/acpi/acconfig.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/acpi/acconfig.h	2004-02-18 09:04:02.000000000 +0000
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20040116
+#define ACPI_CA_VERSION                 0x20040211
 
 /* Maximum objects in the various object caches */
 
--- diff/include/asm-alpha/param.h	2002-10-16 04:27:55.000000000 +0100
+++ source/include/asm-alpha/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -19,10 +19,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-alpha/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-alpha/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -6,6 +6,10 @@
 #include <linux/kernel.h>
 #include <asm/current.h>
 
+#ifdef CONFIG_LOCKMETER
+#undef DEBUG_SPINLOCK
+#undef DEBUG_RWLOCK
+#endif
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -95,9 +99,18 @@
 
 typedef struct {
 	volatile int write_lock:1, read_counter:31;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* need this storage for CPU and lock INDEX ............. */
+	unsigned magic;
+#endif
 } /*__attribute__((aligned(32)))*/ rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *)(x) != 0)
@@ -169,4 +182,41 @@
 	: "m" (*lock) : "memory");
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+	long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	bne %1,1f\n"
+	"	or $31,1,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+
+	return (result);
+}
+
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+	unsigned long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	blbs %1,1f\n"
+	"	subl %1,2,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+	return (result);
+}
+#endif /* CONFIG_LOCKMETER */
+
 #endif /* _ALPHA_SPINLOCK_H */
--- diff/include/asm-alpha/unistd.h	2003-07-22 18:54:27.000000000 +0100
+++ source/include/asm-alpha/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -548,15 +548,14 @@
 
 #include <linux/string.h>
 #include <linux/signal.h>
+#include <linux/syscalls.h>
 #include <asm/ptrace.h>
 
-extern long sys_open(const char *, int, int);
 static inline long open(const char * name, int mode, int flags)
 {
 	return sys_open(name, mode, flags);
 }
 
-extern long sys_dup(int);
 static inline long dup(int fd)
 {
 	return sys_dup(fd);
@@ -564,17 +563,14 @@
 
 static inline long close(int fd)
 {
-	extern long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
-extern off_t sys_lseek(int, off_t, int);
 static inline off_t lseek(int fd, off_t off, int whence)
 {
 	return sys_lseek(fd, off, whence);
 }
 
-extern long sys_exit(int);
 static inline long _exit(int value)
 {
 	return sys_exit(value);
@@ -582,13 +578,11 @@
 
 #define exit(x) _exit(x)
 
-extern long sys_write(int, const char *, size_t);
 static inline long write(int fd, const char * buf, size_t nr)
 {
 	return sys_write(fd, buf, nr);
 }
 
-extern long sys_read(int, char *, size_t);
 static inline long read(int fd, char * buf, size_t nr)
 {
 	return sys_read(fd, buf, nr);
@@ -596,19 +590,20 @@
 
 extern long execve(char *, char **, char **);
 
-extern long sys_setsid(void);
 static inline long setsid(void)
 {
 	return sys_setsid();
 }
 
-struct rusage;
-extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
 static inline pid_t waitpid(int pid, int * wait_stat, int flags)
 {
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
+asmlinkage int sys_execve(char *ufilename, char **argv, char **envp,
+			unsigned long a3, unsigned long a4, unsigned long a5,
+			struct pt_regs regs);
+
 #endif /* __KERNEL_SYSCALLS__ */
 
 /*
--- diff/include/asm-arm/param.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/asm-arm/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -26,10 +26,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
--- diff/include/asm-arm/tlb.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/asm-arm/tlb.h	2004-02-18 09:04:02.000000000 +0000
@@ -70,6 +70,12 @@
 	check_pgt_cache();
 }
 
+static inline unsigned int
+tlb_is_full_mm(struct mmu_gather *tlb)
+{
+     return tlb->fullmm;
+}
+
 #define tlb_remove_tlb_entry(tlb,ptep,address)	do { } while (0)
 
 #define tlb_start_vma(tlb,vma)						\
--- diff/include/asm-arm/unistd.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-arm/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -450,54 +450,45 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
-struct rusage;
-asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
+#include <linux/syscalls.h>
 
 static inline pid_t setsid(void)
 {
-	extern long sys_setsid(void);
 	return sys_setsid();
 }
 
 static inline long write(int fd, const char *buf, off_t count)
 {
-	extern long sys_write(int, const char *, int);
 	return sys_write(fd, buf, count);
 }
 
 static inline long read(int fd, char *buf, off_t count)
 {
-	extern long sys_read(int, char *, int);
 	return sys_read(fd, buf, count);
 }
 
 static inline off_t lseek(int fd, off_t offset, int count)
 {
-	extern off_t sys_lseek(int, off_t, int);
 	return sys_lseek(fd, offset, count);
 }
 
 static inline long dup(int fd)
 {
-	extern long sys_dup(int);
 	return sys_dup(fd);
 }
 
 static inline long open(const char *file, int flag, int mode)
 {
-	extern long sys_open(const char *, int, int);
 	return sys_open(file, flag, mode);
 }
 
 static inline long close(int fd)
 {
-	extern long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
 static inline long _exit(int exitcode)
 {
-	extern long sys_exit(int) __attribute__((noreturn));
 	return sys_exit(exitcode);
 }
 
@@ -506,6 +497,16 @@
 	return sys_wait4((int)pid, wait_stat, options, NULL);
 }
 
+struct pt_regs;
+asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
+			struct pt_regs *regs);
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+			struct pt_regs *regs);
+asmlinkage int sys_fork(struct pt_regs *regs);
+asmlinkage int sys_vfork(struct pt_regs *regs);
+asmlinkage int sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+
 /*
  * The following two can't be eliminated yet - they rely on
  * specific conditions.
--- diff/include/asm-arm26/module.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/asm-arm26/module.h	2004-02-18 09:04:02.000000000 +0000
@@ -4,9 +4,4 @@
  * This file contains the arm architecture specific module code.
  */
 
-#define module_map(x)		vmalloc(x)
-#define module_unmap(x)		vfree(x)
-#define module_arch_init(x)	(0)
-#define arch_init_modules(x)	do { } while (0)
-
 #endif /* _ASM_ARM_MODULE_H */
--- diff/include/asm-arm26/param.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/asm-arm26/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -22,10 +22,6 @@
 # define HZ		100
 #endif
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
--- diff/include/asm-arm26/unistd.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/asm-arm26/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -377,8 +377,7 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
-struct rusage;
-asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
+#include <linux/syscalls.h>
 
 static inline long idle(void)
 {
@@ -388,61 +387,51 @@
 
 static inline long pause(void)
 {
-	extern long sys_pause(void);
 	return sys_pause();
 }
 
 static inline long sync(void)
 {
-	extern long sys_sync(void);
 	return sys_sync();
 }
 
 static inline pid_t setsid(void)
 {
-	extern long sys_setsid(void);
 	return sys_setsid();
 }
 
 static inline long write(int fd, const char *buf, off_t count)
 {
-	extern long sys_write(int, const char *, int);
 	return sys_write(fd, buf, count);
 }
 
 static inline long read(int fd, char *buf, off_t count)
 {
-	extern long sys_read(int, char *, int);
 	return sys_read(fd, buf, count);
 }
 
 static inline off_t lseek(int fd, off_t offset, int count)
 {
-	extern off_t sys_lseek(int, off_t, int);
 	return sys_lseek(fd, offset, count);
 }
 
 static inline long dup(int fd)
 {
-	extern long sys_dup(int);
 	return sys_dup(fd);
 }
 
 static inline long open(const char *file, int flag, int mode)
 {
-	extern long sys_open(const char *, int, int);
 	return sys_open(file, flag, mode);
 }
 
 static inline long close(int fd)
 {
-	extern long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
 static inline long _exit(int exitcode)
 {
-	extern long sys_exit(int) __attribute__((noreturn));
 	return sys_exit(exitcode);
 }
 
@@ -453,8 +442,7 @@
 
 static inline long delete_module(const char *name)
 {
-	extern long sys_delete_module(const char *name);
-	return sys_delete_module(name);
+	return sys_delete_module(name, 0);
 }
 
 static inline pid_t wait(int * wait_stat)
@@ -462,6 +450,16 @@
 	return sys_wait4(-1, wait_stat, 0, NULL);
 }
 
+struct pt_regs;
+asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
+			struct pt_regs *regs);
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+			struct pt_regs *regs);
+asmlinkage int sys_fork(struct pt_regs *regs);
+asmlinkage int sys_vfork(struct pt_regs *regs);
+asmlinkage int sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+
 /*
  * The following two can't be eliminated yet - they rely on
  * specific conditions.
--- diff/include/asm-cris/param.h	2003-07-11 09:39:50.000000000 +0100
+++ source/include/asm-cris/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-cris/unistd.h	2003-07-11 09:39:50.000000000 +0100
+++ source/include/asm-cris/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -305,6 +305,23 @@
 extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
 extern inline _syscall1(int,close,int,fd)
 
+asmlinkage long sys_mmap2(
+			unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+struct pt_regs;
+asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
+			long r13, long mof, long srp, struct pt_regs *regs);
+asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
+			int* parent_tid, int* child_tid, long mof, long srp,
+			struct pt_regs *regs);
+asmlinkage int sys_fork(long r10, long r11, long r12, long r13,
+			long mof, long srp, struct pt_regs *regs);
+asmlinkage int sys_vfork(long r10, long r11, long r12, long r13,
+			long mof, long srp, struct pt_regs *regs);
+asmlinkage int sys_pipe(unsigned long __user *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+
 /*
  * Since we define it "external", it collides with the built-in
  * definition, which has the "noreturn" attribute and will cause
--- diff/include/asm-generic/tlb.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/asm-generic/tlb.h	2004-02-18 09:04:02.000000000 +0000
@@ -39,7 +39,6 @@
 	unsigned int		nr;	/* set to ~0U means fast mode */
 	unsigned int		need_flush;/* Really unmapped some ptes? */
 	unsigned int		fullmm; /* non-zero means full mm flush */
-	unsigned long		freed;
 	struct page *		pages[FREE_PTE_NR];
 };
 
@@ -60,7 +59,6 @@
 	tlb->nr = num_online_cpus() > 1 ? 0U : ~0U;
 
 	tlb->fullmm = full_mm_flush;
-	tlb->freed = 0;
 
 	return tlb;
 }
@@ -85,19 +83,17 @@
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-	int freed = tlb->freed;
-	struct mm_struct *mm = tlb->mm;
-	int rss = mm->rss;
-
-	if (rss < freed)
-		freed = rss;
-	mm->rss = rss - freed;
 	tlb_flush_mmu(tlb, start, end);
 
 	/* keep the page table cache within bounds */
 	check_pgt_cache();
 }
 
+static inline unsigned int
+tlb_is_full_mm(struct mmu_gather *tlb)
+{
+	return tlb->fullmm;
+}
 
 /* tlb_remove_page
  *	Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
@@ -141,4 +137,6 @@
 		__pmd_free_tlb(tlb, pmdp);			\
 	} while (0)
 
+#define tlb_migrate_prepare(mm) do { } while(0)
+
 #endif /* _ASM_GENERIC__TLB_H */
--- diff/include/asm-h8300/module.h	2003-05-21 11:50:10.000000000 +0100
+++ source/include/asm-h8300/module.h	2004-02-18 09:04:02.000000000 +0000
@@ -4,9 +4,4 @@
  * This file contains the H8/300 architecture specific module code.
  */
 
-#define module_map(x)		vmalloc(x)
-#define module_unmap(x)		vfree(x)
-#define module_arch_init(x)	(0)
-#define arch_init_modules(x)	do { } while (0)
-
 #endif /* _ASM_H8/300_MODULE_H */
--- diff/include/asm-h8300/param.h	2003-05-21 11:50:10.000000000 +0100
+++ source/include/asm-h8300/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-h8300/unistd.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-h8300/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -479,6 +479,14 @@
 {
 	return waitpid(-1,wait_stat,0);
 }
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(char *name, char **argv, char **envp,
+			int dummy, ...);
+asmlinkage int sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 
 #endif
 
--- diff/include/asm-i386/bugs.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/bugs.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,11 +1,11 @@
 /*
  *  include/asm-i386/bugs.h
  *
- *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 1994	Linus Torvalds
  *
  *  Cyrix stuff, June 1998 by:
  *	- Rafael R. Reilova (moved everything from head.S),
- *        <rreilova@ececs.uc.edu>
+ *	  <rreilova@ececs.uc.edu>
  *	- Channing Corn (tests & fixes),
  *	- Andrew D. Balsa (code cleanup).
  *
@@ -25,7 +25,20 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
-
+#ifdef CONFIG_KGDB
+/*
+ * Provied the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+#endif
 static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
@@ -140,7 +153,7 @@
 	  : "ecx", "edi" );
 	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
 	if (res != 12345678) printk( "Buggy.\n" );
-		        else printk( "OK.\n" );
+			else printk( "OK.\n" );
 #endif
 }
 
--- diff/include/asm-i386/checksum.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/asm-i386/checksum.h	2004-02-18 09:04:02.000000000 +0000
@@ -25,7 +25,7 @@
  * better 64-bit) boundary
  */
 
-asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+asmlinkage unsigned int direct_csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
 						   int *src_err_ptr, int *dst_err_ptr);
 
 /*
@@ -39,14 +39,19 @@
 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
 					int len, int sum)
 {
-	return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+	/*
+	 * The direct function is OK for kernel-space => kernel-space copies:
+	 */
+	return direct_csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
 }
 
 static __inline__
 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
 						int len, int sum, int *err_ptr)
 {
-	return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+	if (copy_from_user(dst, src, len))
+		*err_ptr = -EFAULT;
+	return csum_partial(dst, len, sum);
 }
 
 /*
@@ -172,11 +177,26 @@
  *	Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
+static __inline__ unsigned int direct_csum_and_copy_to_user(const char *src, char *dst,
 				    int len, int sum, int *err_ptr)
 {
 	if (access_ok(VERIFY_WRITE, dst, len))
-		return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+		return direct_csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+	if (len)
+		*err_ptr = -EFAULT;
+
+	return -1; /* invalid checksum */
+}
+
+static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst,
+				    int len, int sum, int *err_ptr)
+{
+	if (access_ok(VERIFY_WRITE, dst, len)) {
+		if (copy_to_user(dst, src, len))
+			*err_ptr = -EFAULT;
+		return csum_partial(src, len, sum);
+	}
 
 	if (len)
 		*err_ptr = -EFAULT;
--- diff/include/asm-i386/cpufeature.h	2003-09-30 15:46:19.000000000 +0100
+++ source/include/asm-i386/cpufeature.h	2004-02-18 09:04:02.000000000 +0000
@@ -76,6 +76,9 @@
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
 #define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
+#define X86_FEATURE_XSTORE_EN	(5*32+ 3) /* on-CPU RNG enabled */
+#define X86_FEATURE_XCRYPT	(5*32+ 6) /* on-CPU crypto (xcrypt insn) */
+#define X86_FEATURE_XCRYPT_EN	(5*32+ 7) /* on-CPU crypto enabled */
 
 
 #define cpu_has(c, bit)		test_bit(bit, (c)->x86_capability)
@@ -101,6 +104,7 @@
 #define cpu_has_cyrix_arr	boot_cpu_has(X86_FEATURE_CYRIX_ARR)
 #define cpu_has_centaur_mcr	boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
 #define cpu_has_xstore		boot_cpu_has(X86_FEATURE_XSTORE)
+#define cpu_has_xcrypt		boot_cpu_has(X86_FEATURE_XCRYPT)
 
 #endif /* __ASM_I386_CPUFEATURE_H */
 
--- diff/include/asm-i386/desc.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/desc.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,6 +21,13 @@
 
 extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
 
+extern void trap_init_virtual_IDT(void);
+extern void trap_init_virtual_GDT(void);
+
+asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
+
 #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
 #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
 
@@ -30,6 +37,7 @@
  */
 extern struct desc_struct default_ldt[];
 extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_trap_gate(unsigned int n, void *addr);
 
 #define _set_tssldt_desc(n,addr,limit,type) \
 __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
@@ -90,31 +98,8 @@
 #undef C
 }
 
-static inline void clear_LDT(void)
-{
-	int cpu = get_cpu();
-
-	set_ldt_desc(cpu, &default_ldt[0], 5);
-	load_LDT_desc();
-	put_cpu();
-}
-
-/*
- * load one particular LDT into the current CPU
- */
-static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
-{
-	void *segments = pc->ldt;
-	int count = pc->size;
-
-	if (likely(!count)) {
-		segments = &default_ldt[0];
-		count = 5;
-	}
-		
-	set_ldt_desc(cpu, segments, count);
-	load_LDT_desc();
-}
+extern struct page *default_ldt_page;
+extern void load_LDT_nolock(mm_context_t *pc, int cpu);
 
 static inline void load_LDT(mm_context_t *pc)
 {
@@ -123,6 +108,6 @@
 	put_cpu();
 }
 
-#endif /* !__ASSEMBLY__ */
 
+#endif /* !__ASSEMBLY__ */
 #endif
--- diff/include/asm-i386/fixmap.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/fixmap.h	2004-02-18 09:04:02.000000000 +0000
@@ -18,17 +18,15 @@
 #include <asm/acpi.h>
 #include <asm/apicdef.h>
 #include <asm/page.h>
-#ifdef CONFIG_HIGHMEM
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
-#endif
 
 /*
  * Here we define all the compile-time 'special' virtual
  * addresses. The point is to have a constant address at
  * compile time, but to set the physical address only
- * in the boot process. We allocate these special addresses
- * from the end of virtual memory (0xfffff000) backwards.
+ * in the boot process. We allocate these special  addresses
+ * from the end of virtual memory (0xffffe000) backwards.
  * Also this lets us do fail-safe vmalloc(), we
  * can guarantee that these special addresses and
  * vmalloc()-ed addresses never overlap.
@@ -41,11 +39,20 @@
  * TLB entries of such buffers will not be flushed across
  * task switches.
  */
+
+/*
+ * on UP currently we will have no trace of the fixmap mechanizm,
+ * no page table allocations, etc. This might change in the
+ * future, say framebuffers for the console driver(s) could be
+ * fix-mapped?
+ */
 enum fixed_addresses {
 	FIX_HOLE,
 	FIX_VSYSCALL,
 #ifdef CONFIG_X86_LOCAL_APIC
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
+#else
+	FIX_VSTACK_HOLE_1,
 #endif
 #ifdef CONFIG_X86_IO_APIC
 	FIX_IO_APIC_BASE_0,
@@ -57,20 +64,28 @@
 	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
 	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
 #endif
-#ifdef CONFIG_X86_F00F_BUG
-	FIX_F00F_IDT,	/* Virtual mapping for IDT */
-#endif
+	FIX_IDT,
+	FIX_GDT_1,
+	FIX_GDT_0,
+	FIX_TSS_3,
+	FIX_TSS_2,
+	FIX_TSS_1,
+	FIX_TSS_0,
+	FIX_ENTRY_TRAMPOLINE_1,
+	FIX_ENTRY_TRAMPOLINE_0,
 #ifdef CONFIG_X86_CYCLONE_TIMER
 	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+	FIX_VSTACK_HOLE_2,
 #endif 
-#ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
-#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
 #endif
+#ifdef CONFIG_PCI_MMCONFIG
+	FIX_PCIE_MCFG,
+#endif
 	__end_of_permanent_fixed_addresses,
 	/* temporary boot-time mappings, used before ioremap() is functional */
 #define NR_FIX_BTMAPS	16
@@ -95,12 +110,15 @@
 		__set_fixmap(idx, 0, __pgprot(0))
 
 /*
- * used by vmalloc.c.
+ * used by vmalloc.c and various other places.
  *
  * Leave one empty page between vmalloc'ed areas and
  * the start of the fixmap.
+ *
+ * IMPORTANT: dont change FIXADDR_TOP without adjusting KM_VSTACK0
+ * and KM_VSTACK1 so that the virtual stack is 8K aligned.
  */
-#define FIXADDR_TOP	(0xfffff000UL)
+#define FIXADDR_TOP	(0xffffe000UL)
 #define __FIXADDR_SIZE	(__end_of_permanent_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START	(FIXADDR_TOP - __FIXADDR_SIZE)
 
--- diff/include/asm-i386/highmem.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-i386/highmem.h	2004-02-18 09:04:02.000000000 +0000
@@ -25,26 +25,19 @@
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
+#include <asm/atomic_kmap.h>
 
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
 
-extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
-
-extern void kmap_init(void);
+extern void kmap_init(void) __init;
 
 /*
  * Right now we initialize only a single pte table. It can be extended
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#if NR_CPUS <= 32
-#define PKMAP_BASE (0xff800000UL)
-#else
-#define PKMAP_BASE (0xff600000UL)
-#endif
 #ifdef CONFIG_X86_PAE
 #define LAST_PKMAP 512
 #else
--- diff/include/asm-i386/kmap_types.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/kmap_types.h	2004-02-18 09:04:02.000000000 +0000
@@ -3,30 +3,36 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
-#endif
-
 enum km_type {
-D(0)	KM_BOUNCE_READ,
-D(1)	KM_SKB_SUNRPC_DATA,
-D(2)	KM_SKB_DATA_SOFTIRQ,
-D(3)	KM_USER0,
-D(4)	KM_USER1,
-D(5)	KM_BIO_SRC_IRQ,
-D(6)	KM_BIO_DST_IRQ,
-D(7)	KM_PTE0,
-D(8)	KM_PTE1,
-D(9)	KM_PTE2,
-D(10)	KM_IRQ0,
-D(11)	KM_IRQ1,
-D(12)	KM_SOFTIRQ0,
-D(13)	KM_SOFTIRQ1,
-D(14)	KM_TYPE_NR
-};
-
-#undef D
+	/*
+	 * IMPORTANT: don't move these 3 entries, and only add entries in
+	 * pairs: the 4G/4G virtual stack must be 8K aligned on each cpu.
+	 */
+	KM_BOUNCE_READ,
+	KM_VSTACK1,
+	KM_VSTACK0,
 
+	KM_LDT_PAGE15,
+	KM_LDT_PAGE0 = KM_LDT_PAGE15 + 16-1,
+	KM_USER_COPY,
+	KM_VSTACK_HOLE,
+	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
+	KM_BIO_SRC_IRQ,
+	KM_BIO_DST_IRQ,
+	KM_PTE0,
+	KM_PTE1,
+	KM_PTE2,
+	KM_IRQ0,
+	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
+	/*
+	 * Add new entries in pairs:
+	 * the 4G/4G virtual stack must be 8K aligned on each cpu.
+	 */
+	KM_TYPE_NR
+};
 #endif
--- diff/include/asm-i386/mmu.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/mmu.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,10 +8,13 @@
  *
  * cpu_vm_mask is used to optimize ldt flushing.
  */
+
+#define MAX_LDT_PAGES 16
+
 typedef struct { 
 	int size;
 	struct semaphore sem;
-	void *ldt;
+	struct page *ldt_pages[MAX_LDT_PAGES];
 } mm_context_t;
 
 #endif
--- diff/include/asm-i386/mmu_context.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/mmu_context.h	2004-02-18 09:04:02.000000000 +0000
@@ -29,6 +29,10 @@
 {
 	int cpu = smp_processor_id();
 
+#ifdef CONFIG_X86_SWITCH_PAGETABLES
+	if (tsk->mm)
+		tsk->thread_info->user_pgd = (void *)__pa(tsk->mm->pgd);
+#endif
 	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
 		cpu_clear(cpu, prev->cpu_vm_mask);
@@ -39,12 +43,14 @@
 		cpu_set(cpu, next->cpu_vm_mask);
 
 		/* Re-load page tables */
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
 		load_cr3(next->pgd);
+#endif
 
 		/*
 		 * load the LDT, if the LDT is different:
 		 */
-		if (unlikely(prev->context.ldt != next->context.ldt))
+		if (unlikely(prev->context.size + next->context.size))
 			load_LDT_nolock(&next->context, cpu);
 	}
 #ifdef CONFIG_SMP
@@ -56,7 +62,9 @@
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must reload %cr3.
 			 */
+#if !defined(CONFIG_X86_SWITCH_PAGETABLES)
 			load_cr3(next->pgd);
+#endif
 			load_LDT_nolock(&next->context, cpu);
 		}
 	}
@@ -67,6 +75,6 @@
 	asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0))
 
 #define activate_mm(prev, next) \
-	switch_mm((prev),(next),NULL)
+	switch_mm((prev),(next),current)
 
 #endif
--- diff/include/asm-i386/mmzone.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/mmzone.h	2004-02-18 09:04:02.000000000 +0000
@@ -10,7 +10,49 @@
 
 #ifdef CONFIG_DISCONTIGMEM
 
+#ifdef CONFIG_NUMA
+	#ifdef CONFIG_X86_NUMAQ
+		#include <asm/numaq.h>
+	#else	/* summit or generic arch */
+		#include <asm/srat.h>
+	#endif
+#else /* !CONFIG_NUMA */
+	#define get_memcfg_numa get_memcfg_numa_flat
+	#define get_zholes_size(n) (0)
+#endif /* CONFIG_NUMA */
+
 extern struct pglist_data *node_data[];
+#define NODE_DATA(nid)		(node_data[nid])
+
+/*
+ * generic node memory support, the following assumptions apply:
+ *
+ * 1) memory comes in 256Mb contigious chunks which are either present or not
+ * 2) we will not have more than 64Gb in total
+ *
+ * for now assume that 64Gb is max amount of RAM for whole system
+ *    64Gb / 4096bytes/page = 16777216 pages
+ */
+#define MAX_NR_PAGES 16777216
+#define MAX_ELEMENTS 256
+#define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS)
+
+extern u8 physnode_map[];
+
+static inline int pfn_to_nid(unsigned long pfn)
+{
+#ifdef CONFIG_NUMA
+	return(physnode_map[(pfn) / PAGES_PER_ELEMENT]);
+#else
+	return 0;
+#endif
+}
+
+static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)
+{
+	return(NODE_DATA(pfn_to_nid(pfn)));
+}
+
 
 /*
  * Following are macros that are specific to this numa platform.
@@ -43,11 +85,6 @@
  */
 #define kvaddr_to_nid(kaddr)	pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT)
 
-/*
- * Return a pointer to the node data for node n.
- */
-#define NODE_DATA(nid)		(node_data[nid])
-
 #define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
 #define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
 #define node_end_pfn(nid)						\
@@ -80,48 +117,19 @@
 		+ __zone->zone_start_pfn;				\
 })
 #define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
-/*
- * pfn_valid should be made as fast as possible, and the current definition 
- * is valid for machines that are NUMA, but still contiguous, which is what
- * is currently supported. A more generalised, but slower definition would
- * be something like this - mbligh:
- * ( pfn_to_pgdat(pfn) && ((pfn) < node_end_pfn(pfn_to_nid(pfn))) ) 
- */ 
-#define pfn_valid(pfn)          ((pfn) < num_physpages)
-
-/*
- * generic node memory support, the following assumptions apply:
- *
- * 1) memory comes in 256Mb contigious chunks which are either present or not
- * 2) we will not have more than 64Gb in total
- *
- * for now assume that 64Gb is max amount of RAM for whole system
- *    64Gb / 4096bytes/page = 16777216 pages
- */
-#define MAX_NR_PAGES 16777216
-#define MAX_ELEMENTS 256
-#define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS)
 
-extern u8 physnode_map[];
-
-static inline int pfn_to_nid(unsigned long pfn)
-{
-	return(physnode_map[(pfn) / PAGES_PER_ELEMENT]);
-}
-static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)
+#ifdef CONFIG_X86_NUMAQ            /* we have contiguous memory on NUMA-Q */
+#define pfn_valid(pfn)          ((pfn) < num_physpages)
+#else
+static inline int pfn_valid(int pfn)
 {
-	return(NODE_DATA(pfn_to_nid(pfn)));
-}
+	int nid = pfn_to_nid(pfn);
 
-#ifdef CONFIG_X86_NUMAQ
-#include <asm/numaq.h>
-#elif CONFIG_ACPI_SRAT
-#include <asm/srat.h>
-#elif CONFIG_X86_PC
-#define get_zholes_size(n) (0)
-#else
-#define pfn_to_nid(pfn)		(0)
-#endif /* CONFIG_X86_NUMAQ */
+	if (nid >= 0)
+		return (pfn < node_end_pfn(nid));
+	return 0;
+}
+#endif
 
 extern int get_memcfg_numa_flat(void );
 /*
--- diff/include/asm-i386/module.h	2003-02-26 16:01:02.000000000 +0000
+++ source/include/asm-i386/module.h	2004-02-18 09:04:02.000000000 +0000
@@ -26,6 +26,8 @@
 #define MODULE_PROC_FAMILY "PENTIUMII "
 #elif defined CONFIG_MPENTIUMIII
 #define MODULE_PROC_FAMILY "PENTIUMIII "
+#elif defined CONFIG_MPENTIUMM
+#define MODULE_PROC_FAMILY "PENTIUMM "
 #elif defined CONFIG_MPENTIUM4
 #define MODULE_PROC_FAMILY "PENTIUM4 "
 #elif defined CONFIG_MK6
@@ -46,12 +48,18 @@
 #define MODULE_PROC_FAMILY "WINCHIP3D "
 #elif defined CONFIG_MCYRIXIII
 #define MODULE_PROC_FAMILY "CYRIXIII "
-#elif CONFIG_MVIAC3_2
+#elif defined CONFIG_MVIAC3_2
 #define MODULE_PROC_FAMILY "VIAC3-2 "
 #else
 #error unknown processor family
 #endif
 
-#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
+#ifdef CONFIG_REGPARM
+#define MODULE_REGPARM "REGPARM "
+#else
+#define MODULE_REGPARM ""
+#endif
+
+#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_REGPARM
 
 #endif /* _ASM_I386_MODULE_H */
--- diff/include/asm-i386/page.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/page.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,6 +1,8 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
@@ -9,11 +11,10 @@
 #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
 #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
 
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
 #include <linux/config.h>
 
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
@@ -88,8 +89,19 @@
  *
  * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
  * and CONFIG_HIGHMEM64G options in the kernel configuration.
+ *
+ * Note: on PAE the kernel must never go below 32 MB, we use the
+ * first 8 entries of the 2-level boot pgd for PAE magic.
  */
 
+#ifdef CONFIG_X86_4G_VM_LAYOUT
+#define __PAGE_OFFSET		(0x02000000)
+#define TASK_SIZE		(0xff000000)
+#else
+#define __PAGE_OFFSET		(0xc0000000)
+#define TASK_SIZE		(0xc0000000)
+#endif
+
 /*
  * This much address space is reserved for vmalloc() and iomap()
  * as well as fixmap mappings.
@@ -114,16 +126,10 @@
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef __ASSEMBLY__
-#define __PAGE_OFFSET		(0xC0000000)
-#else
-#define __PAGE_OFFSET		(0xC0000000UL)
-#endif
-
-
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 #define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
-#define MAXMEM			(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define __MAXMEM		(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+#define MAXMEM			((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
--- diff/include/asm-i386/param.h	2002-10-16 04:27:19.000000000 +0100
+++ source/include/asm-i386/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-i386/pgtable.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-i386/pgtable.h	2004-02-18 09:04:02.000000000 +0000
@@ -32,16 +32,17 @@
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 extern unsigned long empty_zero_page[1024];
 extern pgd_t swapper_pg_dir[1024];
-extern kmem_cache_t *pgd_cache;
-extern kmem_cache_t *pmd_cache;
+extern kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache;
 extern spinlock_t pgd_lock;
 extern struct list_head pgd_list;
 
 void pmd_ctor(void *, kmem_cache_t *, unsigned long);
+void kpmd_ctor(void *, kmem_cache_t *, unsigned long);
 void pgd_ctor(void *, kmem_cache_t *, unsigned long);
 void pgd_dtor(void *, kmem_cache_t *, unsigned long);
 void pgtable_cache_init(void);
 void paging_init(void);
+void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end);
 
 #endif /* !__ASSEMBLY__ */
 
@@ -51,6 +52,11 @@
  * newer 3-level PAE-mode page tables.
  */
 #ifndef __ASSEMBLY__
+
+extern void set_system_gate(unsigned int n, void *addr);
+extern void init_entry_mappings(void);
+extern void entry_trampoline_setup(void);
+
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
 #else
@@ -63,7 +69,12 @@
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
-#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#if defined(CONFIG_X86_PAE) && defined(CONFIG_X86_4G_VM_LAYOUT)
+# define USER_PTRS_PER_PGD	4
+#else
+# define USER_PTRS_PER_PGD	((TASK_SIZE/PGDIR_SIZE) + ((TASK_SIZE % PGDIR_SIZE) + PGDIR_SIZE-1)/PGDIR_SIZE)
+#endif
+
 #define FIRST_USER_PGD_NR	0
 
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
@@ -233,6 +244,7 @@
 
 #define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
 #define mk_pte_huge(entry) ((entry).pte_low |= _PAGE_PRESENT | _PAGE_PSE)
+#define mk_pte_phys(physpage, pgprot) pfn_pte((physpage) >> PAGE_SHIFT, pgprot)
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
--- diff/include/asm-i386/processor.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-i386/processor.h	2004-02-18 09:04:02.000000000 +0000
@@ -291,11 +291,6 @@
 extern unsigned int BIOS_revision;
 extern unsigned int mca_pentium_flag;
 
-/*
- * User space process size: 3GB (default).
- */
-#define TASK_SIZE	(PAGE_OFFSET)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
@@ -406,6 +401,7 @@
 struct thread_struct {
 /* cached TLS descriptors. */
 	struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
+	void *stack_page0, *stack_page1;
 	unsigned long	esp0;
 	unsigned long	sysenter_cs;
 	unsigned long	eip;
@@ -449,7 +445,8 @@
 	.io_bitmap	= { [ 0 ... IO_BITMAP_LONGS] = ~0 },		\
 }
 
-static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+static inline void
+load_esp0(struct tss_struct *tss, struct thread_struct *thread)
 {
 	tss->esp0 = thread->esp0;
 	/* This can only happen when SEP is enabled, no need to test "SEP"arately */
@@ -485,6 +482,23 @@
  */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
+#ifdef CONFIG_X86_HIGH_ENTRY
+#define virtual_esp0(tsk) \
+	((unsigned long)(tsk)->thread_info->virtual_stack + ((tsk)->thread.esp0 - (unsigned long)(tsk)->thread_info->real_stack))
+#else
+# define virtual_esp0(tsk) ((tsk)->thread.esp0)
+#endif
+
+#define load_virtual_esp0(tss, task)					\
+	do {								\
+		tss->esp0 = virtual_esp0(task);				\
+		if (likely(cpu_has_sep) && unlikely(tss->ss1 != task->thread.sysenter_cs)) {	\
+			tss->ss1 = task->thread.sysenter_cs;		\
+			wrmsr(MSR_IA32_SYSENTER_CS,			\
+				task->thread.sysenter_cs, 0);		\
+		}							\
+	} while (0)
+
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
 void show_trace(struct task_struct *task, unsigned long *stack);
 
@@ -630,4 +644,9 @@
 
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
+#ifdef CONFIG_SCHED_SMT
+#define ARCH_HAS_SCHED_DOMAIN
+#define ARCH_HAS_SCHED_WAKE_BALANCE
+#endif
+
 #endif /* __ASM_I386_PROCESSOR_H */
--- diff/include/asm-i386/rwlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/rwlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -20,28 +20,52 @@
 #define RW_LOCK_BIAS		 0x01000000
 #define RW_LOCK_BIAS_STR	"0x01000000"
 
-#define __build_read_lock_ptr(rw, helper)   \
-	asm volatile(LOCK "subl $1,(%0)\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_read_lock_const(rw, helper)   \
-	asm volatile(LOCK "subl $1,%0\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "jns 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\t" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "jns 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\t" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
+
 
 #define __build_read_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
@@ -50,28 +74,51 @@
 							__build_read_lock_ptr(rw, helper); \
 					} while (0)
 
-#define __build_write_lock_ptr(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jz 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\n" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jz 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\n" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
 
 #define __build_write_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
--- diff/include/asm-i386/smp.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-i386/smp.h	2004-02-18 09:04:02.000000000 +0000
@@ -34,7 +34,7 @@
 extern void smp_alloc_memory(void);
 extern int pic_mode;
 extern int smp_num_siblings;
-extern int cpu_sibling_map[];
+extern cpumask_t cpu_sibling_map[];
 
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
--- diff/include/asm-i386/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -43,18 +43,35 @@
 #define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
-#define spin_lock_string \
-	"\n1:\t" \
-	"lock ; decb %0\n\t" \
-	"js 2f\n" \
-	LOCK_SECTION_START("") \
-	"2:\t" \
-	"rep;nop\n\t" \
-	"cmpb $0,%0\n\t" \
-	"jle 2b\n\t" \
-	"jmp 1b\n" \
-	LOCK_SECTION_END
+#ifdef CONFIG_SPINLINE
 
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		"jmp 3f\n" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+#else /* !CONFIG_SPINLINE */
+
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+#endif /* CONFIG_SPINLINE */
 /*
  * This works. Despite all the confusion.
  * (except on PPro SMP or if we are using OOSTORE)
@@ -138,6 +155,11 @@
  */
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 #ifdef CONFIG_DEBUG_SPINLOCK
 	unsigned magic;
 #endif
@@ -145,11 +167,19 @@
 
 #define RWLOCK_MAGIC	0xdeaf1eed
 
+#ifdef CONFIG_LOCKMETER
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define RWLOCK_MAGIC_INIT	, 0, RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT	, 0
+#endif
+#else /* !CONFIG_LOCKMETER */
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
 #else
 #define RWLOCK_MAGIC_INIT	/* */
 #endif
+#endif /* !CONFIG_LOCKMETER */
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
 
@@ -196,4 +226,60 @@
 	return 0;
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+/* FIXME -- replace with assembler */
+	atomic_t *count = (atomic_t *)lock;
+	atomic_dec(count);
+	if (count->counter > 0)
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Matches what is in arch/i386/lib/dec_and_lock.c, except this one is
+ *  "static inline" so that the spin_lock(), if actually invoked, is charged
+ *  against the real caller, not against the catch-all atomic_dec_and_lock
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	asm volatile("lock; cmpxchgl %1,%2"
+		:"=a" (newcount)
+		:"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+	/* If the above failed, "eax" will have changed */
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	preempt_disable();
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	preempt_enable();
+	return 0;
+}
+
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /* __ASM_SPINLOCK_H */
--- diff/include/asm-i386/string.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/string.h	2004-02-18 09:04:02.000000000 +0000
@@ -58,6 +58,29 @@
 return dest;
 }
 
+/*
+ * This is a more generic variant of strncpy_count() suitable for
+ * implementing string-access routines with all sorts of return
+ * code semantics. It's used by mm/usercopy.c.
+ */
+static inline size_t strncpy_count(char * dest,const char *src,size_t count)
+{
+	__asm__ __volatile__(
+
+	"1:\tdecl %0\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n\t"
+	"2:"
+	"incl %0"
+	: "=c" (count)
+	:"S" (src),"D" (dest),"0" (count) : "memory");
+
+	return count;
+}
+
 static inline char * strcat(char * dest,const char * src)
 {
 int d0, d1, d2, d3;
--- diff/include/asm-i386/thread_info.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/thread_info.h	2004-02-18 09:04:02.000000000 +0000
@@ -33,23 +33,12 @@
 					 	   0-0xBFFFFFFF for user-thead
 						   0-0xFFFFFFFF for kernel-thread
 						*/
-	struct restart_block    restart_block;
+	void *real_stack, *virtual_stack, *user_pgd;
 
+	struct restart_block    restart_block;
 	__u8			supervisor_stack[0];
 };
 
-#else /* !__ASSEMBLY__ */
-
-/* offsets into the thread_info struct for assembly code access */
-#define TI_TASK		0x00000000
-#define TI_EXEC_DOMAIN	0x00000004
-#define TI_FLAGS	0x00000008
-#define TI_STATUS	0x0000000C
-#define TI_CPU		0x00000010
-#define TI_PRE_COUNT	0x00000014
-#define TI_ADDR_LIMIT	0x00000018
-#define TI_RESTART_BLOCK 0x000001C
-
 #endif
 
 #define PREEMPT_ACTIVE		0x4000000
@@ -61,7 +50,7 @@
  */
 #ifndef __ASSEMBLY__
 
-#define INIT_THREAD_INFO(tsk)			\
+#define INIT_THREAD_INFO(tsk, thread_info)	\
 {						\
 	.task		= &tsk,			\
 	.exec_domain	= &default_exec_domain,	\
@@ -72,21 +61,23 @@
 	.restart_block = {			\
 		.fn = do_no_restart_syscall,	\
 	},					\
+	.real_stack	= &thread_info,		\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
+#define THREAD_SIZE (2*PAGE_SIZE)
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
 	struct thread_info *ti;
-	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~8191UL));
+	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
 	return ti;
 }
 
 /* thread information allocation */
-#define THREAD_SIZE (2*PAGE_SIZE)
 #define alloc_thread_info(task) ((struct thread_info *)kmalloc(THREAD_SIZE, GFP_KERNEL))
 #define free_thread_info(info)	kfree(info)
 #define get_thread_info(ti) get_task_struct((ti)->task)
@@ -94,9 +85,11 @@
 
 #else /* !__ASSEMBLY__ */
 
+#define THREAD_SIZE	8192
+
 /* how to get the thread information struct from ASM */
 #define GET_THREAD_INFO(reg) \
-	movl $-8192, reg; \
+	movl $-THREAD_SIZE, reg; \
 	andl %esp, reg
 
 #endif
@@ -113,6 +106,7 @@
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
 #define TIF_IRET		5	/* return with iret */
+#define TIF_DB7			6	/* has debug registers */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -121,6 +115,7 @@
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 #define _TIF_IRET		(1<<TIF_IRET)
+#define _TIF_DB7		(1<<TIF_DB7)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
--- diff/include/asm-i386/timer.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-i386/timer.h	2004-02-18 09:04:02.000000000 +0000
@@ -40,9 +40,13 @@
 #endif
 
 extern unsigned long calibrate_tsc(void);
+extern void init_cpu_khz(void);
 #ifdef CONFIG_HPET_TIMER
 extern struct timer_opts timer_hpet;
 extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
 #endif
 
+#ifdef CONFIG_X86_PM_TIMER
+extern struct timer_opts timer_pmtmr;
+#endif
 #endif
--- diff/include/asm-i386/timex.h	2003-06-30 10:07:29.000000000 +0100
+++ source/include/asm-i386/timex.h	2004-02-18 09:04:02.000000000 +0000
@@ -12,7 +12,7 @@
 #ifdef CONFIG_X86_PC9800
    extern int CLOCK_TICK_RATE;
 #else
-#ifdef CONFIG_MELAN
+#ifdef CONFIG_X86_ELAN
 #  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
 #  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
--- diff/include/asm-i386/tlbflush.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/tlbflush.h	2004-02-18 09:04:02.000000000 +0000
@@ -85,22 +85,28 @@
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (mm == current->active_mm)
 		__flush_tlb();
+#endif
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long addr)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (vma->vm_mm == current->active_mm)
 		__flush_tlb_one(addr);
+#endif
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
+#ifndef CONFIG_X86_SWITCH_PAGETABLES
 	if (vma->vm_mm == current->active_mm)
 		__flush_tlb();
+#endif
 }
 
 #else
@@ -111,11 +117,10 @@
 	__flush_tlb()
 
 extern void flush_tlb_all(void);
-extern void flush_tlb_current_task(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
-#define flush_tlb()	flush_tlb_current_task()
+#define flush_tlb()	flush_tlb_all()
 
 static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
 {
--- diff/include/asm-i386/uaccess.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-i386/uaccess.h	2004-02-18 09:04:02.000000000 +0000
@@ -26,7 +26,7 @@
 
 
 #define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFFUL)
-#define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
+#define USER_DS		MAKE_MM_SEG(TASK_SIZE)
 
 #define get_ds()	(KERNEL_DS)
 #define get_fs()	(current_thread_info()->addr_limit)
@@ -149,6 +149,45 @@
 		:"=a" (ret),"=d" (x) \
 		:"0" (ptr))
 
+extern int get_user_size(unsigned int size, void *val, const void *ptr);
+extern int put_user_size(unsigned int size, const void *val, void *ptr);
+extern int zero_user_size(unsigned int size, void *ptr);
+extern int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr);
+extern int strlen_fromuser_size(unsigned int size, const void *ptr);
+
+
+# define indirect_get_user(x,ptr)					\
+({	int __ret_gu,__val_gu;						\
+	__typeof__(ptr) __ptr_gu = (ptr);				\
+	__ret_gu = get_user_size(sizeof(*__ptr_gu), &__val_gu,__ptr_gu) ? -EFAULT : 0;\
+	(x) = (__typeof__(*__ptr_gu))__val_gu;				\
+	__ret_gu;							\
+})
+#define indirect_put_user(x,ptr)					\
+({									\
+	__typeof__(*(ptr)) *__ptr_pu = (ptr), __x_pu = (x);		\
+	put_user_size(sizeof(*__ptr_pu), &__x_pu, __ptr_pu) ? -EFAULT : 0; \
+})
+#define __indirect_put_user indirect_put_user
+#define __indirect_get_user indirect_get_user
+
+#define indirect_copy_from_user(to,from,n) get_user_size(n,to,from)
+#define indirect_copy_to_user(to,from,n) put_user_size(n,from,to)
+
+#define __indirect_copy_from_user indirect_copy_from_user
+#define __indirect_copy_to_user indirect_copy_to_user
+
+#define indirect_strncpy_from_user(dst, src, count) \
+		copy_str_fromuser_size(count, dst, src)
+
+extern int strlen_fromuser_size(unsigned int size, const void *ptr);
+#define indirect_strnlen_user(str, n) strlen_fromuser_size(n, str)
+#define indirect_strlen_user(str) indirect_strnlen_user(str, ~0UL >> 1)
+
+extern int zero_user_size(unsigned int size, void *ptr);
+
+#define indirect_clear_user(mem, len) zero_user_size(len, mem)
+#define __indirect_clear_user clear_user
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 /**
@@ -168,7 +207,7 @@
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define get_user(x,ptr)							\
+#define direct_get_user(x,ptr)						\
 ({	int __ret_gu,__val_gu;						\
 	switch(sizeof (*(ptr))) {					\
 	case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;		\
@@ -198,7 +237,7 @@
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define put_user(x,ptr)							\
+#define direct_put_user(x,ptr)						\
   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 
@@ -222,7 +261,7 @@
  * Returns zero on success, or -EFAULT on error.
  * On error, the variable @x is set to zero.
  */
-#define __get_user(x,ptr) \
+#define __direct_get_user(x,ptr) \
   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 
 
@@ -245,7 +284,7 @@
  *
  * Returns zero on success, or -EFAULT on error.
  */
-#define __put_user(x,ptr) \
+#define __direct_put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 #define __put_user_nocheck(x,ptr,size)				\
@@ -396,7 +435,7 @@
  * On success, this will be zero.
  */
 static inline unsigned long
-__copy_to_user(void __user *to, const void *from, unsigned long n)
+__direct_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
@@ -434,7 +473,7 @@
  * data to the requested size using zero bytes.
  */
 static inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__direct_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
@@ -468,11 +507,11 @@
  * On success, this will be zero.
  */
 static inline unsigned long
-copy_to_user(void __user *to, const void *from, unsigned long n)
+direct_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
-		n = __copy_to_user(to, from, n);
+		n = __direct_copy_to_user(to, from, n);
 	return n;
 }
 
@@ -493,11 +532,11 @@
  * data to the requested size using zero bytes.
  */
 static inline unsigned long
-copy_from_user(void *to, const void __user *from, unsigned long n)
+direct_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_READ, from, n))
-		n = __copy_from_user(to, from, n);
+		n = __direct_copy_from_user(to, from, n);
 	else
 		memset(to, 0, n);
 	return n;
@@ -520,10 +559,68 @@
  * If there is a limit on the length of a valid string, you may wish to
  * consider using strnlen_user() instead.
  */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 
-long strnlen_user(const char __user *str, long n);
-unsigned long clear_user(void __user *mem, unsigned long len);
-unsigned long __clear_user(void __user *mem, unsigned long len);
+long direct_strncpy_from_user(char *dst, const char *src, long count);
+long __direct_strncpy_from_user(char *dst, const char *src, long count);
+#define direct_strlen_user(str) direct_strnlen_user(str, ~0UL >> 1)
+long direct_strnlen_user(const char *str, long n);
+unsigned long direct_clear_user(void *mem, unsigned long len);
+unsigned long __direct_clear_user(void *mem, unsigned long len);
+
+extern int indirect_uaccess;
+
+#ifdef CONFIG_X86_UACCESS_INDIRECT
+
+/*
+ * Return code and zeroing semantics:
+
+ __clear_user          0                      <-> bytes not done
+ clear_user            0                      <-> bytes not done
+ __copy_to_user        0                      <-> bytes not done
+ copy_to_user          0                      <-> bytes not done
+ __copy_from_user      0                      <-> bytes not done, zero rest
+ copy_from_user        0                      <-> bytes not done, zero rest
+ __get_user            0                      <-> -EFAULT
+ get_user              0                      <-> -EFAULT
+ __put_user            0                      <-> -EFAULT
+ put_user              0                      <-> -EFAULT
+ strlen_user           strlen + 1             <-> 0
+ strnlen_user          strlen + 1 (or n+1)    <-> 0
+ strncpy_from_user     strlen (or n)          <-> -EFAULT
+
+ */
+
+#define __clear_user(mem,len) __indirect_clear_user(mem,len)
+#define clear_user(mem,len) indirect_clear_user(mem,len)
+#define __copy_to_user(to,from,n) __indirect_copy_to_user(to,from,n)
+#define copy_to_user(to,from,n) indirect_copy_to_user(to,from,n)
+#define __copy_from_user(to,from,n) __indirect_copy_from_user(to,from,n)
+#define copy_from_user(to,from,n) indirect_copy_from_user(to,from,n)
+#define __get_user(val,ptr) __indirect_get_user(val,ptr)
+#define get_user(val,ptr) indirect_get_user(val,ptr)
+#define __put_user(val,ptr) __indirect_put_user(val,ptr)
+#define put_user(val,ptr) indirect_put_user(val,ptr)
+#define strlen_user(str) indirect_strlen_user(str)
+#define strnlen_user(src,count) indirect_strnlen_user(src,count)
+#define strncpy_from_user(dst,src,count) \
+			indirect_strncpy_from_user(dst,src,count)
+
+#else
+
+#define __clear_user __direct_clear_user
+#define clear_user direct_clear_user
+#define __copy_to_user __direct_copy_to_user
+#define copy_to_user direct_copy_to_user
+#define __copy_from_user __direct_copy_from_user
+#define copy_from_user direct_copy_from_user
+#define __get_user __direct_get_user
+#define get_user direct_get_user
+#define __put_user __direct_put_user
+#define put_user direct_put_user
+#define strlen_user direct_strlen_user
+#define strnlen_user direct_strnlen_user
+#define strncpy_from_user direct_strncpy_from_user
+
+#endif /* CONFIG_X86_UACCESS_INDIRECT */
 
 #endif /* __i386_UACCESS_H */
--- diff/include/asm-i386/unistd.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-i386/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -373,6 +373,8 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <asm/ptrace.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -395,6 +397,18 @@
 static inline _syscall1(int,close,int,fd)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount);
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(struct pt_regs regs);
+asmlinkage int sys_clone(struct pt_regs regs);
+asmlinkage int sys_fork(struct pt_regs regs);
+asmlinkage int sys_vfork(struct pt_regs regs);
+asmlinkage int sys_pipe(unsigned long __user *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_iopl(unsigned long unused);
+
 #endif
 
 /*
--- diff/include/asm-ia64/compat.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-ia64/compat.h	2004-02-18 09:04:02.000000000 +0000
@@ -26,6 +26,7 @@
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef u32		compat_timer_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
--- diff/include/asm-ia64/param.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -12,10 +12,6 @@
 
 #define EXEC_PAGESIZE	65536
 
-#ifndef NGROUPS
-# define NGROUPS	32
-#endif
-
 #ifndef NOGROUP
 # define NOGROUP	(-1)
 #endif
--- diff/include/asm-ia64/sal.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/sal.h	2004-02-18 09:04:02.000000000 +0000
@@ -741,10 +741,10 @@
 
 /* Read from PCI configuration space */
 static inline s64
-ia64_sal_pci_config_read (u64 pci_config_addr, u64 size, u64 *value)
+ia64_sal_pci_config_read (u64 pci_config_addr, int type, u64 size, u64 *value)
 {
 	struct ia64_sal_retval isrv;
-	SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, 0, 0, 0, 0, 0);
+	SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, type, 0, 0, 0, 0);
 	if (value)
 		*value = isrv.v0;
 	return isrv.status;
@@ -752,11 +752,11 @@
 
 /* Write to PCI configuration space */
 static inline s64
-ia64_sal_pci_config_write (u64 pci_config_addr, u64 size, u64 value)
+ia64_sal_pci_config_write (u64 pci_config_addr, int type, u64 size, u64 value)
 {
 	struct ia64_sal_retval isrv;
 	SAL_CALL(isrv, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value,
-	         0, 0, 0, 0);
+	         type, 0, 0, 0);
 	return isrv.status;
 }
 
--- diff/include/asm-ia64/sn/clksupport.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/clksupport.h	2004-02-18 09:04:02.000000000 +0000
@@ -24,17 +24,16 @@
 #define _ASM_IA64_SN_CLKSUPPORT_H
 
 #include <asm/sn/arch.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/sn2/addrs.h>
+#include <asm/sn/sn2/shubio.h>
+#include <asm/sn/sn2/shub_mmr.h>
 
 typedef long clkreg_t;
 
 extern unsigned long sn_rtc_cycles_per_second;
 extern unsigned long sn_rtc_per_itc;
 
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/sn2/addrs.h>
-#include <asm/sn/sn2/shubio.h>
-#include <asm/sn/sn2/shub_mmr.h>
 #define RTC_MASK		SH_RTC_MASK
 #define RTC_COUNTER_ADDR	((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
 #define RTC_COMPARE_A_ADDR      ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
--- diff/include/asm-ia64/sn/dmamap.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/dmamap.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,12 +8,6 @@
 #ifndef _ASM_IA64_SN_DMAMAP_H
 #define _ASM_IA64_SN_DMAMAP_H
 
-#include <asm/sn/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * Definitions for allocating, freeing, and using DMA maps
  */
@@ -43,10 +37,6 @@
 	unsigned long	dma_virtaddr;	/* Beginning virtual address that is mapped */
 } dmamap_t;
 
-#ifdef __cplusplus
-}
-#endif
-
 /* standard flags values for pio_map routines,
  * including {xtalk,pciio}_dmamap calls.
  * NOTE: try to keep these in step with PIOMAP flags.
--- diff/include/asm-ia64/sn/driver.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/driver.h	2004-02-18 09:04:02.000000000 +0000
@@ -23,10 +23,6 @@
 /* == Driver thread priority support == */
 typedef int ilvl_t;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct eframe_s;
 struct piomap;
 struct dmamap;
--- diff/include/asm-ia64/sn/intr.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/intr.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,7 +8,6 @@
 #ifndef _ASM_IA64_SN_INTR_H
 #define _ASM_IA64_SN_INTR_H
 
-#include <linux/config.h>
 #include <asm/sn/sn2/intr.h>
 
 extern void sn_send_IPI_phys(long, int, int);
--- diff/include/asm-ia64/sn/io.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/io.h	2004-02-18 09:04:02.000000000 +0000
@@ -9,8 +9,6 @@
 #ifndef _ASM_IA64_SN_IO_H
 #define _ASM_IA64_SN_IO_H
 
-#include <linux/config.h>
-
 #include <asm/sn/addrs.h>
 
 /* Because we only have PCI I/O ports.  */
--- diff/include/asm-ia64/sn/ioc4.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/ioc4.h	2004-02-18 09:04:02.000000000 +0000
@@ -9,682 +9,6 @@
 #ifndef _ASM_IA64_SN_IOC4_H
 #define _ASM_IA64_SN_IOC4_H
 
-#if 0
-
-/*
- * ioc4.h - IOC4 chip header file
- */
-
-/* Notes:
- * The IOC4 chip is a 32-bit PCI device that provides 4 serial ports,
- * an IDE bus interface, a PC keyboard/mouse interface, and a real-time
- * external interrupt interface.
- *
- * It includes an optimized DMA buffer management, and a store-and-forward
- * buffer RAM.
- *
- * All IOC4 registers are 32 bits wide.
- */
-typedef __uint32_t ioc4reg_t;
-
-/*
- * PCI Configuration Space Register Address Map, use offset from IOC4 PCI
- * configuration base such that this can be used for multiple IOC4s
- */
-#define IOC4_PCI_ID		0x0	/* ID */
-
-#define IOC4_VENDOR_ID_NUM	0x10A9
-#define IOC4_DEVICE_ID_NUM	0x100A 
-#define IOC4_ADDRSPACE_MASK	0xfff00000ULL
-
-#define IOC4_PCI_SCR		0x4 /* Status/Command */
-#define IOC4_PCI_REV		0x8 /* Revision */
-#define IOC4_PCI_LAT		0xC /* Latency Timer */
-#define IOC4_PCI_BAR0		0x10 /* IOC4 base address 0 */
-#define IOC4_PCI_SIDV		0x2c /* Subsys ID and vendor */
-#define IOC4_PCI_CAP 		0x34 /* Capability pointer */
-#define IOC4_PCI_LATGNTINT      0x3c /* Max_lat, min_gnt, int_pin, int_line */
-
-/*
- * PCI Memory Space Map 
- */
-#define IOC4_PCI_ERR_ADDR_L     0x000	/* Low Error Address */
-#define IOC4_PCI_ERR_ADDR_VLD	     (0x1 << 0)
-#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1)
-#define IOC4_PCI_ERR_ADDR_MUL_ERR    (0x1 << 5)
-#define IOC4_PCI_ERR_ADDR_ADDR_MSK   (0x3ffffff << 6)
-
-/* Master IDs contained in PCI_ERR_ADDR_MST_ID_MSK */
-#define IOC4_MST_ID_S0_TX		0
-#define IOC4_MST_ID_S0_RX		1
-#define IOC4_MST_ID_S1_TX		2
-#define IOC4_MST_ID_S1_RX		3
-#define IOC4_MST_ID_S2_TX		4
-#define IOC4_MST_ID_S2_RX		5
-#define IOC4_MST_ID_S3_TX		6
-#define IOC4_MST_ID_S3_RX		7
-#define IOC4_MST_ID_ATA 		8
-
-#define IOC4_PCI_ERR_ADDR_H	0x004	/* High Error Address */
-
-#define IOC4_SIO_IR	        0x008	/* SIO Interrupt Register */
-#define IOC4_OTHER_IR	        0x00C	/* Other Interrupt Register */
-
-/* These registers are read-only for general kernel code. To modify
- * them use the functions in ioc4.c
- */
-#define IOC4_SIO_IES_RO         0x010	/* SIO Interrupt Enable Set Reg */
-#define IOC4_OTHER_IES_RO       0x014	/* Other Interrupt Enable Set Reg */
-#define IOC4_SIO_IEC_RO         0x018	/* SIO Interrupt Enable Clear Reg */
-#define IOC4_OTHER_IEC_RO       0x01C	/* Other Interrupt Enable Clear Reg */
-
-#define IOC4_SIO_CR	        0x020	/* SIO Control Reg */
-#define IOC4_INT_OUT	        0x028	/* INT_OUT Reg (realtime interrupt) */
-#define IOC4_GPCR_S	        0x030	/* GenericPIO Cntrl Set Register */
-#define IOC4_GPCR_C	        0x034	/* GenericPIO Cntrl Clear Register */
-#define IOC4_GPDR	        0x038	/* GenericPIO Data Register */
-#define IOC4_GPPR_0	        0x040	/* GenericPIO Pin Registers */
-#define IOC4_GPPR_OFF	        0x4
-#define IOC4_GPPR(x)	        (IOC4_GPPR_0+(x)*IOC4_GPPR_OFF)
-
-/* ATAPI Registers */
-#define IOC4_ATA_0              0x100	/* Data w/timing */
-#define IOC4_ATA_1              0x104	/* Error/Features w/timing */
-#define IOC4_ATA_2              0x108	/* Sector Count w/timing */
-#define IOC4_ATA_3              0x10C	/* Sector Number w/timing */
-#define IOC4_ATA_4              0x110   /* Cyliner Low w/timing */
-#define IOC4_ATA_5              0x114	/* Cylinder High w/timing */
-#define IOC4_ATA_6              0x118	/* Device/Head w/timing */
-#define IOC4_ATA_7              0x11C	/* Status/Command w/timing */
-#define IOC4_ATA_0_AUX          0x120	/* Aux Status/Device Cntrl w/timing */
-#define IOC4_ATA_TIMING       	0x140	/* Timing value register 0 */
-#define IOC4_ATA_DMA_PTR_L      0x144   /* Low Memory Pointer to DMA List */
-#define IOC4_ATA_DMA_PTR_H      0x148   /* High Memory Pointer to DMA List */
-#define IOC4_ATA_DMA_ADDR_L     0x14C   /* Low Memory DMA Address */
-#define IOC4_ATA_DMA_ADDR_H     0x150   /* High Memory DMA Addresss */
-#define IOC4_ATA_BC_DEV         0x154	/* DMA Byte Count at Device */
-#define IOC4_ATA_BC_MEM         0x158	/* DMA Byte Count at Memory */
-#define IOC4_ATA_DMA_CTRL       0x15C	/* DMA Control/Status */
-
-/* Keyboard and Mouse Registers */
-#define IOC4_KM_CSR	        0x200	/* Kbd and Mouse Cntrl/Status Reg */
-#define IOC4_K_RD	        0x204	/* Kbd Read Data Register */
-#define IOC4_M_RD	        0x208	/* Mouse Read Data Register */
-#define IOC4_K_WD	        0x20C	/* Kbd Write Data Register */
-#define IOC4_M_WD	        0x210	/* Mouse Write Data Register */
-
-/* Serial Port Registers used for DMA mode serial I/O */
-#define IOC4_SBBR01_H	        0x300	/* Serial Port Ring Buffers 
-                                           Base Reg High for Channels 0 1*/
-#define IOC4_SBBR01_L	        0x304	/* Serial Port Ring Buffers 
-                                           Base Reg Low for Channels 0 1 */
-#define IOC4_SBBR23_H	        0x308	/* Serial Port Ring Buffers 
-                                           Base Reg High for Channels 2 3*/
-#define IOC4_SBBR23_L	        0x30C	/* Serial Port Ring Buffers 
-                                           Base Reg Low for Channels 2 3 */
-
-#define IOC4_SSCR_0	        0x310	/* Serial Port 0 Control */
-#define IOC4_STPIR_0	        0x314	/* Serial Port 0 TX Produce */
-#define IOC4_STCIR_0	        0x318	/* Serial Port 0 TX Consume */
-#define IOC4_SRPIR_0	        0x31C	/* Serial Port 0 RX Produce */
-#define IOC4_SRCIR_0	        0x320	/* Serial Port 0 RX Consume */
-#define IOC4_SRTR_0	        0x324	/* Serial Port 0 Receive Timer Reg */
-#define IOC4_SHADOW_0		0x328	/* Serial Port 0 16550 Shadow Reg */
-
-#define IOC4_SSCR_1	        0x32C	/* Serial Port 1 Control */
-#define IOC4_STPIR_1	        0x330	/* Serial Port 1 TX Produce */
-#define IOC4_STCIR_1	        0x334	/* Serial Port 1 TX Consume */
-#define IOC4_SRPIR_1	        0x338   /* Serial Port 1 RX Produce */
-#define IOC4_SRCIR_1	        0x33C	/* Serial Port 1 RX Consume */
-#define IOC4_SRTR_1	        0x340	/* Serial Port 1 Receive Timer Reg */
-#define IOC4_SHADOW_1		0x344	/* Serial Port 1 16550 Shadow Reg */
-
-#define IOC4_SSCR_2	        0x348	/* Serial Port 2 Control */
-#define IOC4_STPIR_2	        0x34C	/* Serial Port 2 TX Produce */
-#define IOC4_STCIR_2	        0x350	/* Serial Port 2 TX Consume */
-#define IOC4_SRPIR_2	        0x354	/* Serial Port 2 RX Produce */
-#define IOC4_SRCIR_2	        0x358	/* Serial Port 2 RX Consume */
-#define IOC4_SRTR_2	        0x35C	/* Serial Port 2 Receive Timer Reg */
-#define IOC4_SHADOW_2		0x360	/* Serial Port 2 16550 Shadow Reg */
-
-#define IOC4_SSCR_3	        0x364	/* Serial Port 3 Control */
-#define IOC4_STPIR_3	        0x368	/* Serial Port 3 TX Produce */
-#define IOC4_STCIR_3	        0x36C	/* Serial Port 3 TX Consume */
-#define IOC4_SRPIR_3	        0x370	/* Serial Port 3 RX Produce */
-#define IOC4_SRCIR_3	        0x374	/* Serial Port 3 RX Consume */
-#define IOC4_SRTR_3	        0x378	/* Serial Port 3 Receive Timer Reg */
-#define IOC4_SHADOW_3		0x37C	/* Serial Port 3 16550 Shadow Reg */
-
-#define IOC4_UART0_BASE         0x380   /* UART 0 */
-#define IOC4_UART1_BASE         0x388   /* UART 1 */
-#define IOC4_UART2_BASE         0x390   /* UART 2 */
-#define IOC4_UART3_BASE         0x398   /* UART 3 */
-
-/* Private page address aliases for usermode mapping */
-#define IOC4_INT_OUT_P	        0x04000	/* INT_OUT Reg */
-
-#define IOC4_SSCR_0_P	        0x08000 /* Serial Port 0 */
-#define IOC4_STPIR_0_P	        0x08004
-#define IOC4_STCIR_0_P	        0x08008	/* (read-only) */
-#define IOC4_SRPIR_0_P	        0x0800C	/* (read-only) */
-#define IOC4_SRCIR_0_P	        0x08010
-#define IOC4_SRTR_0_P	        0x08014
-#define IOC4_UART_LSMSMCR_0_P   0x08018	/* (read-only) */
-
-#define IOC4_SSCR_1_P	        0x0C000	/* Serial Port 1 */
-#define IOC4_STPIR_1_P	        0x0C004
-#define IOC4_STCIR_1_P	        0x0C008	/* (read-only) */
-#define IOC4_SRPIR_1_P	        0x0C00C	/* (read-only) */
-#define IOC4_SRCIR_1_P	        0x0C010
-#define IOC4_SRTR_1_P	        0x0C014
-#define IOC4_UART_LSMSMCR_1_P   0x0C018	/* (read-only) */
-
-#define IOC4_SSCR_2_P	        0x10000	/* Serial Port 2 */
-#define IOC4_STPIR_2_P	        0x10004
-#define IOC4_STCIR_2_P	        0x10008	/* (read-only) */
-#define IOC4_SRPIR_2_P	        0x1000C	/* (read-only) */
-#define IOC4_SRCIR_2_P	        0x10010
-#define IOC4_SRTR_2_P	        0x10014
-#define IOC4_UART_LSMSMCR_2_P   0x10018	/* (read-only) */
-
-#define IOC4_SSCR_3_P	        0x14000	/* Serial Port 3 */
-#define IOC4_STPIR_3_P	        0x14004
-#define IOC4_STCIR_3_P	        0x14008	/* (read-only) */
-#define IOC4_SRPIR_3_P	        0x1400C	/* (read-only) */
-#define IOC4_SRCIR_3_P	        0x14010
-#define IOC4_SRTR_3_P	        0x14014
-#define IOC4_UART_LSMSMCR_3_P   0x14018	/* (read-only) */
-
-#define IOC4_ALIAS_PAGE_SIZE	0x4000
-
-/* Interrupt types */
-typedef enum ioc4_intr_type_e {
-    ioc4_sio_intr_type,
-    ioc4_other_intr_type,
-    ioc4_num_intr_types
-} ioc4_intr_type_t;
-#define ioc4_first_intr_type    ioc4_sio_intr_type
-
-/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
-#define IOC4_SIO_IR_S0_TX_MT		0x00000001 /* Serial port 0 TX empty */
-#define IOC4_SIO_IR_S0_RX_FULL		0x00000002 /* Port 0 RX buf full */
-#define IOC4_SIO_IR_S0_RX_HIGH		0x00000004 /* Port 0 RX hiwat */
-#define IOC4_SIO_IR_S0_RX_TIMER		0x00000008 /* Port 0 RX timeout */
-#define IOC4_SIO_IR_S0_DELTA_DCD	0x00000010 /* Port 0 delta DCD */
-#define IOC4_SIO_IR_S0_DELTA_CTS	0x00000020 /* Port 0 delta CTS */
-#define IOC4_SIO_IR_S0_INT	        0x00000040 /* Port 0 pass-thru intr */
-#define IOC4_SIO_IR_S0_TX_EXPLICIT	0x00000080 /* Port 0 explicit TX thru */
-#define IOC4_SIO_IR_S1_TX_MT		0x00000100 /* Serial port 1 */
-#define IOC4_SIO_IR_S1_RX_FULL		0x00000200 /* */
-#define IOC4_SIO_IR_S1_RX_HIGH		0x00000400 /* */
-#define IOC4_SIO_IR_S1_RX_TIMER		0x00000800 /* */
-#define IOC4_SIO_IR_S1_DELTA_DCD	0x00001000 /* */
-#define IOC4_SIO_IR_S1_DELTA_CTS	0x00002000 /* */
-#define IOC4_SIO_IR_S1_INT		0x00004000 /* */
-#define IOC4_SIO_IR_S1_TX_EXPLICIT	0x00008000 /* */
-#define IOC4_SIO_IR_S2_TX_MT		0x00010000 /* Serial port 2 */
-#define IOC4_SIO_IR_S2_RX_FULL		0x00020000 /* */
-#define IOC4_SIO_IR_S2_RX_HIGH		0x00040000 /* */
-#define IOC4_SIO_IR_S2_RX_TIMER		0x00080000 /* */
-#define IOC4_SIO_IR_S2_DELTA_DCD	0x00100000 /* */
-#define IOC4_SIO_IR_S2_DELTA_CTS	0x00200000 /* */
-#define IOC4_SIO_IR_S2_INT		0x00400000 /* */
-#define IOC4_SIO_IR_S2_TX_EXPLICIT	0x00800000 /* */
-#define IOC4_SIO_IR_S3_TX_MT		0x01000000 /* Serial port 3 */
-#define IOC4_SIO_IR_S3_RX_FULL		0x02000000 /* */
-#define IOC4_SIO_IR_S3_RX_HIGH		0x04000000 /* */
-#define IOC4_SIO_IR_S3_RX_TIMER		0x08000000 /* */
-#define IOC4_SIO_IR_S3_DELTA_DCD	0x10000000 /* */
-#define IOC4_SIO_IR_S3_DELTA_CTS	0x20000000 /* */
-#define IOC4_SIO_IR_S3_INT		0x40000000 /* */
-#define IOC4_SIO_IR_S3_TX_EXPLICIT	0x80000000 /* */
-
-/* Per device interrupt masks */
-#define IOC4_SIO_IR_S0		(IOC4_SIO_IR_S0_TX_MT | \
-				 IOC4_SIO_IR_S0_RX_FULL | \
-				 IOC4_SIO_IR_S0_RX_HIGH | \
-				 IOC4_SIO_IR_S0_RX_TIMER | \
-				 IOC4_SIO_IR_S0_DELTA_DCD | \
-				 IOC4_SIO_IR_S0_DELTA_CTS | \
-				 IOC4_SIO_IR_S0_INT | \
-				 IOC4_SIO_IR_S0_TX_EXPLICIT)
-#define IOC4_SIO_IR_S1		(IOC4_SIO_IR_S1_TX_MT | \
-				 IOC4_SIO_IR_S1_RX_FULL | \
-				 IOC4_SIO_IR_S1_RX_HIGH | \
-				 IOC4_SIO_IR_S1_RX_TIMER | \
-				 IOC4_SIO_IR_S1_DELTA_DCD | \
-				 IOC4_SIO_IR_S1_DELTA_CTS | \
-				 IOC4_SIO_IR_S1_INT | \
-				 IOC4_SIO_IR_S1_TX_EXPLICIT)
-#define IOC4_SIO_IR_S2		(IOC4_SIO_IR_S2_TX_MT | \
-				 IOC4_SIO_IR_S2_RX_FULL | \
-				 IOC4_SIO_IR_S2_RX_HIGH | \
-				 IOC4_SIO_IR_S2_RX_TIMER | \
-				 IOC4_SIO_IR_S2_DELTA_DCD | \
-				 IOC4_SIO_IR_S2_DELTA_CTS | \
-				 IOC4_SIO_IR_S2_INT | \
-				 IOC4_SIO_IR_S2_TX_EXPLICIT)
-#define IOC4_SIO_IR_S3		(IOC4_SIO_IR_S3_TX_MT | \
-				 IOC4_SIO_IR_S3_RX_FULL | \
-				 IOC4_SIO_IR_S3_RX_HIGH | \
-				 IOC4_SIO_IR_S3_RX_TIMER | \
-				 IOC4_SIO_IR_S3_DELTA_DCD | \
-				 IOC4_SIO_IR_S3_DELTA_CTS | \
-				 IOC4_SIO_IR_S3_INT | \
-				 IOC4_SIO_IR_S3_TX_EXPLICIT)
-
-/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
-#define IOC4_OTHER_IR_ATA_INT           0x00000001 /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR        0x00000002 /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR         0x00000004 /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR         0x00000008 /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR         0x00000010 /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR         0x00000020 /* Port 3 PCI error */
-#define IOC4_OTHER_IR_KBD_INT		0x00000040 /* Kbd/mouse intr */
-#define IOC4_OTHER_IR_ATA_DMAINT        0x00000089 /* ATAPI DMA intr */
-#define IOC4_OTHER_IR_RT_INT		0x00800000 /* RT output pulse */
-#define IOC4_OTHER_IR_GEN_INT1		0x02000000 /* RT input pulse */
-#define IOC4_OTHER_IR_GEN_INT_SHIFT	        25
-
-/* Per device interrupt masks */
-#define IOC4_OTHER_IR_ATA       (IOC4_OTHER_IR_ATA_INT | \
-				 IOC4_OTHER_IR_ATA_MEMERR | \
-				 IOC4_OTHER_IR_ATA_DMAINT)
-#define IOC4_OTHER_IR_RT	(IOC4_OTHER_IR_RT_INT | IOC4_OTHER_IR_GEN_INT1)
-
-/* Macro to load pending interrupts */
-#define IOC4_PENDING_SIO_INTRS(mem)     (PCI_INW(&((mem)->sio_ir)) & \
-				         PCI_INW(&((mem)->sio_ies_ro)))
-#define IOC4_PENDING_OTHER_INTRS(mem)   (PCI_INW(&((mem)->other_ir)) & \
-				         PCI_INW(&((mem)->other_ies_ro)))
-
-/* Bitmasks for IOC4_SIO_CR */
-#define IOC4_SIO_SR_CMD_PULSE		0x00000004 /* Byte bus strobe length */
-#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0
-#define IOC4_SIO_CR_ARB_DIAG		0x00000070 /* Current non-ATA PCI bus
-                                                      requester (ro) */
-#define IOC4_SIO_CR_ARB_DIAG_TX0	0x00000000
-#define IOC4_SIO_CR_ARB_DIAG_RX0	0x00000010
-#define IOC4_SIO_CR_ARB_DIAG_TX1	0x00000020
-#define IOC4_SIO_CR_ARB_DIAG_RX1	0x00000030
-#define IOC4_SIO_CR_ARB_DIAG_TX2	0x00000040
-#define IOC4_SIO_CR_ARB_DIAG_RX2	0x00000050
-#define IOC4_SIO_CR_ARB_DIAG_TX3	0x00000060
-#define IOC4_SIO_CR_ARB_DIAG_RX3	0x00000070
-#define IOC4_SIO_CR_SIO_DIAG_IDLE	0x00000080 /* 0 -> active request among
-                                                      serial ports (ro) */
-#define IOC4_SIO_CR_ATA_DIAG_IDLE	0x00000100 /* 0 -> active request from
-                                                      ATA port */
-#define IOC4_SIO_CR_ATA_DIAG_ACTIVE     0x00000200 /* 1 -> ATA request is winner */ 
-
-/* Bitmasks for IOC4_INT_OUT */
-#define IOC4_INT_OUT_COUNT	        0x0000ffff /* Pulse interval timer */
-#define IOC4_INT_OUT_MODE	        0x00070000 /* Mode mask */
-#define IOC4_INT_OUT_MODE_0             0x00000000 /* Set output to 0 */
-#define IOC4_INT_OUT_MODE_1             0x00040000 /* Set output to 1 */
-#define IOC4_INT_OUT_MODE_1PULSE        0x00050000 /* Send 1 pulse */
-#define IOC4_INT_OUT_MODE_PULSES        0x00060000 /* Send 1 pulse every interval */
-#define IOC4_INT_OUT_MODE_SQW           0x00070000 /* Toggle output every interval */
-#define IOC4_INT_OUT_DIAG	        0x40000000 /* Diag mode */
-#define IOC4_INT_OUT_INT_OUT            0x80000000 /* Current state of INT_OUT */
-
-/* Time constants for IOC4_INT_OUT */
-#define IOC4_INT_OUT_NS_PER_TICK        (15 * 520) /* 15 ns PCI clock, multi=520 */
-#define IOC4_INT_OUT_TICKS_PER_PULSE             3 /* Outgoing pulse lasts 3
-                                                      ticks */
-#define IOC4_INT_OUT_US_TO_COUNT(x)	           /* Convert uS to a count value */ \
-	(((x) * 10 + IOC4_INT_OUT_NS_PER_TICK / 200) *	\
-	 100 / IOC4_INT_OUT_NS_PER_TICK - 1)
-#define IOC4_INT_OUT_COUNT_TO_US(x)	           /* Convert count value to uS */ \
-	(((x) + 1) * IOC4_INT_OUT_NS_PER_TICK / 1000)
-#define IOC4_INT_OUT_MIN_TICKS                   3 /* Min period is width of
-                                                      pulse in "ticks" */
-#define IOC4_INT_OUT_MAX_TICKS  IOC4_INT_OUT_COUNT /* Largest possible count */
-
-/* Bitmasks for IOC4_GPCR */
-#define IOC4_GPCR_DIR	                0x000000ff /* Tristate pin in or out */
-#define IOC4_GPCR_DIR_PIN(x)              (1<<(x)) /* Access one of the DIR bits */
-#define IOC4_GPCR_EDGE	                0x0000ff00 /* Extint edge or level
-                                                      sensitive */
-#define IOC4_GPCR_EDGE_PIN(x)        (1<<((x)+7 )) /* Access one of the EDGE bits */
-
-/* Values for IOC4_GPCR */
-#define IOC4_GPCR_INT_OUT_EN            0x00100000 /* Enable INT_OUT to pin 0 */
-#define IOC4_GPCR_DIR_SER0_XCVR         0x00000010 /* Port 0 Transceiver select
-                                                      enable */
-#define IOC4_GPCR_DIR_SER1_XCVR         0x00000020 /* Port 1 Transceiver select
-                                                      enable */
-#define IOC4_GPCR_DIR_SER2_XCVR         0x00000040 /* Port 2 Transceiver select
-                                                      enable */
-#define IOC4_GPCR_DIR_SER3_XCVR         0x00000080 /* Port 3 Transceiver select
-                                                      enable */
-
-/* Defs for some of the generic I/O pins */
-#define IOC4_GPCR_UART0_MODESEL	              0x10 /* Pin is output to port 0
-                                                      mode sel */
-#define IOC4_GPCR_UART1_MODESEL	              0x20 /* Pin is output to port 1
-                                                      mode sel */
-#define IOC4_GPCR_UART2_MODESEL	              0x40 /* Pin is output to port 2
-                                                      mode sel */
-#define IOC4_GPCR_UART3_MODESEL	              0x80 /* Pin is output to port 3
-                                                      mode sel */
-
-#define IOC4_GPPR_UART0_MODESEL_PIN	         4 /* GIO pin controlling
-                                                      uart 0 mode select */
-#define IOC4_GPPR_UART1_MODESEL_PIN	         5 /* GIO pin controlling
-                                                      uart 1 mode select */
-#define IOC4_GPPR_UART2_MODESEL_PIN	         6 /* GIO pin controlling
-                                                      uart 2 mode select */
-#define IOC4_GPPR_UART3_MODESEL_PIN	         7 /* GIO pin controlling
-                                                      uart 3 mode select */
-
-/* Bitmasks for IOC4_ATA_TIMING */
-#define IOC4_ATA_TIMING_ADR_SETUP	0x00000003 /* Clocks of addr set-up */
-#define IOC4_ATA_TIMING_PULSE_WIDTH	0x000001f8 /* Clocks of read or write
-                                                      pulse width */
-#define IOC4_ATA_TIMING_RECOVERY	0x0000fe00 /* Clocks before next read
-                                                      or write */
-#define IOC4_ATA_TIMING_USE_IORDY	0x00010000 /* PIO uses IORDY */
-
-/* Bitmasks for address list elements pointed to by IOC4_ATA_DMA_PTR_<L|H> */
-#define IOC4_ATA_ALE_DMA_ADDRESS        0xfffffffffffffffe
-
-/* Bitmasks for byte count list elements pointed to by IOC4_ATA_DMA_PTR_<L|H> */
-#define IOC4_ATA_BCLE_BYTE_COUNT        0x000000000000fffe
-#define IOC4_ATA_BCLE_LIST_END          0x0000000080000000
-
-/* Bitmasks for IOC4_ATA_BC_<DEV|MEM> */
-#define IOC4_ATA_BC_BYTE_CNT            0x0001fffe /* Byte count */
-
-/* Bitmasks for IOC4_ATA_DMA_CTRL */
-#define IOC4_ATA_DMA_CTRL_STRAT		0x00000001 /* 1 -> start DMA engine */
-#define IOC4_ATA_DMA_CTRL_STOP		0x00000002 /* 1 -> stop DMA engine */
-#define IOC4_ATA_DMA_CTRL_DIR		0x00000004 /* 1 -> ATA bus data copied
-                                                      to memory */
-#define IOC4_ATA_DMA_CTRL_ACTIVE	0x00000008 /* DMA channel is active */
-#define IOC4_ATA_DMA_CTRL_MEM_ERROR	0x00000010 /* DMA engine encountered 
-						      a PCI error */
-/* Bitmasks for IOC4_KM_CSR */
-#define IOC4_KM_CSR_K_WRT_PEND  0x00000001 /* Kbd port xmitting or resetting */
-#define IOC4_KM_CSR_M_WRT_PEND  0x00000002 /* Mouse port xmitting or resetting */
-#define IOC4_KM_CSR_K_LCB       0x00000004 /* Line Cntrl Bit for last KBD write */
-#define IOC4_KM_CSR_M_LCB       0x00000008 /* Same for mouse */
-#define IOC4_KM_CSR_K_DATA      0x00000010 /* State of kbd data line */
-#define IOC4_KM_CSR_K_CLK       0x00000020 /* State of kbd clock line */
-#define IOC4_KM_CSR_K_PULL_DATA 0x00000040 /* Pull kbd data line low */
-#define IOC4_KM_CSR_K_PULL_CLK  0x00000080 /* Pull kbd clock line low */
-#define IOC4_KM_CSR_M_DATA      0x00000100 /* State of mouse data line */
-#define IOC4_KM_CSR_M_CLK       0x00000200 /* State of mouse clock line */
-#define IOC4_KM_CSR_M_PULL_DATA 0x00000400 /* Pull mouse data line low */
-#define IOC4_KM_CSR_M_PULL_CLK  0x00000800 /* Pull mouse clock line low */
-#define IOC4_KM_CSR_EMM_MODE	0x00001000 /* Emulation mode */
-#define IOC4_KM_CSR_SIM_MODE	0x00002000 /* Clock X8 */
-#define IOC4_KM_CSR_K_SM_IDLE   0x00004000 /* Keyboard is idle */
-#define IOC4_KM_CSR_M_SM_IDLE   0x00008000 /* Mouse is idle */
-#define IOC4_KM_CSR_K_TO	0x00010000 /* Keyboard trying to send/receive */
-#define IOC4_KM_CSR_M_TO        0x00020000 /* Mouse trying to send/receive */
-#define IOC4_KM_CSR_K_TO_EN     0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN =
-                                              cause SIO_IR to assert */
-#define IOC4_KM_CSR_M_TO_EN	0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN =
-                                              cause SIO_IR to assert */
-#define IOC4_KM_CSR_K_CLAMP_ONE	0x00100000 /* Pull K_CLK low after rec. one char */
-#define IOC4_KM_CSR_M_CLAMP_ONE	0x00200000 /* Pull M_CLK low after rec. one char */
-#define IOC4_KM_CSR_K_CLAMP_THREE \
-                           	0x00400000 /* Pull K_CLK low after rec. three chars */
-#define IOC4_KM_CSR_M_CLAMP_THREE \
-                            	0x00800000 /* Pull M_CLK low after rec. three char */
-
-/* Bitmasks for IOC4_K_RD and IOC4_M_RD */
-#define IOC4_KM_RD_DATA_2       0x000000ff /* 3rd char recvd since last read */
-#define IOC4_KM_RD_DATA_2_SHIFT          0
-#define IOC4_KM_RD_DATA_1       0x0000ff00 /* 2nd char recvd since last read */
-#define IOC4_KM_RD_DATA_1_SHIFT          8
-#define IOC4_KM_RD_DATA_0	0x00ff0000 /* 1st char recvd since last read */
-#define IOC4_KM_RD_DATA_0_SHIFT         16
-#define IOC4_KM_RD_FRAME_ERR_2  0x01000000 /* Framing or parity error in byte 2 */
-#define IOC4_KM_RD_FRAME_ERR_1  0x02000000 /* Same for byte 1 */
-#define IOC4_KM_RD_FRAME_ERR_0  0x04000000 /* Same for byte 0 */
-
-#define IOC4_KM_RD_KBD_MSE      0x08000000 /* 0 if from kbd, 1 if from mouse */
-#define IOC4_KM_RD_OFLO	        0x10000000 /* 4th char recvd before this read */
-#define IOC4_KM_RD_VALID_2      0x20000000 /* DATA_2 valid */
-#define IOC4_KM_RD_VALID_1      0x40000000 /* DATA_1 valid */
-#define IOC4_KM_RD_VALID_0      0x80000000 /* DATA_0 valid */
-#define IOC4_KM_RD_VALID_ALL    (IOC4_KM_RD_VALID_0 | IOC4_KM_RD_VALID_1 | \
-                                 IOC4_KM_RD_VALID_2)
-
-/* Bitmasks for IOC4_K_WD & IOC4_M_WD */
-#define IOC4_KM_WD_WRT_DATA     0x000000ff /* Write to keyboard/mouse port */
-#define IOC4_KM_WD_WRT_DATA_SHIFT        0
-
-/* Bitmasks for serial RX status byte */
-#define IOC4_RXSB_OVERRUN       0x01       /* Char(s) lost */
-#define IOC4_RXSB_PAR_ERR	0x02	   /* Parity error */
-#define IOC4_RXSB_FRAME_ERR	0x04	   /* Framing error */
-#define IOC4_RXSB_BREAK	        0x08	   /* Break character */
-#define IOC4_RXSB_CTS	        0x10	   /* State of CTS */
-#define IOC4_RXSB_DCD	        0x20	   /* State of DCD */
-#define IOC4_RXSB_MODEM_VALID   0x40	   /* DCD, CTS, and OVERRUN are valid */
-#define IOC4_RXSB_DATA_VALID    0x80	   /* Data byte, FRAME_ERR PAR_ERR & BREAK valid */
-
-/* Bitmasks for serial TX control byte */
-#define IOC4_TXCB_INT_WHEN_DONE 0x20       /* Interrupt after this byte is sent */
-#define IOC4_TXCB_INVALID	0x00	   /* Byte is invalid */
-#define IOC4_TXCB_VALID	        0x40	   /* Byte is valid */
-#define IOC4_TXCB_MCR	        0x80	   /* Data<7:0> to modem control register */
-#define IOC4_TXCB_DELAY	        0xc0	   /* Delay data<7:0> mSec */
-
-/* Bitmasks for IOC4_SBBR_L */
-#define IOC4_SBBR_L_SIZE	0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */
-#define IOC4_SBBR_L_BASE	0xfffff000 /* Lower serial ring base addr */
-
-/* Bitmasks for IOC4_SSCR_<3:0> */
-#define IOC4_SSCR_RX_THRESHOLD  0x000001ff /* Hiwater mark */
-#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */
-#define IOC4_SSCR_HFC_EN	0x00020000 /* Hardware flow control enabled */
-#define IOC4_SSCR_RX_RING_DCD   0x00040000 /* Post RX record on delta-DCD */
-#define IOC4_SSCR_RX_RING_CTS   0x00080000 /* Post RX record on delta-CTS */
-#define IOC4_SSCR_DIAG	        0x00200000 /* Bypass clock divider for sim */
-#define IOC4_SSCR_RX_DRAIN	0x08000000 /* Drain RX buffer to memory */
-#define IOC4_SSCR_DMA_EN	0x10000000 /* Enable ring buffer DMA */
-#define IOC4_SSCR_DMA_PAUSE	0x20000000 /* Pause DMA */
-#define IOC4_SSCR_PAUSE_STATE   0x40000000 /* Sets when PAUSE takes effect */
-#define IOC4_SSCR_RESET	        0x80000000 /* Reset DMA channels */
-
-/* All producer/comsumer pointers are the same bitfield */
-#define IOC4_PROD_CONS_PTR_4K   0x00000ff8 /* For 4K buffers */
-#define IOC4_PROD_CONS_PTR_1K   0x000003f8 /* For 1K buffers */
-#define IOC4_PROD_CONS_PTR_OFF           3
-
-/* Bitmasks for IOC4_STPIR_<3:0> */
-/* Reserved for future register definitions */
-
-/* Bitmasks for IOC4_STCIR_<3:0> */
-#define IOC4_STCIR_BYTE_CNT     0x0f000000 /* Bytes in unpacker */
-#define IOC4_STCIR_BYTE_CNT_SHIFT       24
-
-/* Bitmasks for IOC4_SRPIR_<3:0> */
-#define IOC4_SRPIR_BYTE_CNT	0x0f000000 /* Bytes in packer */
-#define IOC4_SRPIR_BYTE_CNT_SHIFT       24
-
-/* Bitmasks for IOC4_SRCIR_<3:0> */
-#define IOC4_SRCIR_ARM	        0x80000000 /* Arm RX timer */
-
-/* Bitmasks for IOC4_SHADOW_<3:0> */
-#define IOC4_SHADOW_DR          0x00000001  /* Data ready */
-#define IOC4_SHADOW_OE          0x00000002  /* Overrun error */
-#define IOC4_SHADOW_PE          0x00000004  /* Parity error */
-#define IOC4_SHADOW_FE          0x00000008  /* Framing error */
-#define IOC4_SHADOW_BI          0x00000010  /* Break interrupt */
-#define IOC4_SHADOW_THRE        0x00000020  /* Xmit holding register empty */
-#define IOC4_SHADOW_TEMT        0x00000040  /* Xmit shift register empty */
-#define IOC4_SHADOW_RFCE        0x00000080  /* Char in RX fifo has an error */
-#define IOC4_SHADOW_DCTS        0x00010000  /* Delta clear to send */
-#define IOC4_SHADOW_DDCD        0x00080000  /* Delta data carrier detect */
-#define IOC4_SHADOW_CTS         0x00100000  /* Clear to send */
-#define IOC4_SHADOW_DCD         0x00800000  /* Data carrier detect */
-#define IOC4_SHADOW_DTR         0x01000000  /* Data terminal ready */
-#define IOC4_SHADOW_RTS         0x02000000  /* Request to send */
-#define IOC4_SHADOW_OUT1        0x04000000  /* 16550 OUT1 bit */
-#define IOC4_SHADOW_OUT2        0x08000000  /* 16550 OUT2 bit */
-#define IOC4_SHADOW_LOOP        0x10000000  /* Loopback enabled */
-
-/* Bitmasks for IOC4_SRTR_<3:0> */
-#define IOC4_SRTR_CNT	        0x00000fff /* Reload value for RX timer */
-#define IOC4_SRTR_CNT_VAL	0x0fff0000 /* Current value of RX timer */
-#define IOC4_SRTR_CNT_VAL_SHIFT         16
-#define IOC4_SRTR_HZ                 16000 /* SRTR clock frequency */
-
-/* Serial port register map used for DMA and PIO serial I/O */
-typedef volatile struct ioc4_serialregs {
-    ioc4reg_t		    sscr;
-    ioc4reg_t		    stpir;
-    ioc4reg_t		    stcir;
-    ioc4reg_t		    srpir;
-    ioc4reg_t		    srcir;
-    ioc4reg_t		    srtr;
-    ioc4reg_t		    shadow;
-} ioc4_sregs_t;
-
-/* IOC4 UART register map */
-typedef volatile struct ioc4_uartregs {
-    union {
-        char                    rbr;    /* read only, DLAB == 0 */
-        char                    thr;    /* write only, DLAB == 0 */
-        char                    dll;    /* DLAB == 1 */
-    } u1;
-    union {
-        char                    ier;    /* DLAB == 0 */
-        char                    dlm;    /* DLAB == 1 */
-    } u2;
-    union {
-        char                    iir;    /* read only */
-        char                    fcr;    /* write only */
-    } u3;
-    char                    i4u_lcr;
-    char                    i4u_mcr;
-    char                    i4u_lsr;
-    char                    i4u_msr;
-    char                    i4u_scr;
-} ioc4_uart_t;
-
-#define i4u_rbr u1.rbr
-#define i4u_thr u1.thr
-#define i4u_dll u1.dll
-#define i4u_ier u2.ier
-#define i4u_dlm u2.dlm
-#define i4u_iir u3.iir
-#define i4u_fcr u3.fcr
-
-/* PCI config space register map */
-typedef volatile struct ioc4_configregs {
-    ioc4reg_t		    pci_id;
-    ioc4reg_t		    pci_scr;
-    ioc4reg_t		    pci_rev;
-    ioc4reg_t		    pci_lat;
-    ioc4reg_t		    pci_bar0;
-    ioc4reg_t		    pci_bar1;
-    ioc4reg_t               pci_bar2_not_implemented;
-    ioc4reg_t               pci_cis_ptr_not_implemented;
-    ioc4reg_t		    pci_sidv;
-    ioc4reg_t		    pci_rom_bar_not_implemented;
-    ioc4reg_t		    pci_cap;
-    ioc4reg_t		    pci_rsv;
-    ioc4reg_t		    pci_latgntint;
-
-    char                    pci_fill1[0x58 - 0x3c - 4];
-
-    ioc4reg_t               pci_pcix;
-    ioc4reg_t               pci_pcixstatus;
-} ioc4_cfg_t;
-
-/* PCI memory space register map addressed using pci_bar0 */
-typedef volatile struct ioc4_memregs {
-
-    /* Miscellaneous IOC4  registers */
-    ioc4reg_t		    pci_err_addr_l;
-    ioc4reg_t		    pci_err_addr_h;
-    ioc4reg_t		    sio_ir;
-    ioc4reg_t		    other_ir;
-
-    /* These registers are read-only for general kernel code.  To
-     * modify them use the functions in ioc4.c.
-     */
-    ioc4reg_t		    sio_ies_ro;
-    ioc4reg_t		    other_ies_ro;
-    ioc4reg_t		    sio_iec_ro;
-    ioc4reg_t		    other_iec_ro;
-    ioc4reg_t		    sio_cr;
-    ioc4reg_t		    misc_fill1;
-    ioc4reg_t		    int_out;
-    ioc4reg_t		    misc_fill2;
-    ioc4reg_t		    gpcr_s;
-    ioc4reg_t		    gpcr_c;
-    ioc4reg_t		    gpdr;
-    ioc4reg_t		    misc_fill3;
-    ioc4reg_t		    gppr_0;
-    ioc4reg_t		    gppr_1;
-    ioc4reg_t		    gppr_2;
-    ioc4reg_t		    gppr_3;
-    ioc4reg_t		    gppr_4;
-    ioc4reg_t		    gppr_5;
-    ioc4reg_t		    gppr_6;
-    ioc4reg_t		    gppr_7;
-
-    char		    misc_fill4[0x100 - 0x5C - 4];
-
-    /* ATA/ATAP registers */
-    ioc4reg_t		    ata_0;
-    ioc4reg_t		    ata_1;
-    ioc4reg_t		    ata_2;
-    ioc4reg_t		    ata_3;
-    ioc4reg_t		    ata_4;
-    ioc4reg_t		    ata_5;
-    ioc4reg_t		    ata_6;
-    ioc4reg_t		    ata_7;
-    ioc4reg_t		    ata_aux;
-
-    char		    ata_fill1[0x140 - 0x120 - 4];
-
-    ioc4reg_t		    ata_timing;
-    ioc4reg_t		    ata_dma_ptr_l;
-    ioc4reg_t		    ata_dma_ptr_h;
-    ioc4reg_t		    ata_dma_addr_l;
-    ioc4reg_t		    ata_dma_addr_h;
-    ioc4reg_t		    ata_bc_dev;
-    ioc4reg_t		    ata_bc_mem;
-    ioc4reg_t		    ata_dma_ctrl;
-
-    char		    ata_fill2[0x200 - 0x15C - 4];
-
-    /* Keyboard and mouse registers */
-    ioc4reg_t		    km_csr;
-    ioc4reg_t		    k_rd;
-    ioc4reg_t		    m_rd;
-    ioc4reg_t		    k_wd;
-    ioc4reg_t		    m_wd;
-
-    char		    km_fill1[0x300 - 0x210 - 4];
-
-    /* Serial port registers used for DMA serial I/O */
-    ioc4reg_t		    sbbr01_l;
-    ioc4reg_t		    sbbr01_h;
-    ioc4reg_t		    sbbr23_l;
-    ioc4reg_t		    sbbr23_h;
-
-    ioc4_sregs_t	    port_0;
-    ioc4_sregs_t	    port_1;
-    ioc4_sregs_t	    port_2;
-    ioc4_sregs_t	    port_3;
-
-    ioc4_uart_t		    uart_0;
-    ioc4_uart_t		    uart_1;
-    ioc4_uart_t		    uart_2;
-    ioc4_uart_t		    uart_3;
-} ioc4_mem_t;
-
-#endif	/* 0 */
-
 /*
  * Bytebus device space
  */
@@ -693,88 +17,4 @@
 #define IOC4_BYTEBUS_DEV2	0xC0000L  /* Addressed using pci_bar0 */
 #define IOC4_BYTEBUS_DEV3	0xE0000L  /* Addressed using pci_bar0 */
 
-#if 0
-/* UART clock speed */
-#define IOC4_SER_XIN_CLK        66000000
-
-typedef enum ioc4_subdevs_e {
-    ioc4_subdev_generic,
-    ioc4_subdev_kbms,
-    ioc4_subdev_tty0,
-    ioc4_subdev_tty1,
-    ioc4_subdev_tty2,
-    ioc4_subdev_tty3,
-    ioc4_subdev_rt,
-    ioc4_nsubdevs
-} ioc4_subdev_t;
-
-/* Subdevice disable bits,
- * from the standard INFO_LBL_SUBDEVS
- */
-#define IOC4_SDB_TTY0		(1 << ioc4_subdev_tty0)
-#define IOC4_SDB_TTY1		(1 << ioc4_subdev_tty1)
-#define IOC4_SDB_TTY2		(1 << ioc4_subdev_tty2)
-#define IOC4_SDB_TTY3		(1 << ioc4_subdev_tty3)
-#define IOC4_SDB_KBMS		(1 << ioc4_subdev_kbms)
-#define IOC4_SDB_RT		(1 << ioc4_subdev_rt)
-#define IOC4_SDB_GENERIC	(1 << ioc4_subdev_generic)
-
-#define IOC4_ALL_SUBDEVS	((1 << ioc4_nsubdevs) - 1)
-
-#define IOC4_SDB_SERIAL		(IOC4_SDB_TTY0 | IOC4_SDB_TTY1 | IOC4_SDB_TTY2 | IOC4_SDB_TTY3)
-
-#define IOC4_STD_SUBDEVS	IOC4_ALL_SUBDEVS
-
-#define IOC4_INTA_SUBDEVS	(IOC4_SDB_SERIAL | IOC4_SDB_KBMS | IOC4_SDB_RT | IOC4_SDB_GENERIC)
-
-extern int		ioc4_subdev_enabled(vertex_hdl_t, ioc4_subdev_t);
-extern void		ioc4_subdev_enables(vertex_hdl_t, ulong_t);
-extern void		ioc4_subdev_enable(vertex_hdl_t, ioc4_subdev_t);
-extern void		ioc4_subdev_disable(vertex_hdl_t, ioc4_subdev_t);
-
-/* Macros to read and write the SIO_IEC and SIO_IES registers (see the
- * comments in ioc4.c for details on why this is necessary
- */
-#define IOC4_W_IES	0
-#define IOC4_W_IEC	1
-extern void		ioc4_write_ireg(void *, ioc4reg_t, int, ioc4_intr_type_t);
-
-#define IOC4_WRITE_IES(ioc4, val, type)	ioc4_write_ireg(ioc4, val, IOC4_W_IES, type)
-#define IOC4_WRITE_IEC(ioc4, val, type)	ioc4_write_ireg(ioc4, val, IOC4_W_IEC, type)
-
-typedef void
-ioc4_intr_func_f	(intr_arg_t, ioc4reg_t);
-
-typedef void
-ioc4_intr_connect_f	(vertex_hdl_t conn_vhdl,
-			 ioc4_intr_type_t,
-			 ioc4reg_t,
-			 ioc4_intr_func_f *,
-			 intr_arg_t info,
-			 vertex_hdl_t owner_vhdl,
-			 vertex_hdl_t intr_dev_vhdl,
-			 int (*)(intr_arg_t));
-
-typedef void
-ioc4_intr_disconnect_f	(vertex_hdl_t conn_vhdl,
-			 ioc4_intr_type_t,
-			 ioc4reg_t,
-			 ioc4_intr_func_f *,
-			 intr_arg_t info,
-			 vertex_hdl_t owner_vhdl);
-
-ioc4_intr_disconnect_f	ioc4_intr_disconnect;
-ioc4_intr_connect_f	ioc4_intr_connect;
-
-extern int		ioc4_is_console(vertex_hdl_t conn_vhdl);
-
-extern void		ioc4_mlreset(ioc4_cfg_t *, ioc4_mem_t *);
-
-extern intr_func_f	ioc4_intr;
-
-extern ioc4_mem_t      *ioc4_mem_ptr(void *ioc4_fastinfo);
-
-typedef ioc4_intr_func_f *ioc4_intr_func_t;
-
-#endif	/* 0 */
-#endif				/* _ASM_IA64_SN_IOC4_H */
+#endif	/* _ASM_IA64_SN_IOC4_H */
--- diff/include/asm-ia64/sn/ioconfig_bus.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/ioconfig_bus.h	2004-02-18 09:04:02.000000000 +0000
@@ -9,19 +9,19 @@
 #ifndef _ASM_IA64_SN_IOCONFIG_BUS_H
 #define _ASM_IA64_SN_IOCONFIG_BUS_H
 
-#define IOCONFIG_PCIBUS "/boot/efi/ioconfig_pcibus"
-#define POUND_CHAR                   '#'
+#define IOCONFIG_PCIBUS	"/boot/efi/ioconfig_pcibus"
+#define POUND_CHAR	'#'
 #define MAX_LINE_LEN	128
 #define MAXPATHLEN	128
 
 struct ioconfig_parm {
 	unsigned long ioconfig_activated;
-        unsigned long number;
-        void *buffer;
+	unsigned long number;
+	void *buffer;
 };
 
-struct  ascii_moduleid{
-                unsigned char   io_moduleid[8]; /* pci path name */
+struct ascii_moduleid {
+	unsigned char   io_moduleid[8]; /* pci path name */
 };
 
 #endif	/* _ASM_IA64_SN_IOCONFIG_BUS_H */
--- diff/include/asm-ia64/sn/ioerror_handling.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/sn/ioerror_handling.h	2004-02-18 09:04:02.000000000 +0000
@@ -11,7 +11,7 @@
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
 
-#if __KERNEL__
+#ifdef __KERNEL__
 
 /*
  * Basic types required for io error handling interfaces.
@@ -155,88 +155,5 @@
 	ERROR_CLASS_BAD_RESP_PKT
 };
 
-typedef uint64_t  error_class_t;
-
-
-/* 
- * Error context which the error action can use.
- */
-typedef void			*error_context_t;
-#define ERROR_CONTEXT_IGNORE	((error_context_t)-1ll)
-
-
-/* 
- * Error action type.
- */
-typedef error_return_code_t 	(*error_action_f)( error_context_t);
-#define ERROR_ACTION_IGNORE	((error_action_f)-1ll)
-
-/* Typical set of error actions */
-typedef struct error_action_set_s {
-	error_action_f		eas_panic;
-	error_action_f		eas_shutdown;
-	error_action_f		eas_abort;
-	error_action_f		eas_retry;
-	error_action_f		eas_failover;
-	error_action_f		eas_log_n_ignore;
-	error_action_f		eas_reset;
-} error_action_set_t;
-
-
-/* Set of priorites for in case mutliple error actions/states
- * are trying to be prescribed for a device.
- * NOTE : The ordering below encapsulates the priorities. Highest value
- * corresponds to highest priority.
- */
-enum error_priority_e {
-	ERROR_PRIORITY_IGNORE,
-	ERROR_PRIORITY_NONE,
-	ERROR_PRIORITY_NORMAL,
-	ERROR_PRIORITY_LOG,
-	ERROR_PRIORITY_FAILOVER,
-	ERROR_PRIORITY_RETRY,
-	ERROR_PRIORITY_ABORT,
-	ERROR_PRIORITY_SHUTDOWN,
-	ERROR_PRIORITY_RESTART,
-	ERROR_PRIORITY_PANIC
-};
-
-typedef uint64_t  error_priority_t;
-
-/* Error action interfaces */
-
-extern error_return_code_t	error_action_set(vertex_hdl_t,
-						 error_action_f,
-						 error_context_t,
-						 error_priority_t);
-extern error_return_code_t	error_action_perform(vertex_hdl_t);
-
-
-#define INFO_LBL_ERROR_SKIP_ENV	"error_skip_env"
-
-#define v_error_skip_env_get(v, l)		\
-hwgraph_info_get_LBL(v, INFO_LBL_ERROR_SKIP_ENV, (arbitrary_info_t *)&l)
-
-#define v_error_skip_env_set(v, l, r)		\
-(r ? 						\
- hwgraph_info_replace_LBL(v, INFO_LBL_ERROR_SKIP_ENV, (arbitrary_info_t)l,0) :\
- hwgraph_info_add_LBL(v, INFO_LBL_ERROR_SKIP_ENV, (arbitrary_info_t)l))
-
-#define v_error_skip_env_clear(v)		\
-hwgraph_info_remove_LBL(v, INFO_LBL_ERROR_SKIP_ENV, 0)
-
-typedef uint64_t		counter_t;
-
-extern counter_t		error_retry_count_get(vertex_hdl_t);
-extern error_return_code_t	error_retry_count_set(vertex_hdl_t,counter_t);
-extern counter_t		error_retry_count_increment(vertex_hdl_t);
-extern counter_t		error_retry_count_decrement(vertex_hdl_t);
-
-/* Except for the PIO Read error typically the other errors are handled in
- * the context of an asynchronous error interrupt.
- */
-#define	IS_ERROR_INTR_CONTEXT(_ec)	((_ec & IOECODE_DMA) 		|| \
-					 (_ec == IOECODE_PIO_WRITE))
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_IA64_SN_IOERROR_HANDLING_H */
--- diff/include/asm-ia64/sn/iograph.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/iograph.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,6 +8,8 @@
 #ifndef _ASM_IA64_SN_IOGRAPH_H
 #define _ASM_IA64_SN_IOGRAPH_H
 
+#include <asm/sn/xtalk/xbow.h>	/* For get MAX_PORT_NUM */
+
 /*
  * During initialization, platform-dependent kernel code establishes some
  * basic elements of the hardware graph.  This file contains edge and
@@ -115,40 +117,13 @@
 #define INFO_LBL_XSWITCH_VOL		"_xswitch_volunteer"
 #define INFO_LBL_XFUNCS			"_xtalk_ops"	/* ops vector for gio providers */
 #define INFO_LBL_XWIDGET		"_xwidget"
-/* Device/Driver  Admin directive labels  */
-#define ADMIN_LBL_INTR_TARGET		"INTR_TARGET"	/* Target cpu for device interrupts*/
-#define ADMIN_LBL_INTR_SWLEVEL		"INTR_SWLEVEL"	/* Priority level of the ithread */
-
-#define	ADMIN_LBL_DMATRANS_NODE		"PCIBUS_DMATRANS_NODE" /* Node used for
-								* 32-bit Direct
-								* Mapping I/O
-								*/
-#define ADMIN_LBL_DISABLED		"DISABLE"	/* Device has been disabled */
-#define ADMIN_LBL_DETACH		"DETACH"	/* Device has been detached */
-
-#define ADMIN_LBL_THREAD_PRI		"thread_priority" 
-							/* Driver adminstrator
-							 * hint parameter for 
-							 * thread priority
-							 */
-#define ADMIN_LBL_THREAD_CLASS		"thread_class" 
-							/* Driver adminstrator
-							 * hint parameter for 
-							 * thread priority
-							 * default class
-							 */
-/* Info labels that begin with '_' cannot be overwritten by an attr_set call */
-#define INFO_LBL_RESERVED(name) ((name)[0] == '_')
 
-#if defined(__KERNEL__)
+
+#ifdef __KERNEL__
 void init_all_devices(void);
 #endif /* __KERNEL__ */
 
-#include <asm/sn/sgi.h>
-#include <asm/sn/xtalk/xbow.h>	/* For get MAX_PORT_NUM */
-
 int io_brick_map_widget(int, int);
-int io_path_map_widget(vertex_hdl_t);
 
 /*
  * Map a brick's widget number to a meaningful int
@@ -159,5 +134,4 @@
     int                 ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */
 };
 
-
 #endif /* _ASM_IA64_SN_IOGRAPH_H */
--- diff/include/asm-ia64/sn/leds.h	2003-06-30 10:07:34.000000000 +0100
+++ source/include/asm-ia64/sn/leds.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,10 +8,7 @@
  * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/config.h>
-#include <asm/smp.h>
 #include <asm/sn/addrs.h>
-#include <asm/sn/sn_cpuid.h>
 #include <asm/sn/pda.h>
 #include <asm/sn/sn2/shub.h>
 
@@ -23,7 +20,7 @@
 #define LED_ALWAYS_SET		0x00
 
 /*
- * Basic macros for flashing the LEDS on an SGI, SN1.
+ * Basic macros for flashing the LEDS on an SGI SN.
  */
 
 static __inline__ void
--- diff/include/asm-ia64/sn/module.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/module.h	2004-02-18 09:04:02.000000000 +0000
@@ -8,12 +8,6 @@
 #ifndef _ASM_IA64_SN_MODULE_H
 #define _ASM_IA64_SN_MODULE_H
 
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-
-#include <asm/semaphore.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/ksys/elsc.h>
 
--- diff/include/asm-ia64/sn/sgi.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/sgi.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,7 +13,6 @@
 #include <linux/config.h>
 
 #include <asm/sn/types.h>
-#include <asm/uaccess.h>		/* for copy_??_user */
 #include <asm/sn/hwgfs.h>
 
 typedef hwgfs_handle_t vertex_hdl_t;
--- diff/include/asm-ia64/sn/sn2/sn_private.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ia64/sn/sn2/sn_private.h	2004-02-18 09:04:02.000000000 +0000
@@ -11,6 +11,7 @@
 #include <linux/wait.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
 #include <asm/sn/xtalk/xwidget.h>
 #include <asm/sn/xtalk/xtalk_private.h>
 
--- diff/include/asm-ia64/spinlock.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-ia64/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -110,8 +110,18 @@
 typedef struct {
 	volatile int read_counter	: 31;
 	volatile int write_lock		:  1;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
+
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *) (x) != 0)
@@ -127,6 +137,48 @@
 	}										\
 } while (0)
 
+#ifdef CONFIG_LOCKMETER
+/*
+ * HACK: This works, but still have a timing window that affects performance:
+ * we see that no one owns the Write lock, then someone * else grabs for Write
+ * lock before we do a read_lock().
+ * This means that on rare occasions our read_lock() will stall and spin-wait
+ * until we acquire for Read, instead of simply returning a trylock failure.
+ */
+static inline int _raw_read_trylock(rwlock_t *rw)
+{
+	if (rw->write_lock) {
+		return 0;
+	} else {
+		_raw_read_lock(rw);
+		return 1;
+	}
+}
+
+static inline int _raw_write_trylock(rwlock_t *rw)
+{
+	if (!(rw->write_lock)) {
+	    /* isn't currently write-locked... that looks promising... */
+	    if (test_and_set_bit(31, rw) == 0) {
+		/* now it is write-locked by me... */
+		if (rw->read_counter) {
+		    /* really read-locked, so release write-lock and fail */
+		    clear_bit(31, rw);
+		} else {
+		    /* we've the the write-lock, no read-lockers... success! */
+		    barrier();
+		    return 1;
+		}
+
+	    }
+	}
+
+	/* falls through ... fails to write-lock */
+	barrier();
+	return 0;
+}
+#endif
+
 #define _raw_read_unlock(rw)					\
 do {								\
 	rwlock_t *__read_lock_ptr = (rw);			\
@@ -190,4 +242,25 @@
 	clear_bit(31, (x));								\
 })
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering
+ *  so we can see the callerPC of who is actually doing the spin_lock().
+ *  Otherwise, all we see is the generic rollup of all locks done by
+ *  atomic_dec_and_lock().
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	return 0;
+}
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /*  _ASM_IA64_SPINLOCK_H */
--- diff/include/asm-ia64/tlb.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ia64/tlb.h	2004-02-18 09:04:02.000000000 +0000
@@ -173,6 +173,12 @@
 	check_pgt_cache();
 }
 
+static inline unsigned int
+tlb_is_full_mm(struct mmu_gather *tlb)
+{
+     return tlb->fullmm;
+}
+
 /*
  * Logically, this routine frees PAGE.  On MP machines, the actual freeing of the page
  * must be delayed until after the TLB has been flushed (see comments at the beginning of
@@ -204,6 +210,8 @@
 	tlb->end_addr = address + PAGE_SIZE;
 }
 
+#define tlb_migrate_prepare(mm) flush_tlb_mm(mm)
+
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)
 
--- diff/include/asm-ia64/unistd.h	2003-10-27 09:20:39.000000000 +0000
+++ source/include/asm-ia64/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -255,6 +255,9 @@
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
+#include <linux/types.h>
+#include <linux/linkage.h>
+
 extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr);
 
 #ifdef __KERNEL_SYSCALLS__
@@ -263,39 +266,35 @@
 #include <linux/signal.h>
 #include <asm/ptrace.h>
 #include <linux/stringify.h>
+#include <linux/syscalls.h>
 
 static inline long
 open (const char * name, int mode, int flags)
 {
-	extern long sys_open (const char *, int, int);
 	return sys_open(name, mode, flags);
 }
 
 static inline long
 dup (int fd)
 {
-	extern long sys_dup (int);
 	return sys_dup(fd);
 }
 
 static inline long
 close (int fd)
 {
-	extern long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
 static inline off_t
 lseek (int fd, off_t off, int whence)
 {
-	extern off_t sys_lseek (int, off_t, int);
 	return sys_lseek(fd, off, whence);
 }
 
 static inline long
 _exit (int value)
 {
-	extern long sys_exit (int);
 	return sys_exit(value);
 }
 
@@ -304,14 +303,12 @@
 static inline long
 write (int fd, const char * buf, size_t nr)
 {
-	extern long sys_write (int, const char *, size_t);
 	return sys_write(fd, buf, nr);
 }
 
 static inline long
 read (int fd, char * buf, size_t nr)
 {
-	extern long sys_read (int, char *, size_t);
 	return sys_read(fd, buf, nr);
 }
 
@@ -319,17 +316,12 @@
 static inline long
 setsid (void)
 {
-	extern long sys_setsid (void);
 	return sys_setsid();
 }
 
-struct rusage;
-
 static inline pid_t
 waitpid (int pid, int * wait_stat, int flags)
 {
-	extern asmlinkage long sys_wait4 (pid_t, unsigned int *, int, struct rusage *);
-
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
@@ -339,6 +331,23 @@
 
 #endif /* __KERNEL_SYSCALLS__ */
 
+asmlinkage unsigned long sys_mmap(
+				unsigned long addr, unsigned long len,
+				int prot, int flags,
+				int fd, long off);
+asmlinkage unsigned long sys_mmap2(
+				unsigned long addr, unsigned long len,
+				int prot, int flags,
+				int fd, long pgoff);
+struct pt_regs;
+asmlinkage long sys_execve(char *filename, char **argv, char **envp,
+				struct pt_regs *regs);
+asmlinkage long sys_pipe(long arg0, long arg1, long arg2, long arg3,
+			long arg4, long arg5, long arg6, long arg7, long stack);
+asmlinkage long sys_ptrace(long request, pid_t pid,
+			unsigned long addr, unsigned long data,
+			long arg4, long arg5, long arg6, long arg7, long stack);
+
 /*
  * "Conditional" syscalls
  *
--- diff/include/asm-m68k/irq.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/asm-m68k/irq.h	2004-02-18 09:04:02.000000000 +0000
@@ -76,11 +76,6 @@
 
 struct pt_regs;
 
-extern int sys_request_irq(unsigned int, 
-	irqreturn_t (*)(int, void *, struct pt_regs *), 
-	unsigned long, const char *, void *);
-extern void sys_free_irq(unsigned int, void *);
-
 /*
  * various flags for request_irq() - the Amiga now uses the standard
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
--- diff/include/asm-m68k/param.h	2002-10-16 04:28:24.000000000 +0100
+++ source/include/asm-m68k/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-m68k/unistd.h	2003-05-21 11:49:56.000000000 +0100
+++ source/include/asm-m68k/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -339,6 +339,8 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <linux/interrupt.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -363,6 +365,20 @@
 static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+asmlinkage long sys_mmap2(
+			unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(char *name, char **argv, char **envp);
+asmlinkage int sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+struct pt_regs;
+int sys_request_irq(unsigned int,
+			irqreturn_t (*)(int, void *, struct pt_regs *),
+			unsigned long, const char *, void *);
+void sys_free_irq(unsigned int, void *);
+
 #endif
 
 /*
--- diff/include/asm-m68knommu/irq.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/asm-m68knommu/irq.h	2004-02-18 09:04:02.000000000 +0000
@@ -62,11 +62,6 @@
 extern void (*mach_enable_irq)(unsigned int);
 extern void (*mach_disable_irq)(unsigned int);
 
-extern int sys_request_irq(unsigned int, 
-	irqreturn_t (*)(int, void *, struct pt_regs *), 
-	unsigned long, const char *, void *);
-extern void sys_free_irq(unsigned int, void *);
-
 /*
  * various flags for request_irq() - the Amiga now uses the standard
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
--- diff/include/asm-m68knommu/param.h	2002-11-11 11:09:43.000000000 +0000
+++ source/include/asm-m68knommu/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -44,10 +44,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-m68knommu/unistd.h	2003-05-21 11:49:46.000000000 +0100
+++ source/include/asm-m68knommu/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -371,10 +371,12 @@
   }										\
   return (type)__res;								\
 }
-		
+
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <linux/interrupt.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -406,6 +408,18 @@
 {
 	return waitpid(-1,wait_stat,0);
 }
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(char *name, char **argv, char **envp);
+asmlinkage int sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+struct pt_regs;
+int sys_request_irq(unsigned int,
+			irqreturn_t (*)(int, void *, struct pt_regs *),
+			unsigned long, const char *, void *);
+void sys_free_irq(unsigned int, void *);
 
 #endif
 
--- diff/include/asm-mips/hardirq.h	2003-08-20 14:16:33.000000000 +0100
+++ source/include/asm-mips/hardirq.h	2004-02-18 09:04:02.000000000 +0000
@@ -79,7 +79,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
--- diff/include/asm-mips/param.h	2003-07-08 09:55:19.000000000 +0100
+++ source/include/asm-mips/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -33,10 +33,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-mips/pgtable-32.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-mips/pgtable-32.h	2004-02-18 09:04:02.000000000 +0000
@@ -80,7 +80,7 @@
 
 #define VMALLOC_START     KSEG2
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 # define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
 #else
 # define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
--- diff/include/asm-mips/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/asm-mips/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -91,9 +91,18 @@
 
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
--- diff/include/asm-mips/topology.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/asm-mips/topology.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef __ASM_TOPOLOGY_H
 #define __ASM_TOPOLOGY_H
 
-#if CONFIG_SGI_IP27
+#ifdef CONFIG_SGI_IP27
 
 #include <asm/mmzone.h>
 
--- diff/include/asm-mips/unistd.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/asm-mips/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -1047,6 +1047,9 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <asm/ptrace.h>
+#include <asm/sim.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -1077,6 +1080,18 @@
 	return wait4(pid, wait_stat, flags, NULL);
 }
 
+asmlinkage unsigned long sys_mmap(
+				unsigned long addr, size_t len,
+				int prot, int flags,
+				int fd, off_t offset);
+asmlinkage long sys_mmap2(
+			unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs);
+asmlinkage int sys_pipe(nabi_no_regargs struct pt_regs regs);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+
 #endif /* __KERNEL_SYSCALLS__ */
 #endif /* !__ASSEMBLY__ */
 
--- diff/include/asm-parisc/module.h	2003-06-30 10:07:29.000000000 +0100
+++ source/include/asm-parisc/module.h	2004-02-18 09:04:02.000000000 +0000
@@ -17,11 +17,6 @@
 #define Elf_Rela Elf32_Rela
 #endif
 
-#define module_map(x)		vmalloc(x)
-#define module_unmap(x)		vfree(x)
-#define module_arch_init(x)	(0)
-#define arch_init_modules(x)	do { } while (0)
-
 struct mod_arch_specific
 {
 	unsigned long got_offset, got_count, got_max;
--- diff/include/asm-parisc/param.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/asm-parisc/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-parisc/unistd.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/asm-parisc/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -840,34 +840,30 @@
 #ifdef __KERNEL_SYSCALLS__
 
 #include <asm/current.h>
+#include <linux/syscalls.h>
 
 static inline pid_t setsid(void)
 {
-	extern long sys_setsid(void);
 	return sys_setsid();
 }
 
 static inline int write(int fd, const char *buf, off_t count)
 {
-	extern long sys_write(int, const char *, int);
 	return sys_write(fd, buf, count);
 }
 
 static inline int read(int fd, char *buf, off_t count)
 {
-	extern long sys_read(int, char *, int);
 	return sys_read(fd, buf, count);
 }
 
 static inline off_t lseek(int fd, off_t offset, int count)
 {
-	extern off_t sys_lseek(int, off_t, int);
 	return sys_lseek(fd, offset, count);
 }
 
 static inline int dup(int fd)
 {
-	extern long sys_dup(int);
 	return sys_dup(fd);
 }
 
@@ -880,30 +876,39 @@
 
 static inline int open(const char *file, int flag, int mode)
 {
-	extern long sys_open(const char *, int, int);
 	return sys_open(file, flag, mode);
 }
 
 static inline int close(int fd)
 {
-	extern asmlinkage long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
 static inline int _exit(int exitcode)
 {
-	extern long sys_exit(int) __attribute__((noreturn));
 	return sys_exit(exitcode);
 }
 
-struct rusage;
-extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
-
 static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
 {
 	return sys_wait4(pid, wait_stat, options, NULL);
 }
 
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, unsigned long offset);
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, unsigned long pgoff);
+struct pt_regs;
+asmlinkage int sys_execve(struct pt_regs *regs);
+int sys_clone(unsigned long clone_flags, unsigned long usp,
+		struct pt_regs *regs);
+int sys_vfork(struct pt_regs *regs);
+int sys_pipe(int *fildes);
+long sys_ptrace(long request, pid_t pid, long addr, long data);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
+
 #endif	/* __KERNEL_SYSCALLS__ */
 
 #endif /* __ASSEMBLY__ */
--- diff/include/asm-ppc/machdep.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc/machdep.h	2004-02-18 09:04:02.000000000 +0000
@@ -104,7 +104,8 @@
 };
 
 extern struct machdep_calls ppc_md;
-extern char cmd_line[512];
+#define COMMAND_LINE_SIZE 512
+extern char cmd_line[COMMAND_LINE_SIZE];
 
 extern void setup_pci_ptrs(void);
 
--- diff/include/asm-ppc/param.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-ppc/unistd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -390,6 +390,27 @@
 extern int close(int fd);
 extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
 
+unsigned long sys_mmap(unsigned long addr, size_t len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, off_t offset);
+unsigned long sys_mmap2(unsigned long addr, size_t len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+struct pt_regs;
+int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+		unsigned long a3, unsigned long a4, unsigned long a5,
+		struct pt_regs *regs);
+int sys_clone(unsigned long clone_flags, unsigned long usp,
+	      int __user *parent_tidp, void __user *child_threadptr,
+	      int __user *child_tidp, int p6,
+	      struct pt_regs *regs);
+int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+		struct pt_regs *regs);
+int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+		struct pt_regs *regs);
+int sys_pipe(int __user *fildes);
+int sys_ptrace(long request, long pid, long addr, long data);
+
 #endif /* __KERNEL_SYSCALLS__ */
 
 /*
--- diff/include/asm-ppc64/compat.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/compat.h	2004-02-18 09:04:02.000000000 +0000
@@ -25,6 +25,7 @@
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef u32		compat_timer_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
--- diff/include/asm-ppc64/machdep.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc64/machdep.h	2004-02-18 09:04:02.000000000 +0000
@@ -109,7 +109,8 @@
 };
 
 extern struct machdep_calls ppc_md;
-extern char cmd_line[512];
+#define COMMAND_LINE_SIZE 512
+extern char cmd_line[COMMAND_LINE_SIZE];
 
 /* Functions to produce codes on the leds.
  * The SRC code should be unique for the message category and should
--- diff/include/asm-ppc64/mmu_context.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/mmu_context.h	2004-02-18 09:04:02.000000000 +0000
@@ -156,6 +156,8 @@
 	 : : );
 #endif /* CONFIG_ALTIVEC */
 
+	cpu_set(smp_processor_id(), next->cpu_vm_mask);
+
 	/* No need to flush userspace segments if the mm doesnt change */
 	if (prev == next)
 		return;
@@ -164,7 +166,6 @@
 		flush_slb(tsk, next);
 	else
 		flush_stab(tsk, next);
-	cpu_set(smp_processor_id(), next->cpu_vm_mask);
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
--- diff/include/asm-ppc64/param.h	2002-10-16 04:29:02.000000000 +0100
+++ source/include/asm-ppc64/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -20,10 +20,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-ppc64/ppc32.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/ppc32.h	2004-02-18 09:04:02.000000000 +0000
@@ -2,6 +2,7 @@
 #define _PPC64_PPC32_H
 
 #include <linux/compat.h>
+#include <linux/compat_siginfo.h>
 #include <asm/siginfo.h>
 #include <asm/signal.h>
 
@@ -40,55 +41,6 @@
 
 /* These are here to support 32-bit syscalls on a 64-bit kernel. */
 
-typedef struct compat_siginfo {
-	int si_signo;
-	int si_errno;
-	int si_code;
-
-	union {
-		int _pad[SI_PAD_SIZE32];
-
-		/* kill() */
-		struct {
-			compat_pid_t _pid;		/* sender's pid */
-			compat_uid_t _uid;		/* sender's uid */
-		} _kill;
-
-		/* POSIX.1b timers */
-		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
-		} _timer;
-
-		/* POSIX.1b signals */
-		struct {
-			compat_pid_t _pid;		/* sender's pid */
-			compat_uid_t _uid;		/* sender's uid */
-			compat_sigval_t _sigval;
-		} _rt;
-
-		/* SIGCHLD */
-		struct {
-			compat_pid_t _pid;		/* which child */
-			compat_uid_t _uid;		/* sender's uid */
-			int _status;			/* exit code */
-			compat_clock_t _utime;
-			compat_clock_t _stime;
-		} _sigchld;
-
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
-		struct {
-			unsigned int _addr; /* faulting insn/memory ref. */
-		} _sigfault;
-
-		/* SIGPOLL */
-		struct {
-			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
-			int _fd;
-		} _sigpoll;
-	} _sifields;
-} compat_siginfo_t;
-
 #define __old_sigaction32	old_sigaction32
 
 struct __old_sigaction32 {
@@ -141,20 +93,6 @@
 	struct mcontext32	uc_mcontext;
 };
 
-typedef struct compat_sigevent {
-	compat_sigval_t sigev_value;
-	int sigev_signo;
-	int sigev_notify;
-	union {
-		int _pad[SIGEV_PAD_SIZE];
-		int _tid;
-		struct {
-			compat_uptr_t _function;
-			compat_uptr_t _attribute;
-		} _sigev_thread;
-	} _sigev_un;
-} compat_sigevent_t;
-
 struct ipc_kludge_32 {
 	unsigned int msgp;
 	int msgtyp;
--- diff/include/asm-ppc64/signal.h	2003-09-30 15:46:19.000000000 +0100
+++ source/include/asm-ppc64/signal.h	2004-02-18 09:04:02.000000000 +0000
@@ -148,15 +148,6 @@
 struct timespec;
 extern int do_signal(sigset_t *oldset, struct pt_regs *regs);
 extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-extern long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
-			       size_t sigsetsize);
-extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
-extern long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
-				const struct timespec *uts, size_t sigsetsize);
-extern long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 
-struct pt_regs;
-int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-
 #endif /* _ASMPPC64_SIGNAL_H */
--- diff/include/asm-ppc64/system.h	2004-02-18 08:54:12.000000000 +0000
+++ source/include/asm-ppc64/system.h	2004-02-18 09:04:02.000000000 +0000
@@ -82,12 +82,12 @@
 #endif
 
 #else
-#define debugger(regs)			0
-#define debugger_bpt(regs)		0
-#define debugger_sstep(regs)		0
-#define debugger_iabr_match(regs)	0
-#define debugger_dabr_match(regs)	0
-#define debugger_fault_handler(regs)	0
+static inline int debugger(struct *pt_regs regs) { return 0; }
+static inline int debugger_bpt(struct *pt_regs regs) { return 0; }
+static inline int debugger_sstep(struct *pt_regs regs) { return 0; }
+static inline int debugger_iabr_match(struct *pt_regs regs) { return 0; }
+static inline int debugger_dabr_match(struct *pt_regs regs) { return 0; }
+static inline int debugger_fault_handler(struct *pt_regs regs) { return 0; }
 #endif
 
 extern void show_regs(struct pt_regs * regs);
--- diff/include/asm-ppc64/unistd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-ppc64/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -274,6 +274,9 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/types.h>
+#include <linux/linkage.h>
+
 /* On powerpc a system call basically clobbers the same registers like a
  * function call, with the exception of LR (which is needed for the
  * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
@@ -404,9 +407,27 @@
 extern int open(const char *file, int flag, int mode);
 extern int close(int fd);
 extern pid_t waitpid(pid_t pid, int *wait_stat, int options);
-
 #endif /* __KERNEL_SYSCALLS__ */
 
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, off_t offset);
+struct pt_regs;
+int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+		unsigned long a3, unsigned long a4, unsigned long a5,
+		struct pt_regs *regs);
+int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3,
+		unsigned long p4, unsigned long p5, unsigned long p6,
+		struct pt_regs *regs);
+int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3,
+		unsigned long p4, unsigned long p5, unsigned long p6,
+		struct pt_regs *regs);
+int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
+		unsigned long p4, unsigned long p5, unsigned long p6,
+		struct pt_regs *regs);
+asmlinkage int sys_pipe(int *fildes);
+int sys_ptrace(long request, long pid, long addr, long data);
+
 /*
  * "Conditional" syscalls
  *
--- diff/include/asm-s390/param.h	2002-10-16 04:27:14.000000000 +0100
+++ source/include/asm-s390/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,10 +21,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-s390/unistd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-s390/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -505,7 +505,10 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <linux/config.h>
+#include <asm/ptrace.h>
 #include <asm/stat.h>
+#include <linux/syscalls.h>
 
 /*
  * we need this inline - forking from kernel space will result
@@ -531,12 +534,25 @@
 static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
 
-struct rusage;
-extern long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
 static inline pid_t waitpid(int pid, int *wait_stat, int flags)
 {
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
+struct mmap_arg_struct;
+asmlinkage long sys_mmap2(struct mmap_arg_struct *arg);
+
+asmlinkage int sys_execve(struct pt_regs regs);
+asmlinkage int sys_clone(struct pt_regs regs);
+asmlinkage int sys_fork(struct pt_regs regs);
+asmlinkage int sys_vfork(struct pt_regs regs);
+#ifndef CONFIG_ARCH_S390X
+#define __SYS_RETTYPE int
+#else
+#define __SYS_RETTYPE long
+#endif /* CONFIG_ARCH_S390X */
+asmlinkage __SYS_RETTYPE sys_pipe(unsigned long *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 
 #endif
 
--- diff/include/asm-sh/hardirq.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-sh/hardirq.h	2004-02-18 09:04:02.000000000 +0000
@@ -74,7 +74,7 @@
 #define nmi_enter()		(irq_enter())
 #define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
--- diff/include/asm-sh/kmap_types.h	2003-07-08 09:55:19.000000000 +0100
+++ source/include/asm-sh/kmap_types.h	2004-02-18 09:04:02.000000000 +0000
@@ -5,7 +5,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
--- diff/include/asm-sh/param.h	2003-07-08 09:55:19.000000000 +0100
+++ source/include/asm-sh/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -17,10 +17,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-sh/unistd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-sh/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -402,6 +402,8 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <asm/ptrace.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -433,6 +435,33 @@
 {
 	return waitpid(-1,wait_stat,0);
 }
+
+asmlinkage long sys_mmap2(
+			unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(char *ufilename, char **uargv,
+			char **uenvp, unsigned long r7,
+			struct pt_regs regs);
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+			unsigned long parent_tidptr,
+			unsigned long child_tidptr,
+			struct pt_regs regs);
+asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7,
+			struct pt_regs regs);
+asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7,
+			struct pt_regs regs);
+asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7,
+			struct pt_regs regs);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char *buf,
+				size_t count, long dummy, loff_t pos);
+asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char *buf,
+				size_t count, long dummy, loff_t pos);
+
 #endif
 
 /*
--- diff/include/asm-sparc/param.h	2002-10-16 04:27:19.000000000 +0100
+++ source/include/asm-sparc/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-sparc/unistd.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-sparc/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -450,6 +450,16 @@
 static __inline__ _syscall1(int,_exit,int,exitcode)
 static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+asmlinkage unsigned long sys_mmap(
+				unsigned long addr, unsigned long len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, unsigned long off);
+asmlinkage unsigned long sys_mmap2(
+				unsigned long addr, unsigned long len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+
 #endif /* __KERNEL_SYSCALLS__ */
 
 /*
--- diff/include/asm-sparc64/param.h	2002-10-16 04:27:09.000000000 +0100
+++ source/include/asm-sparc64/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-sparc64/spinlock.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/asm-sparc64/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -30,15 +30,23 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
+typedef struct {
+	unsigned char lock;
+	unsigned int  index;
+} spinlock_t;
 
-#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
-#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
+#ifdef CONFIG_LOCKMETER
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0, 0}
+#else
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
+#endif
 
-#define spin_unlock_wait(lock)	\
+#define spin_lock_init(__lock)	do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+
+#define spin_unlock_wait(__lock)	\
 do {	membar("#LoadLoad");	\
-} while(*((volatile unsigned char *)lock))
+} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock))))
 
 static __inline__ void _raw_spin_lock(spinlock_t *lock)
 {
@@ -109,17 +117,31 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED	0
-#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
-#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
+#ifdef CONFIG_LOCKMETER
+typedef struct {
+	unsigned int lock;
+	unsigned int index;
+	unsigned int cpu;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff }
+#else
+typedef struct {
+	unsigned int lock;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED        (rwlock_t) { 0 }
+#endif
+
+#define rwlock_init(lp)		do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x)	((x)->lock != 0)
 
+extern int __read_trylock(rwlock_t *);
 extern void __read_lock(rwlock_t *);
 extern void __read_unlock(rwlock_t *);
 extern void __write_lock(rwlock_t *);
 extern void __write_unlock(rwlock_t *);
 extern int __write_trylock(rwlock_t *);
 
+#define _raw_read_trylock(p)	__read_trylock(p)
 #define _raw_read_lock(p)	__read_lock(p)
 #define _raw_read_unlock(p)	__read_unlock(p)
 #define _raw_write_lock(p)	__write_lock(p)
--- diff/include/asm-sparc64/unistd.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/asm-sparc64/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -440,6 +440,12 @@
 static __inline__ _syscall1(int,_exit,int,exitcode)
 static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+asmlinkage unsigned long sys_mmap(
+				unsigned long addr, unsigned long len,
+				unsigned long prot, unsigned long flags,
+				unsigned long fd, unsigned long off);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+
 #endif /* __KERNEL_SYSCALLS__ */
 
 #ifdef __KERNEL__
--- diff/include/asm-um/param.h	2002-10-16 04:27:18.000000000 +0100
+++ source/include/asm-um/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -3,10 +3,6 @@
 
 #define EXEC_PAGESIZE   4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
--- diff/include/asm-um/unistd.h	2002-11-18 10:11:55.000000000 +0000
+++ source/include/asm-um/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -6,24 +6,11 @@
 #ifndef _UM_UNISTD_H_
 #define _UM_UNISTD_H_
 
+#include <linux/syscalls.h>
 #include "linux/resource.h"
 #include "asm/uaccess.h"
 
-extern long sys_open(const char *filename, int flags, int mode);
-extern long sys_dup(unsigned int fildes);
-extern long sys_close(unsigned int fd);
 extern int um_execve(const char *file, char *const argv[], char *const env[]);
-extern long sys_setsid(void);
-extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
-extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, 
-		      struct rusage *ru);
-extern long sys_mount(char *dev_name, char *dir_name, char *type, 
-		      unsigned long flags, void *data);
-extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, 
-		       struct timeval *tvp);
-extern long sys_lseek(unsigned int fildes, unsigned long offset, int whence);
-extern long sys_read(unsigned int fildes, char *buf, int len);
-extern long sys_write(int fildes, const char *buf, size_t len);
 
 #ifdef __KERNEL_SYSCALLS__
 
@@ -81,6 +68,17 @@
 	KERNEL_CALL(int, sys_write, fd, buf, len)
 }
 
+long sys_mmap2(unsigned long addr, unsigned long len,
+		unsigned long prot, unsigned long flags,
+		unsigned long fd, unsigned long pgoff);
+int sys_execve(char *file, char **argv, char **env);
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+		int *parent_tid, int *child_tid);
+long sys_fork(void);
+long sys_vfork(void);
+int sys_pipe(unsigned long *fildes);
+int sys_ptrace(long request, long pid, long addr, long data);
+
 #endif
 
 /* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying
--- diff/include/asm-v850/param.h	2002-11-11 11:09:43.000000000 +0000
+++ source/include/asm-v850/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-v850/unistd.h	2003-05-21 11:50:10.000000000 +0100
+++ source/include/asm-v850/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -417,6 +417,17 @@
 	return waitpid (-1, wait_stat, 0);
 }
 
+unsigned long sys_mmap(unsigned long addr, size_t len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, off_t offset);
+unsigned long sys_mmap2(unsigned long addr, size_t len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff);
+struct pt_regs;
+int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs);
+int sys_pipe (int *fildes);
+int sys_ptrace(long request, long pid, long addr, long data);
+
 #endif
 
 /*
--- diff/include/asm-x86_64/compat.h	2003-06-30 10:07:34.000000000 +0100
+++ source/include/asm-x86_64/compat.h	2004-02-18 09:04:02.000000000 +0000
@@ -28,6 +28,7 @@
 typedef s32		compat_daddr_t;
 typedef u32		compat_caddr_t;
 typedef __kernel_fsid_t	compat_fsid_t;
+typedef u32		compat_timer_t;
 
 typedef s32		compat_int_t;
 typedef s32		compat_long_t;
--- diff/include/asm-x86_64/param.h	2002-11-11 11:09:30.000000000 +0000
+++ source/include/asm-x86_64/param.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
--- diff/include/asm-x86_64/proto.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/proto.h	2004-02-18 09:04:02.000000000 +0000
@@ -24,7 +24,6 @@
 
 extern void calibrate_delay(void);
 extern void cpu_idle(void);
-extern void sys_ni_syscall(void);
 extern void config_acpi_tables(void);
 extern void ia32_syscall(void);
 extern void iommu_hole_init(void);
--- diff/include/asm-x86_64/unistd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/asm-x86_64/unistd.h	2004-02-18 09:04:02.000000000 +0000
@@ -636,6 +636,9 @@
 
 #else /* __KERNEL_SYSCALLS__ */
 
+#include <linux/syscalls.h>
+#include <asm/ptrace.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -650,31 +653,26 @@
  */
 #define __NR__exit __NR_exit
 
-extern pid_t sys_setsid(void);
 static inline pid_t setsid(void)
 {
 	return sys_setsid();
 }
 
-long sys_write(int fd, const char *buf, size_t size);
 static inline ssize_t write(unsigned int fd, char * buf, size_t count)
 {
 	return sys_write(fd, buf, count);
 }
 
-extern ssize_t sys_read(unsigned int, char *, size_t);
 static inline ssize_t read(unsigned int fd, char * buf, size_t count)
 {
 	return sys_read(fd, buf, count);
 }
 
-extern off_t sys_lseek(unsigned int, off_t, unsigned int);
 static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
 	return sys_lseek(fd, offset, origin);
 }
 
-extern long sys_dup(unsigned int);
 static inline long dup(unsigned int fd)
 {
 	return sys_dup(fd);
@@ -683,34 +681,49 @@
 /* implemented in asm in arch/x86_64/kernel/entry.S */
 extern long execve(char *, char **, char **);
 
-extern long sys_open(const char *, int, int);
 static inline long open(const char * filename, int flags, int mode)
 {
 	return sys_open(filename, flags, mode);
 }
 
-extern long sys_close(unsigned int);
 static inline long close(unsigned int fd)
 {
 	return sys_close(fd);
 }
 
-extern long sys_exit(int) __attribute__((noreturn));
-extern inline void exit(int error_code)
-{
-	sys_exit(error_code);
-}
-
-struct rusage; 
-long sys_wait4(pid_t pid,unsigned int * stat_addr, 
-			int options, struct rusage * ru);
 static inline pid_t waitpid(int pid, int * wait_stat, int flags)
 {
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
+extern long sys_mmap(unsigned long addr, unsigned long len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long off);
+
+extern int sys_modify_ldt(int func, void *ptr, unsigned long bytecount);
+
+asmlinkage long sys_execve(char *name, char **argv, char **envp,
+			struct pt_regs regs);
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
+			void *parent_tid, void *child_tid,
+			struct pt_regs regs);
+asmlinkage long sys_fork(struct pt_regs regs);
+asmlinkage long sys_vfork(struct pt_regs regs);
+asmlinkage long sys_pipe(int *fildes);
+
 #endif /* __KERNEL_SYSCALLS__ */
 
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+
+asmlinkage long sys_ptrace(long request, long pid,
+				unsigned long addr, long data);
+asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
+
+#endif	/* __ASSEMBLY__ */
+
 #endif /* __NO_STUBS */
 
 /*
--- diff/include/linux/acpi.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/acpi.h	2004-02-18 09:04:02.000000000 +0000
@@ -317,6 +317,15 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+/* PCI MMCONFIG */
+
+struct acpi_table_mcfg {
+	struct acpi_table_header	header;
+	u8				reserved[8];
+	u32				base_address;
+	u32				base_reserved;
+} __attribute__ ((packed));
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +347,7 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
@@ -369,6 +379,8 @@
 
 extern int acpi_mp_config;
 
+extern u32 pci_mmcfg_base_addr;
+
 #else	/*!CONFIG_ACPI_BOOT*/
 
 #define acpi_mp_config	0
--- diff/include/linux/aio.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/aio.h	2004-02-18 09:04:02.000000000 +0000
@@ -167,6 +167,7 @@
 }
 
 /* for sysctl: */
-extern unsigned aio_max_nr, aio_max_size, aio_max_pinned;
+extern atomic_t aio_nr;
+extern unsigned aio_max_nr;
 
 #endif /* __LINUX__AIO_H */
--- diff/include/linux/binfmts.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/linux/binfmts.h	2004-02-18 09:04:02.000000000 +0000
@@ -35,9 +35,13 @@
 	char * interp;		/* Name of the binary really executed. Most
 				   of the time same as filename, but could be
 				   different for binfmt_{misc,script} */
+	unsigned long interp_flags;
 	unsigned long loader, exec;
 };
 
+#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
+#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
+
 /*
  * This structure defines the functions that are used to load the binary formats that
  * linux accepts.
--- diff/include/linux/bitmap.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/bitmap.h	2004-02-18 09:04:02.000000000 +0000
@@ -41,7 +41,7 @@
 void bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
 			const unsigned long *bitmap2, int bits);
 int bitmap_weight(const unsigned long *bitmap, int bits);
-int bitmap_snprintf(char *buf, unsigned int buflen,
+int bitmap_scnprintf(char *buf, unsigned int buflen,
 			const unsigned long *maskp, int bits);
 int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
 			unsigned long *maskp, int bits);
--- diff/include/linux/blkdev.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/blkdev.h	2004-02-18 09:04:02.000000000 +0000
@@ -586,7 +586,7 @@
 extern void blk_queue_free_tags(request_queue_t *);
 extern int blk_queue_resize_tags(request_queue_t *, int);
 extern void blk_queue_invalidate_tags(request_queue_t *);
-extern void blk_congestion_wait(int rw, long timeout);
+extern long blk_congestion_wait(int rw, long timeout);
 
 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
 extern void blk_rq_prep_restart(struct request *);
--- diff/include/linux/compat.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/compat.h	2004-02-18 09:04:02.000000000 +0000
@@ -6,15 +6,26 @@
  */
 #include <linux/config.h>
 
-#ifdef CONFIG_COMPAT
+#ifndef CONFIG_COMPAT
+
+/* Non-native task requiring compat... doesn't exist */
+#define is_compat_task(x) 0
+
+#else
 
 #include <linux/stat.h>
 #include <linux/param.h>	/* for HZ */
+#include <linux/personality.h>  /* Conditional process compat */
 #include <asm/compat.h>
 
 #define compat_jiffies_to_clock_t(x)	\
 		(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
+/* Non-native task requiring compat */
+#ifndef HAVE_ARCH_IS_COMPAT_TASK
+#define is_compat_task(x) (x->personality == PER_LINUX32)
+#endif
+
 struct compat_itimerspec { 
 	struct compat_timespec it_interval;
 	struct compat_timespec it_value;
@@ -83,10 +94,15 @@
 	char		d_name[256];
 };
 
-typedef union compat_sigval {
-	compat_int_t	sival_int;
-	compat_uptr_t	sival_ptr;
-} compat_sigval_t;
-
+long compat_sys_semctl(int first, int second, int third, void __user *uptr);
+long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
+long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
+		int version, void __user *uptr);
+long compat_sys_msgctl(int first, int second, void __user *uptr);
+long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
+		void __user *uptr);
+long compat_sys_shmctl(int first, int second, void __user *uptr);
+long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
+		unsigned nsems, const struct compat_timespec __user *timeout);
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
--- diff/include/linux/compiler-gcc.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/compiler-gcc.h	2004-02-18 09:04:02.000000000 +0000
@@ -13,5 +13,5 @@
    shouldn't recognize the original var, and make assumptions about it */
 #define RELOC_HIDE(ptr, off)					\
   ({ unsigned long __ptr;					\
-    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		\
+	__asm__ ("" : "=r"(__ptr) : "0"(ptr));			\
     (typeof(ptr)) (__ptr + (off)); })
--- diff/include/linux/compiler-gcc3.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/compiler-gcc3.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,3 +21,7 @@
 
 #define __attribute_pure__	__attribute__((pure))
 #define __attribute_const__	__attribute__((__const__))
+
+#if __GNUC_MINOR__ >= 1
+#define  noinline __attribute__((noinline))
+#endif
--- diff/include/linux/compiler.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/compiler.h	2004-02-18 09:04:02.000000000 +0000
@@ -96,6 +96,10 @@
 # define __attribute_const__	/* unimplemented */
 #endif
 
+#ifndef noinline
+#define noinline
+#endif
+
 /* Optimization barrier */
 #ifndef barrier
 # define barrier() __memory_barrier()
--- diff/include/linux/concap.h	2002-10-16 04:27:51.000000000 +0100
+++ source/include/linux/concap.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: concap.h,v 1.2.8.1 2001/09/23 22:25:05 kai Exp $
+/* $Id: concap.h,v 1.3.2.2 2004/01/12 23:08:35 keil Exp $
  *
  * Copyright 1997 by Henner Eisen <eis@baty.hanse.de>
  *
@@ -31,6 +31,7 @@
 	struct net_device *net_dev;	/* net device using our service  */
 	struct concap_device_ops *dops;	/* callbacks provided by device */
  	struct concap_proto_ops  *pops;	/* callbacks provided by us */
+ 	spinlock_t lock;
 	int flags;
 	void *proto_data;		/* protocol specific private data, to
 					   be accessed via *pops methods only*/
--- diff/include/linux/config.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/config.h	2004-02-18 09:04:02.000000000 +0000
@@ -2,5 +2,8 @@
 #define _LINUX_CONFIG_H
 
 #include <linux/autoconf.h>
+#ifdef CONFIG_X86
+#include <asm/kgdb.h>
+#endif
 
 #endif
--- diff/include/linux/cpu.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/cpu.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,6 +21,8 @@
 
 #include <linux/sysdev.h>
 #include <linux/node.h>
+#include <linux/compiler.h>
+#include <linux/cpumask.h>
 #include <asm/semaphore.h>
 
 struct cpu {
@@ -56,9 +58,21 @@
 extern struct semaphore cpucontrol;
 #define lock_cpu_hotplug()	down(&cpucontrol)
 #define unlock_cpu_hotplug()	up(&cpucontrol)
+#define lock_cpu_hotplug_interruptible() down_interruptible(&cpucontrol)
+int cpu_down(unsigned int cpu);
+#define hotcpu_notifier(fn, pri) {				\
+	static struct notifier_block fn##_nb = { fn, pri };	\
+	register_cpu_notifier(&fn##_nb);			\
+}
+#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
 #define lock_cpu_hotplug()	do { } while (0)
 #define unlock_cpu_hotplug()	do { } while (0)
+#define lock_cpu_hotplug_interruptible() 0
+#define hotcpu_notifier(fn, pri)
+
+/* CPUs don't go offline once they're online w/o CONFIG_HOTPLUG_CPU */
+#define cpu_is_offline(cpu) 0
 #endif
 
 #endif /* _LINUX_CPU_H_ */
--- diff/include/linux/cpufreq.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/cpufreq.h	2004-02-18 09:04:02.000000000 +0000
@@ -110,24 +110,24 @@
  * @div:   divisor
  * @mult:  multiplier
  *
- * Needed for loops_per_jiffy and similar calculations.  We do it 
- * this way to avoid math overflow on 32-bit machines.  This will
- * become architecture dependent once high-resolution-timer is
- * merged (or any other thing that introduces sc_math.h).
  *
  *    new = old * mult / div
  */
 static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult)
 {
-	unsigned long val, carry;
+#if BITS_PER_LONG == 32
 
-	mult /= 100;
-	div  /= 100;
-        val   = (old / div) * mult;
-        carry = old % div;
-	carry = carry * mult / div;
+	u64 result = ((u64) old) * ((u64) mult);
+	do_div(result, div);
+	return (unsigned long) result;
 
-	return carry + val;
+#elif BITS_PER_LONG == 64
+
+	unsigned long result = old * ((u64) mult);
+	result /= div;
+	return result;
+
+#endif
 };
 
 /*********************************************************************
--- diff/include/linux/cpumask.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/cpumask.h	2004-02-18 09:04:02.000000000 +0000
@@ -12,6 +12,7 @@
 extern cpumask_t cpu_possible_map;
 
 #define num_online_cpus()		cpus_weight(cpu_online_map)
+#define num_possible_cpus()		cpus_weight(cpu_possible_map)
 #define cpu_online(cpu)			cpu_isset(cpu, cpu_online_map)
 #define cpu_possible(cpu)		cpu_isset(cpu, cpu_possible_map)
 
@@ -24,7 +25,9 @@
 #define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map)
 #else
 #define	cpu_online_map			cpumask_of_cpu(0)
+#define	cpu_possible_map		cpumask_of_cpu(0)
 #define num_online_cpus()		1
+#define num_possible_cpus()		1
 #define cpu_online(cpu)			({ BUG_ON((cpu) != 0); 1; })
 #define cpu_possible(cpu)		({ BUG_ON((cpu) != 0); 1; })
 
@@ -32,8 +35,8 @@
 #define for_each_online_cpu(cpu) for (cpu = 0; cpu < 1; cpu++)
 #endif
 
-#define cpumask_snprintf(buf, buflen, map)				\
-	bitmap_snprintf(buf, buflen, cpus_addr(map), NR_CPUS)
+#define cpumask_scnprintf(buf, buflen, map)				\
+	bitmap_scnprintf(buf, buflen, cpus_addr(map), NR_CPUS)
 
 #define cpumask_parse(buf, buflen, map)					\
 	bitmap_parse(buf, buflen, cpus_addr(map), NR_CPUS)
--- diff/include/linux/devpts_fs.h	2002-10-16 04:28:33.000000000 +0100
+++ source/include/linux/devpts_fs.h	2004-02-18 09:04:02.000000000 +0000
@@ -2,7 +2,7 @@
  *
  * linux/include/linux/devpts_fs.h
  *
- *  Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *  Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -13,21 +13,22 @@
 #ifndef _LINUX_DEVPTS_FS_H
 #define _LINUX_DEVPTS_FS_H 1
 
-#ifdef CONFIG_DEVPTS_FS
+#include <linux/errno.h>
 
-void devpts_pty_new(int, dev_t);	/* mknod in devpts */
-void devpts_pty_kill(int);		/* unlink */
+#if CONFIG_UNIX98_PTYS
+
+int devpts_pty_new(struct tty_struct *); /* mknod in devpts */
+struct tty_struct *devpts_get_tty(int);	 /* get tty structure */
+void devpts_pty_kill(int);		 /* unlink */
 
 #else
 
-static inline void devpts_pty_new(int line, dev_t device)
-{
-}
-
-static inline void devpts_pty_kill(int line)
-{
-}
+/* Dummy stubs in the no-pty case */
+static inline int devpts_pty_new(struct tty_struct *) { return -EINVAL; }
+static inline struct tty_struct *devpts_get_tty(int)  { return NULL; }
+static inline void devpts_pty_kill(int) { }
 
 #endif
 
+
 #endif /* _LINUX_DEVPTS_FS_H */
--- diff/include/linux/elevator.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/elevator.h	2004-02-18 09:04:02.000000000 +0000
@@ -94,6 +94,11 @@
  */
 extern elevator_t iosched_as;
 
+/*
+ * completely fair queueing I/O scheduler
+ */
+extern elevator_t iosched_cfq;
+
 extern int elevator_init(request_queue_t *, elevator_t *);
 extern void elevator_exit(request_queue_t *);
 extern int elv_rq_merge_ok(struct request *, struct bio *);
--- diff/include/linux/eventpoll.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/eventpoll.h	2004-02-18 09:04:02.000000000 +0000
@@ -49,13 +49,6 @@
 struct file;
 
 
-/* Kernel space functions implementing the user space "epoll" API */
-asmlinkage long sys_epoll_create(int size);
-asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
-			      struct epoll_event __user *event);
-asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
-			       int maxevents, int timeout);
-
 #ifdef CONFIG_EPOLL
 
 /* Used to initialize the epoll bits inside the "struct file" */
--- diff/include/linux/ext3_fs_sb.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/ext3_fs_sb.h	2004-02-18 09:04:02.000000000 +0000
@@ -69,6 +69,10 @@
 	struct timer_list turn_ro_timer;	/* For turning read-only (crash simulation) */
 	wait_queue_head_t ro_wait_queue;	/* For people waiting for the fs to go read-only */
 #endif
+#ifdef CONFIG_QUOTA
+	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
+	int s_jquota_fmt;			/* Format of quota to use */
+#endif
 };
 
 #endif	/* _LINUX_EXT3_FS_SB */
--- diff/include/linux/ext3_jbd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/ext3_jbd.h	2004-02-18 09:04:02.000000000 +0000
@@ -42,8 +42,9 @@
  * superblock only gets updated once, of course, so don't bother
  * counting that again for the quota updates. */
 
-#define EXT3_DATA_TRANS_BLOCKS		(3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
-					 EXT3_XATTR_TRANS_BLOCKS - 2)
+#define EXT3_DATA_TRANS_BLOCKS		(EXT3_SINGLEDATA_TRANS_BLOCKS + \
+					 EXT3_XATTR_TRANS_BLOCKS - 2 + \
+					 2*EXT3_QUOTA_TRANS_BLOCKS)
 
 extern int ext3_writepage_trans_blocks(struct inode *inode);
 
@@ -72,6 +73,15 @@
 
 #define EXT3_INDEX_EXTRA_TRANS_BLOCKS	8
 
+#ifdef CONFIG_QUOTA
+/* Amount of blocks needed for quota update - we know that the structure was
+ * allocated so we need to update only inode+data */
+#define EXT3_QUOTA_TRANS_BLOCKS 2
+#define EXT3_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*(EXT3_SINGLEDATA_TRANS_BLOCKS-2)+2)
+#else
+#define EXT3_QUOTA_TRANS_BLOCKS 0
+#endif
+
 int
 ext3_mark_iloc_dirty(handle_t *handle, 
 		     struct inode *inode,
--- diff/include/linux/fb.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/fb.h	2004-02-18 09:04:02.000000000 +0000
@@ -371,16 +371,16 @@
 #define FB_PIXMAP_SYNC    256   /* set if GPU can DMA       */
 
 struct fb_pixmap {
-	u8 *addr;		/* pointer to memory                    */
-	u32 size;		/* size of buffer in bytes              */
-	u32 offset;		/* current offset to buffer             */
-	u32 buf_align;		/* byte alignment of each bitmap        */
-	u32 scan_align;		/* alignment per scanline               */
-	u32 access_align;	/* alignment per read/write             */
-	u32 flags;		/* see FB_PIXMAP_*                      */
-					  /* access methods                */
-	void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); 
-	u8   (*inbuf) (u8 *addr);
+	u8  *addr;		/* pointer to memory			*/
+	u32 size;		/* size of buffer in bytes		*/
+	u32 offset;		/* current offset to buffer		*/
+	u32 buf_align;		/* byte alignment of each bitmap	*/
+	u32 scan_align;		/* alignment per scanline		*/
+	u32 access_align;	/* alignment per read/write		*/
+	u32 flags;		/* see FB_PIXMAP_*			*/
+				/* access methods			*/
+	void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size);
+	u8   (*inbuf) (struct fb_info *info, u8 *addr);
 };
 
     /*
@@ -388,64 +388,53 @@
      */
 
 struct fb_ops {
-    /* open/release and usage marking */
-    struct module *owner;
-    int (*fb_open)(struct fb_info *info, int user);
-    int (*fb_release)(struct fb_info *info, int user);
-
-    /* For framebuffers with strange non linear layouts */	
-	ssize_t(*fb_read) (struct file * file, char *buf, size_t count,
-			   loff_t * ppos);
-	ssize_t(*fb_write) (struct file * file, const char *buf,
-			    size_t count, loff_t * ppos);
+	/* open/release and usage marking */
+	struct module *owner;
+	int (*fb_open)(struct fb_info *info, int user);
+	int (*fb_release)(struct fb_info *info, int user);
+
+	/* For framebuffers with strange non linear layouts */
+	ssize_t (*fb_read)(struct file *file, char *buf, size_t count, loff_t *ppos);
+	ssize_t (*fb_write)(struct file *file, const char *buf, size_t count, loff_t *ppos);
 
 	/* checks var and eventually tweaks it to something supported,
 	 * DO NOT MODIFY PAR */
-	int (*fb_check_var) (struct fb_var_screeninfo * var,
-			     struct fb_info * info);
+	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
 	/* set the video mode according to info->var */
-    int (*fb_set_par)(struct fb_info *info);
+	int (*fb_set_par)(struct fb_info *info);
 
-    /* set color register */
-    int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
-			     unsigned blue, unsigned transp,
-			     struct fb_info * info);
-
-    /* blank display */
-    int (*fb_blank)(int blank, struct fb_info *info);
-
-    /* pan display */
-	int (*fb_pan_display) (struct fb_var_screeninfo * var,
-			       struct fb_info * info);
-
-    /* draws a rectangle */
-	void (*fb_fillrect) (struct fb_info * info,
-			     const struct fb_fillrect * rect);
-    /* Copy data from area to another */
-	void (*fb_copyarea) (struct fb_info * info,
-			     const struct fb_copyarea * region);
-    /* Draws a image to the display */
-	void (*fb_imageblit) (struct fb_info * info,
-			      const struct fb_image * image);
-
-    /* Draws cursor */
-	int (*fb_cursor) (struct fb_info * info,
-			  struct fb_cursor * cursor);
-
-    /* Rotates the display */
-    void (*fb_rotate)(struct fb_info *info, int angle);
-
-    /* wait for blit idle, optional */
-    int (*fb_sync)(struct fb_info *info);		
-
-    /* perform fb specific ioctl (optional) */
-	int (*fb_ioctl) (struct inode * inode, struct file * file,
-			 unsigned int cmd, unsigned long arg,
-			 struct fb_info * info);
-
-    /* perform fb specific mmap */
-	int (*fb_mmap) (struct fb_info * info, struct file * file,
-			struct vm_area_struct * vma);
+	/* set color register */
+	int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp, struct fb_info *info);
+
+	/* blank display */
+	int (*fb_blank)(int blank, struct fb_info *info);
+
+	/* pan display */
+	int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
+
+	/* Draws a rectangle */
+	void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
+	/* Copy data from area to another */
+	void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
+	/* Draws a image to the display */
+	void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
+
+	/* Draws cursor */
+	int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
+
+	/* Rotates the display */
+	void (*fb_rotate)(struct fb_info *info, int angle);
+
+	/* wait for blit idle, optional */
+	int (*fb_sync)(struct fb_info *info);
+
+	/* perform fb specific ioctl (optional) */
+	int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
+			unsigned long arg, struct fb_info *info);
+
+	/* perform fb specific mmap */
+	int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
 };
 
 struct fb_info {
@@ -459,6 +448,7 @@
 	struct fb_cursor cursor;	/* Current cursor */	
 	struct work_struct queue;	/* Framebuffer event queue */
 	struct fb_pixmap pixmap;	/* Image Hardware Mapper */
+	struct fb_pixmap sprite;	/* Cursor hardware Mapper */
 	struct fb_cmap cmap;		/* Current cmap */
 	struct fb_ops *fbops;
 	char *screen_base;		/* Virtual address */
@@ -537,14 +527,16 @@
 extern int unregister_framebuffer(struct fb_info *fb_info);
 extern int fb_prepare_logo(struct fb_info *fb_info);
 extern int fb_show_logo(struct fb_info *fb_info);
-extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size);
-extern void move_buf_unaligned(struct fb_info *info, u8 * dst, u8 * src,
-				u32 d_pitch, u32 height, u32 mask,
-				u32 shift_high, u32 shift_low, u32 mod,
-				u32 idx);
-extern void move_buf_aligned(struct fb_info *info, u8 * dst, u8 * src,
-				u32 d_pitch, u32 s_pitch, u32 height);
+extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
+extern void fb_move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
+				u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+				u32 height, u32 shift_high, u32 shift_low, u32 mod);
+extern void fb_move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
+				u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+				u32 height);
+extern void fb_load_cursor_image(struct fb_info *);
 extern void fb_set_suspend(struct fb_info *info, int state);
+
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 
--- diff/include/linux/fs.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/fs.h	2004-02-18 09:04:02.000000000 +0000
@@ -137,6 +137,7 @@
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
 #define S_DIRSYNC	128	/* Directory modifications are synchronous */
+#define S_NOCMTIME	256	/* Do not update file c/mtime */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -170,6 +171,7 @@
 #define IS_ONE_SECOND(inode)	__IS_FLG(inode, MS_ONE_SECOND)
 
 #define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
+#define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -336,6 +338,7 @@
 	spinlock_t		private_lock;	/* for use by the address_space */
 	struct list_head	private_list;	/* ditto */
 	struct address_space	*assoc_mapping;	/* ditto */
+	struct rw_semaphore	wb_rwsema;	/* serialize SYNC writebacks */
 };
 
 struct block_device {
@@ -376,6 +379,7 @@
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
+	struct list_head	i_sb_list;
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
@@ -395,6 +399,7 @@
 	unsigned short          i_bytes;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct semaphore	i_sem;
+	struct rw_semaphore	i_alloc_sem;
 	struct inode_operations	*i_op;
 	struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
 	struct super_block	*i_sb;
@@ -507,6 +512,8 @@
 	unsigned long prev_page;	/* Cache last read() position */
 	unsigned long ahead_start;	/* Ahead window */
 	unsigned long ahead_size;
+	unsigned long serial_cnt;	/* measure of sequentiality */
+	unsigned long average;		/* another measure of sequentiality */
 	unsigned long ra_pages;		/* Maximum readahead window */
 	unsigned long mmap_hit;		/* Cache hit stat for mmap accesses */
 	unsigned long mmap_miss;	/* Cache miss stat for mmap accesses */
@@ -700,6 +707,7 @@
 	atomic_t		s_active;
 	void                    *s_security;
 
+	struct list_head	s_inodes;	/* all inodes */
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
@@ -1045,6 +1053,7 @@
 			void *data);
 struct super_block *get_sb_pseudo(struct file_system_type *, char *,
 			struct super_operations *ops, unsigned long);
+void unnamed_dev_init(void);
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
@@ -1117,10 +1126,7 @@
 
 /* fs/open.c */
 
-asmlinkage long sys_open(const char __user *, int, int);
-asmlinkage long sys_close(unsigned int);	/* yes, it's really unsigned */
 extern int do_truncate(struct dentry *, loff_t start);
-
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
 extern int filp_close(struct file *, fl_owner_t id);
@@ -1213,6 +1219,7 @@
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_flush(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
+extern int filemap_write_and_wait(struct address_space *mapping);
 extern void sync_supers(void);
 extern void sync_filesystems(int wait);
 extern void emergency_sync(void);
@@ -1324,9 +1331,6 @@
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
 extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb,
 	const struct iovec *iov, loff_t offset, unsigned long nr_segs);
-extern int blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, 
-	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
-	unsigned long nr_segs, get_blocks_t *get_blocks, dio_iodone_t *end_io);
 extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, 
 	unsigned long nr_segs, loff_t *ppos);
 ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, 
@@ -1348,6 +1352,32 @@
 				actor);
 }
 
+int __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+	struct block_device *bdev, const struct iovec *iov, loff_t offset,
+	unsigned long nr_segs, get_blocks_t get_blocks, dio_iodone_t end_io,
+	int needs_special_locking);
+
+/*
+ * For filesystems which need locking between buffered and direct access
+ */
+static inline int blockdev_direct_IO(int rw, struct kiocb *iocb,
+	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	dio_iodone_t end_io)
+{
+	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+				nr_segs, get_blocks, end_io, 1);
+}
+
+static inline int blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
+	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks,
+	dio_iodone_t end_io)
+{
+	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+				nr_segs, get_blocks, end_io, 0);
+}
+
 extern struct file_operations generic_ro_fops;
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
--- diff/include/linux/futex.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/linux/futex.h	2004-02-18 09:04:02.000000000 +0000
@@ -10,10 +10,6 @@
 #define FUTEX_REQUEUE (3)
 
 
-asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
-			  struct timespec __user *utime, u32 __user *uaddr2);
-
-
 long do_futex(unsigned long uaddr, int op, int val,
 		unsigned long timeout, unsigned long uaddr2, int val2);
 
--- diff/include/linux/genhd.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/genhd.h	2004-02-18 09:04:02.000000000 +0000
@@ -64,10 +64,11 @@
 	int policy, partno;
 };
 
-#define GENHD_FL_REMOVABLE  1
-#define GENHD_FL_DRIVERFS  2
-#define GENHD_FL_CD	8
-#define GENHD_FL_UP	16
+#define GENHD_FL_REMOVABLE			1
+#define GENHD_FL_DRIVERFS			2
+#define GENHD_FL_CD				8
+#define GENHD_FL_UP				16
+#define GENHD_FL_SUPPRESS_PARTITION_INFO	32
 
 struct disk_stats {
 	unsigned read_sectors, write_sectors;
--- diff/include/linux/hdlc.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/linux/hdlc.h	2004-02-18 09:04:02.000000000 +0000
@@ -75,7 +75,7 @@
 
 
 typedef struct pvc_device_struct {
-	struct hdlc_device_struct *master;
+	struct net_device *master;
 	struct net_device *main;
 	struct net_device *ether; /* bridged Ethernet interface */
 	struct pvc_device_struct *next;	/* Sorted in ascending DLCI order */
@@ -96,11 +96,10 @@
 
 typedef struct hdlc_device_struct {
 	/* To be initialized by hardware driver */
-	struct net_device netdev; /* master net device - must be first */
 	struct net_device_stats stats;
 
 	/* used by HDLC layer to take control over HDLC device from hw driver*/
-	int (*attach)(struct hdlc_device_struct *hdlc,
+	int (*attach)(struct net_device *dev,
 		      unsigned short encoding, unsigned short parity);
 
 	/* hardware driver must handle this instead of dev->hard_start_xmit */
@@ -109,13 +108,13 @@
 
 	/* Things below are for HDLC layer internal use only */
 	struct {
-		int (*open)(struct hdlc_device_struct *hdlc);
-		void (*close)(struct hdlc_device_struct *hdlc);
+		int (*open)(struct net_device *dev);
+		void (*close)(struct net_device *dev);
 
 		/* if open & DCD */
-		void (*start)(struct hdlc_device_struct *hdlc);
+		void (*start)(struct net_device *dev);
 		/* if open & !DCD */
-		void (*stop)(struct hdlc_device_struct *hdlc);
+		void (*stop)(struct net_device *dev);
 
 		void (*detach)(struct hdlc_device_struct *hdlc);
 		int (*netif_rx)(struct sk_buff *skb);
@@ -167,16 +166,17 @@
 					      int new_mtu);
 		}ppp;
 	}state;
+	void *priv;
 }hdlc_device;
 
 
 
-int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
-int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
-int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
-int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
-int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
-int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr);
+int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
+int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
+int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
+int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr);
+int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
 
 
 /* Exported from hdlc.o */
@@ -185,19 +185,14 @@
 int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 /* Must be used by hardware driver on module startup/exit */
-int register_hdlc_device(hdlc_device *hdlc);
-void unregister_hdlc_device(hdlc_device *hdlc);
-
-
-static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
-{
-	return &hdlc->netdev;
-}
+int register_hdlc_device(struct net_device *dev);
+void unregister_hdlc_device(struct net_device *dev);
 
+struct net_device *alloc_hdlcdev(void *priv);
 
 static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
-	return (hdlc_device*)dev;
+	return netdev_priv(dev);
 }
 
 
@@ -207,12 +202,6 @@
 }
 
 
-static __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
-{
-	return hdlc_to_dev(hdlc)->name;
-}
-
-
 static __inline__ void debug_frame(const struct sk_buff *skb)
 {
 	int i;
@@ -229,11 +218,11 @@
 
 
 /* Must be called by hardware driver when HDLC device is being opened */
-int hdlc_open(hdlc_device *hdlc);
+int hdlc_open(struct net_device *dev);
 /* Must be called by hardware driver when HDLC device is being closed */
-void hdlc_close(hdlc_device *hdlc);
+void hdlc_close(struct net_device *dev);
 /* Called by hardware driver when DCD line level changes */
-void hdlc_set_carrier(int on, hdlc_device *hdlc);
+void hdlc_set_carrier(int on, struct net_device *dev);
 
 /* May be used by hardware driver to gain control over HDLC device */
 static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
@@ -244,6 +233,12 @@
 }
 
 
+static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
+{
+	return &dev_to_hdlc(dev)->stats;
+}
+
+
 static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb,
 						 struct net_device *dev)
 {
--- diff/include/linux/hiddev.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/linux/hiddev.h	2004-02-18 09:04:02.000000000 +0000
@@ -39,33 +39,33 @@
 };
 
 struct hiddev_devinfo {
-	unsigned int bustype;
-	unsigned int busnum;
-	unsigned int devnum;
-	unsigned int ifnum;
-	short vendor;
-	short product;
-	short version;
-	unsigned num_applications;
+	__u32 bustype;
+	__u32 busnum;
+	__u32 devnum;
+	__u32 ifnum;
+	__s16 vendor;
+	__s16 product;
+	__s16 version;
+	__u32 num_applications;
 };
 
 struct hiddev_collection_info {
-	unsigned index;
-	unsigned type;
-	unsigned usage;
-	unsigned level;
+	__u32 index;
+	__u32 type;
+	__u32 usage;
+	__u32 level;
 };
 
 #define HID_STRING_SIZE 256
 struct hiddev_string_descriptor {
-	int index;
+	__s32 index;
 	char value[HID_STRING_SIZE];
 };
 
 struct hiddev_report_info {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned num_fields;
+	__u32 report_type;
+	__u32 report_id;
+	__u32 num_fields;
 };
 
 /* To do a GUSAGE/SUSAGE, fill in at least usage_code,  report_type and 
@@ -88,20 +88,20 @@
 #define HID_REPORT_TYPE_MAX     3
 
 struct hiddev_field_info {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned field_index;
-	unsigned maxusage;
-	unsigned flags;
-	unsigned physical;		/* physical usage for this field */
-	unsigned logical;		/* logical usage for this field */
-	unsigned application;		/* application usage for this field */
+	__u32 report_type;
+	__u32 report_id;
+	__u32 field_index;
+	__u32 maxusage;
+	__u32 flags;
+	__u32 physical;		/* physical usage for this field */
+	__u32 logical;		/* logical usage for this field */
+	__u32 application;		/* application usage for this field */
 	__s32 logical_minimum;
 	__s32 logical_maximum;
 	__s32 physical_minimum;
 	__s32 physical_maximum;
-	unsigned unit_exponent;
-	unsigned unit;
+	__u32 unit_exponent;
+	__u32 unit;
 };
 
 /* Fill in report_type, report_id and field_index to get the information on a
@@ -118,14 +118,22 @@
 #define HID_FIELD_BUFFERED_BYTE		0x100
 
 struct hiddev_usage_ref {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned field_index;
-	unsigned usage_index;
-	unsigned usage_code;
+	__u32 report_type;
+	__u32 report_id;
+	__u32 field_index;
+	__u32 usage_index;
+	__u32 usage_code;
 	__s32 value;
 };
 
+/* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
+ * It really manifests itself as setting the value of consecutive usages */
+struct hiddev_usage_ref_multi {
+	struct hiddev_usage_ref uref;
+	__u32 num_values;
+	__s32 values[HID_MAX_USAGES];
+};
+
 /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
  * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has
  * been sent by the device 
@@ -161,6 +169,10 @@
 #define HIDIOCGCOLLECTIONINFO	_IOWR('H', 0x11, struct hiddev_collection_info)
 #define HIDIOCGPHYS(len)	_IOC(_IOC_READ, 'H', 0x12, len)
 
+/* For writing/reading to multiple/consecutive usages */
+#define HIDIOCGUSAGES		_IOWR('H', 0x13, struct hiddev_usage_ref_multi)
+#define HIDIOCSUSAGES		_IOW('H', 0x14, struct hiddev_usage_ref_multi)
+
 /* 
  * Flags to be used in HIDIOCSFLAG
  */
--- diff/include/linux/idr.h	2003-05-21 11:50:00.000000000 +0100
+++ source/include/linux/idr.h	2004-02-18 09:04:02.000000000 +0000
@@ -58,7 +58,7 @@
  */
 
 void *idr_find(struct idr *idp, int id);
-int idr_pre_get(struct idr *idp);
+int idr_pre_get(struct idr *idp, unsigned gfp_mask);
 int idr_get_new(struct idr *idp, void *ptr);
 void idr_remove(struct idr *idp, int id);
 void idr_init(struct idr *idp);
--- diff/include/linux/if_bonding.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/if_bonding.h	2004-02-18 09:04:02.000000000 +0000
@@ -32,6 +32,9 @@
  * 2003/05/01 - Amir Noam <amir.noam at intel dot com>
  *	- Added ABI version control to restore compatibility between
  *	  new/old ifenslave and new/old bonding.
+ *
+ * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
+ *	- Code cleanup and style changes
  */
 
 #ifndef _LINUX_IF_BONDING_H
@@ -86,7 +89,7 @@
 typedef struct ifslave
 {
 	__s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */
-	__s8 slave_name[IFNAMSIZ];
+	char slave_name[IFNAMSIZ];
 	__s8 link;
 	__s8 state;
 	__u32  link_failure_count;
--- diff/include/linux/init_task.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/init_task.h	2004-02-18 09:04:02.000000000 +0000
@@ -57,6 +57,8 @@
 	.siglock	= SPIN_LOCK_UNLOCKED, 		\
 }
 
+extern struct group_info init_groups;
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -88,6 +90,7 @@
 	.real_timer	= {						\
 		.function	= it_real_fn				\
 	},								\
+	.group_info	= &init_groups,					\
 	.cap_effective	= CAP_INIT_EFF_SET,				\
 	.cap_inheritable = CAP_INIT_INH_SET,				\
 	.cap_permitted	= CAP_FULL_SET,					\
--- diff/include/linux/interrupt.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/linux/interrupt.h	2004-02-18 09:04:02.000000000 +0000
@@ -211,6 +211,7 @@
 }
 
 extern void tasklet_kill(struct tasklet_struct *t);
+extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
 extern void tasklet_init(struct tasklet_struct *t,
 			 void (*func)(unsigned long), unsigned long data);
 
--- diff/include/linux/ioctl32.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/linux/ioctl32.h	2004-02-18 09:04:02.000000000 +0000
@@ -3,8 +3,6 @@
 
 struct file;
 
-extern long sys_ioctl(unsigned int, unsigned int, unsigned long);
-
 /* 
  * Register an 32bit ioctl translation handler for ioctl cmd.
  *
--- diff/include/linux/isdn.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/linux/isdn.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,9 +1,10 @@
-/* Linux ISDN subsystem, main header
+/* $Id: isdn.h,v 1.125.2.3 2004/02/10 01:07:14 keil Exp $
+ *
+ * Main header for the Linux ISDN subsystem (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- * Copyright 2000-2002  by Kai Germaschewski (kai@germaschewski.name)
  * 
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -14,7 +15,6 @@
 #define __ISDN_H__
 
 #include <linux/ioctl.h>
-#include <linux/isdn/fsm.h>
 
 #ifdef CONFIG_COBALT_MICRO_SERVER
 /* Save memory */
@@ -75,7 +75,7 @@
 #define ISDN_NET_ENCAP_UIHDLC     5
 #define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive    */
 #define ISDN_NET_ENCAP_X25IFACE   7 /* Documentation/networking/x25-iface.txt*/
-#define ISDN_NET_ENCAP_NR         8
+#define ISDN_NET_ENCAP_MAX_ENCAP  ISDN_NET_ENCAP_X25IFACE
 
 /* Facility which currently uses an ISDN-channel */
 #define ISDN_USAGE_NONE       0
@@ -94,48 +94,48 @@
 #define ISDN_CMSGLEN	     50	 /* Length of CONNECT-Message to add for Modem */
 
 #define ISDN_MSNLEN          32
-#define NET_DV	0x06  /* Data version for isdn_net_ioctl_cfg   */
-#define TTY_DV	0x06  /* Data version for iprofd etc.          */
+#define NET_DV 0x06  /* Data version for isdn_net_ioctl_cfg   */
+#define TTY_DV 0x06  /* Data version for iprofd etc.          */
 
-#define INF_DV	0x01  /* Data version for /dev/isdninfo        */
+#define INF_DV 0x01  /* Data version for /dev/isdninfo        */
 
 typedef struct {
-	char		drvid[25];
-	unsigned long	arg;
+  char drvid[25];
+  unsigned long arg;
 } isdn_ioctl_struct;
 
 typedef struct {
-	char	name[10];
-	char	phone[ISDN_MSNLEN];
-	int	outgoing;
+  char name[10];
+  char phone[ISDN_MSNLEN];
+  int  outgoing;
 } isdn_net_ioctl_phone;
 
 typedef struct {
-	char	name[10];	/* Name of interface                     */
-	char	master[10];	/* Name of Master for Bundling           */
-	char	slave[10];	/* Name of Slave for Bundling            */
-	char	eaz[256];	/* EAZ/MSN                               */
-	char	drvid[25];	/* DriverId for Bindings                 */
-	int	onhtime;	/* Hangup-Timeout                        */
-	int	charge;		/* Charge-Units                          */
-	int	l2_proto;	/* Layer-2 protocol                      */
-	int	l3_proto;	/* Layer-3 protocol                      */
-	int	p_encap;	/* Encapsulation                         */
-	int	exclusive;	/* Channel, if bound exclusive           */
-	int	dialmax;	/* Dial Retry-Counter                    */
-	int	slavedelay;	/* Delay until slave starts up           */
-	int	cbdelay;	/* Delay before Callback                 */
-	int	chargehup;	/* Flag: Charge-Hangup                   */
-	int	ihup;		/* Flag: Hangup-Timeout on incoming line */
-	int	secure;		/* Flag: Secure                          */
-	int	callback;	/* Flag: Callback                        */
-	int	cbhup;		/* Flag: Reject Call before Callback     */
-	int	pppbind;	/* ippp device for bindings              */
-	int	chargeint;	/* Use fixed charge interval length      */
-	int	triggercps;	/* BogoCPS needed for triggering slave   */
-	int	dialtimeout;	/* Dial-Timeout                          */
-	int	dialwait;	/* Time to wait after failed dial        */
-	int	dialmode;	/* Flag: off / on / auto                 */
+  char name[10];     /* Name of interface                     */
+  char master[10];   /* Name of Master for Bundling           */
+  char slave[10];    /* Name of Slave for Bundling            */
+  char eaz[256];     /* EAZ/MSN                               */
+  char drvid[25];    /* DriverId for Bindings                 */
+  int  onhtime;      /* Hangup-Timeout                        */
+  int  charge;       /* Charge-Units                          */
+  int  l2_proto;     /* Layer-2 protocol                      */
+  int  l3_proto;     /* Layer-3 protocol                      */
+  int  p_encap;      /* Encapsulation                         */
+  int  exclusive;    /* Channel, if bound exclusive           */
+  int  dialmax;      /* Dial Retry-Counter                    */
+  int  slavedelay;   /* Delay until slave starts up           */
+  int  cbdelay;      /* Delay before Callback                 */
+  int  chargehup;    /* Flag: Charge-Hangup                   */
+  int  ihup;         /* Flag: Hangup-Timeout on incoming line */
+  int  secure;       /* Flag: Secure                          */
+  int  callback;     /* Flag: Callback                        */
+  int  cbhup;        /* Flag: Reject Call before Callback     */
+  int  pppbind;      /* ippp device for bindings              */
+  int  chargeint;    /* Use fixed charge interval length      */
+  int  triggercps;   /* BogoCPS needed for triggering slave   */
+  int  dialtimeout;  /* Dial-Timeout                          */
+  int  dialwait;     /* Time to wait after failed dial        */
+  int  dialmode;     /* Flag: off / on / auto                 */
 } isdn_net_ioctl_cfg;
 
 #define ISDN_NET_DIALMODE_MASK  0xC0    /* bits for status                */
@@ -150,6 +150,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
+#include <asm/segment.h>
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -178,6 +179,8 @@
  * the correspondent code in isdn.c
  */
 
+#define ISDN_MINOR_B        0
+#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 #define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_PPP      128
@@ -192,7 +195,6 @@
 
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
-#include <linux/if_pppvar.h>
 
 #include <linux/isdn_ppp.h>
 #endif
@@ -231,9 +233,177 @@
 #define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \
                              ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)     )
 
+/* Timer-delays and scheduling-flags */
+#define ISDN_TIMER_RES         4                         /* Main Timer-Resolution   */
+#define ISDN_TIMER_02SEC       (HZ/ISDN_TIMER_RES/5)     /* Slow-Timer1 .2 sec      */
+#define ISDN_TIMER_1SEC        (HZ/ISDN_TIMER_RES)       /* Slow-Timer2 1 sec       */
+#define ISDN_TIMER_RINGING     5 /* tty RINGs = ISDN_TIMER_1SEC * this factor       */
+#define ISDN_TIMER_KEEPINT    10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
+#define ISDN_TIMER_MODEMREAD   1
+#define ISDN_TIMER_MODEMPLUS   2
+#define ISDN_TIMER_MODEMRING   4
+#define ISDN_TIMER_MODEMXMIT   8
+#define ISDN_TIMER_NETDIAL    16 
+#define ISDN_TIMER_NETHANGUP  32
+#define ISDN_TIMER_CARRIER   256 /* Wait for Carrier */
+#define ISDN_TIMER_FAST      (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
+                              ISDN_TIMER_MODEMXMIT)
+#define ISDN_TIMER_SLOW      (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
+                              ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER)
+
+/* Timeout-Values for isdn_net_dial() */
+#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+
 /* GLOBAL_FLAGS */
 #define ISDN_GLOBAL_STOPPED 1
 
+/*=================== Start of ip-over-ISDN stuff =========================*/
+
+/* Feature- and status-flags for a net-interface */
+#define ISDN_NET_CONNECTED  0x01       /* Bound to ISDN-Channel             */
+#define ISDN_NET_SECURE     0x02       /* Accept calls from phonelist only  */
+#define ISDN_NET_CALLBACK   0x04       /* activate callback                 */
+#define ISDN_NET_CBHUP      0x08       /* hangup before callback            */
+#define ISDN_NET_CBOUT      0x10       /* remote machine does callback      */
+
+#define ISDN_NET_MAGIC      0x49344C02 /* for paranoia-checking             */
+
+/* Phone-list-element */
+typedef struct {
+  void *next;
+  char num[ISDN_MSNLEN];
+} isdn_net_phone;
+
+/*
+   Principles when extending structures for generic encapsulation protocol
+   ("concap") support:
+   - Stuff which is hardware specific (here i4l-specific) goes in 
+     the netdev -> local structure (here: isdn_net_local)
+   - Stuff which is encapsulation protocol specific goes in the structure
+     which holds the linux device structure (here: isdn_net_device)
+*/
+
+/* Local interface-data */
+typedef struct isdn_net_local_s {
+  ulong                  magic;
+  char                   name[10];     /* Name of device                   */
+  struct net_device_stats stats;       /* Ethernet Statistics              */
+  int                    isdn_device;  /* Index to isdn-device             */
+  int                    isdn_channel; /* Index to isdn-channel            */
+  int			 ppp_slot;     /* PPPD device slot number          */
+  int                    pre_device;   /* Preselected isdn-device          */
+  int                    pre_channel;  /* Preselected isdn-channel         */
+  int                    exclusive;    /* If non-zero idx to reserved chan.*/
+  int                    flags;        /* Connection-flags                 */
+  int                    dialretry;    /* Counter for Dialout-retries      */
+  int                    dialmax;      /* Max. Number of Dial-retries      */
+  int                    cbdelay;      /* Delay before Callback starts     */
+  int                    dtimer;       /* Timeout-counter for dialing      */
+  char                   msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
+  u_char                 cbhup;        /* Flag: Reject Call before Callback*/
+  u_char                 dialstate;    /* State for dialing                */
+  u_char                 p_encap;      /* Packet encapsulation             */
+                                       /*   0 = Ethernet over ISDN         */
+				       /*   1 = RAW-IP                     */
+                                       /*   2 = IP with type field         */
+  u_char                 l2_proto;     /* Layer-2-protocol                 */
+				       /* See ISDN_PROTO_L2..-constants in */
+                                       /* isdnif.h                         */
+                                       /*   0 = X75/LAPB with I-Frames     */
+				       /*   1 = X75/LAPB with UI-Frames    */
+				       /*   2 = X75/LAPB with BUI-Frames   */
+				       /*   3 = HDLC                       */
+  u_char                 l3_proto;     /* Layer-3-protocol                 */
+				       /* See ISDN_PROTO_L3..-constants in */
+                                       /* isdnif.h                         */
+                                       /*   0 = Transparent                */
+  int                    huptimer;     /* Timeout-counter for auto-hangup  */
+  int                    charge;       /* Counter for charging units       */
+  ulong                  chargetime;   /* Timer for Charging info          */
+  int                    hupflags;     /* Flags for charge-unit-hangup:    */
+				       /* bit0: chargeint is invalid       */
+				       /* bit1: Getting charge-interval    */
+                                       /* bit2: Do charge-unit-hangup      */
+                                       /* bit3: Do hangup even on incoming */
+  int                    outgoing;     /* Flag: outgoing call              */
+  int                    onhtime;      /* Time to keep link up             */
+  int                    chargeint;    /* Interval between charge-infos    */
+  int                    onum;         /* Flag: at least 1 outgoing number */
+  int                    cps;          /* current speed of this interface  */
+  int                    transcount;   /* byte-counter for cps-calculation */
+  int                    sqfull;       /* Flag: netdev-queue overloaded    */
+  ulong                  sqfull_stamp; /* Start-Time of overload           */
+  ulong                  slavedelay;   /* Dynamic bundling delaytime       */
+  int                    triggercps;   /* BogoCPS needed for trigger slave */
+  isdn_net_phone         *phone[2];    /* List of remote-phonenumbers      */
+				       /* phone[0] = Incoming Numbers      */
+				       /* phone[1] = Outgoing Numbers      */
+  isdn_net_phone         *dial;        /* Pointer to dialed number         */
+  struct net_device      *master;      /* Ptr to Master device for slaves  */
+  struct net_device      *slave;       /* Ptr to Slave device for masters  */
+  struct isdn_net_local_s *next;       /* Ptr to next link in bundle       */
+  struct isdn_net_local_s *last;       /* Ptr to last link in bundle       */
+  struct isdn_net_dev_s  *netdev;      /* Ptr to netdev                    */
+  struct sk_buff_head    super_tx_queue; /* List of supervisory frames to  */
+	                               /* be transmitted asap              */
+  atomic_t frame_cnt;                  /* number of frames currently       */
+                        	       /* queued in HL driver              */    
+                                       /* Ptr to orig. hard_header_cache   */
+  spinlock_t             xmit_lock;    /* used to protect the xmit path of */
+                                       /* a particular channel (including  */
+                                       /* the frame_cnt                    */
+
+  int                    (*org_hhc)(
+				    struct neighbour *neigh,
+				    struct hh_cache *hh);
+                                       /* Ptr to orig. header_cache_update */
+  void                   (*org_hcu)(struct hh_cache *,
+				    struct net_device *,
+                                    unsigned char *);
+  int  pppbind;                        /* ippp device for bindings         */
+  int					dialtimeout;	/* How long shall we try on dialing? (jiffies) */
+  int					dialwait;		/* How long shall we wait after failed attempt? (jiffies) */
+  ulong					dialstarted;	/* jiffies of first dialing-attempt */
+  ulong					dialwait_timer;	/* jiffies of earliest next dialing-attempt */
+  int					huptimeout;		/* How long will the connection be up? (seconds) */
+#ifdef CONFIG_ISDN_X25
+  struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
+#endif
+  /* use an own struct for that in later versions */
+  ulong cisco_myseq;                   /* Local keepalive seq. for Cisco   */
+  ulong cisco_mineseen;                /* returned keepalive seq. from remote */
+  ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
+  int cisco_keepalive_period;		/* keepalive period */
+  ulong cisco_last_slarp_in;		/* jiffie of last keepalive packet we received */
+  char cisco_line_state;		/* state of line according to keepalive packets */
+  char cisco_debserint;			/* debugging flag of cisco hdlc with slarp */
+  struct timer_list cisco_timer;
+  struct work_struct tqueue;
+} isdn_net_local;
+
+/* the interface itself */
+typedef struct isdn_net_dev_s {
+  isdn_net_local *local;
+  isdn_net_local *queue;               /* circular list of all bundled
+					  channels, which are currently
+					  online                           */
+  spinlock_t queue_lock;               /* lock to protect queue            */
+  void *next;                          /* Pointer to next isdn-interface   */
+  struct net_device dev;               /* interface to upper levels        */
+#ifdef CONFIG_ISDN_PPP
+  ippp_bundle * pb;		/* pointer to the common bundle structure
+   			         * with the per-bundle data */
+#endif
+#ifdef CONFIG_ISDN_X25
+  struct concap_proto  *cprot; /* connection oriented encapsulation protocol */
+#endif
+
+} isdn_net_dev;
+
+/*===================== End of ip-over-ISDN stuff ===========================*/
+
 /*======================= Start of ISDN-tty stuff ===========================*/
 
 #define ISDN_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
@@ -250,21 +420,22 @@
 #define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
 #define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
+#define ISDN_SERIAL_TYPE_NORMAL            1
+#define ISDN_SERIAL_TYPE_CALLOUT           2
 
 #ifdef CONFIG_ISDN_AUDIO
 /* For using sk_buffs with audio we need some private variables
  * within each sk_buff. For this purpose, we declare a struct here,
- * and put it always at skb->head. A few macros help accessing the
- * variables. Of course, we need to check skb_headroom prior to
- * any access.
+ * and put it always at the private skb->cb data array. A few macros help
+ * accessing the variables.
  */
-typedef struct _isdnaudio_header {
+typedef struct _isdn_audio_data {
   unsigned short dle_count;
   unsigned char  lock;
-} isdnaudio_header;
+} isdn_audio_data_t;
 
-#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdnaudio_header*)skb->head)->dle_count)
-#define ISDN_AUDIO_SKB_LOCK(skb) (((isdnaudio_header*)skb->head)->lock)
+#define ISDN_AUDIO_SKB_DLECOUNT(skb)	(((isdn_audio_data_t *)&skb->cb[0])->dle_count)
+#define ISDN_AUDIO_SKB_LOCK(skb)	(((isdn_audio_data_t *)&skb->cb[0])->lock)
 #endif
 
 /* Private data of AT-command-interpreter */
@@ -283,7 +454,8 @@
 #endif
 	int          mdmcmdl;                    /* Length of Modem-Commandbuffer      */
 	int          pluscount;                  /* Counter for +++ sequence           */
-	unsigned long lastplus;                  /* Timestamp of last +                */
+	u_long       lastplus;                   /* Timestamp of last +                */
+	int	     carrierwait;                /* Seconds of carrier waiting         */
 	char         mdmcmd[255];                /* Modem-Commandbuffer                */
 	unsigned int charge;                     /* Charge units of current connection */
 } atemu;
@@ -300,13 +472,15 @@
   int			line;
   int			count;		 /* # of fd on device              */
   int			blocked_open;	 /* # of blocked opens             */
+  long			session;	 /* Session of opening process     */
+  long			pgrp;		 /* pgrp of opening process        */
   int                   online;          /* 1 = B-Channel is up, drop data */
 					 /* 2 = B-Channel is up, deliver d.*/
   int                   dialing;         /* Dial in progress or ATA        */
   int                   rcvsched;        /* Receive needs schedule         */
-  struct isdn_slot     *isdn_slot;	 /* Ptr to isdn-driver/channel     */
-  struct sk_buff_head   rpqueue;         /* Queue of recv'd packets        */
-  int                   rcvcount;        /* Byte-counters for B rx         */
+  int                   isdn_driver;	 /* Index to isdn-driver           */
+  int                   isdn_channel;    /* Index to isdn-channel          */
+  int                   drv_index;       /* Index to dev->usage            */
   int                   ncarrier;        /* Flag: schedule NO CARRIER      */
   unsigned char         last_cause[8];   /* Last cause message             */
   unsigned char         last_num[ISDN_MSNLEN];
@@ -323,7 +497,6 @@
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
   atomic_t              xmit_lock;       /* Semaphore for isdn_tty_write   */
 #ifdef CONFIG_ISDN_AUDIO
-  unsigned long         DLEflag;         /* Insert DLE at next read     */
   int                   vonline;         /* Voice-channel status           */
 					 /* Bit 0 = recording              */
 					 /* Bit 1 = playback               */
@@ -340,16 +513,25 @@
 #endif
   struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
   atemu                 emu;             /* AT-emulator data               */
-  struct timer_list     escape_timer;    /* to recognize +++ escape        */
-  struct timer_list     ring_timer;      /* for writing 'RING' responses   */
-  struct timer_list     connect_timer;   /* waiting for CONNECT            */
-  struct timer_list     read_timer;      /* read incoming data             */
+  struct termios	normal_termios;  /* For saving termios structs     */
+  struct termios	callout_termios;
   wait_queue_head_t	open_wait, close_wait;
   struct semaphore      write_sem;
+  spinlock_t	        readlock;
 } modem_info;
 
 #define ISDN_MODEM_WINSIZE 8
 
+/* Description of one ISDN-tty */
+typedef struct _isdn_modem {
+  int                refcount;				/* Number of opens        */
+  struct tty_driver  *tty_modem;			/* tty-device             */
+  struct tty_struct  *modem_table[ISDN_MAX_CHANNELS];	/* ?? copied from Orig    */
+  struct termios     *modem_termios[ISDN_MAX_CHANNELS];
+  struct termios     *modem_termios_locked[ISDN_MAX_CHANNELS];
+  modem_info         info[ISDN_MAX_CHANNELS];	   /* Private data           */
+} isdn_modem_t;
+
 /*======================= End of ISDN-tty stuff ============================*/
 
 /*======================== Start of V.110 stuff ============================*/
@@ -384,23 +566,72 @@
 	char *private;
 } infostruct;
 
+#define DRV_FLAG_RUNNING 1
+#define DRV_FLAG_REJBUS  2
+#define DRV_FLAG_LOADED  4
+
+/* Description of hardware-level-driver */
+typedef struct _isdn_driver {
+	ulong               online;           /* Channel-Online flags             */
+	ulong               flags;            /* Misc driver Flags                */
+	int                 locks;            /* Number of locks for this driver  */
+	int                 channels;         /* Number of channels               */
+	wait_queue_head_t   st_waitq;         /* Wait-Queue for status-read's     */
+	int                 maxbufsize;       /* Maximum Buffersize supported     */
+	unsigned long       pktcount;         /* Until now: unused                */
+	int                 stavail;          /* Chars avail on Status-device     */
+	isdn_if            *interface;        /* Interface to driver              */
+	int                *rcverr;           /* Error-counters for B-Ch.-receive */
+	int                *rcvcount;         /* Byte-counters for B-Ch.-receive  */
+#ifdef CONFIG_ISDN_AUDIO
+	unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
+#endif
+	struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
+	wait_queue_head_t  *rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
+	wait_queue_head_t  *snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
+	char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
+} isdn_driver_t;
+
 /* Main driver-data */
-typedef struct _isdn_dev_t {
-	unsigned short		flags;		/* Bitmapped Flags:           */
-	int			channels;	/* Current number of channels */
-	int			net_verbose;	/* Verbose-Flag               */
-	int			modempoll;	/* Flag: tty-read active      */
-	int			tflags;		/* Timer-Flags:               */
-						/*  see ISDN_TIMER_..defines  */
-	int			global_flags;
-	infostruct		*infochain;	/* List of open info-devs.    */
-	wait_queue_head_t	info_waitq;	/* Wait-Queue for isdninfo    */
-	struct task_struct	*profd;		/* For iprofd                 */
-	struct semaphore	sem;		/* serialize list access*/
-	unsigned long		global_features; 
-} isdn_dev_t;
+typedef struct isdn_devt {
+	struct module     *owner;
+	spinlock_t	  lock;
+	unsigned short    flags;		      /* Bitmapped Flags:           */
+	int               drivers;		      /* Current number of drivers  */
+	int               channels;		      /* Current number of channels */
+	int               net_verbose;                /* Verbose-Flag               */
+	int               modempoll;		      /* Flag: tty-read active      */
+	spinlock_t	  timerlock;
+	int               tflags;                     /* Timer-Flags:               */
+	/*  see ISDN_TIMER_..defines  */
+	int               global_flags;
+	infostruct        *infochain;                 /* List of open info-devs.    */
+	wait_queue_head_t info_waitq;                 /* Wait-Queue for isdninfo    */
+	struct timer_list timer;		      /* Misc.-function Timer       */
+	int               chanmap[ISDN_MAX_CHANNELS]; /* Map minor->device-channel  */
+	int               drvmap[ISDN_MAX_CHANNELS];  /* Map minor->driver-index    */
+	int               usage[ISDN_MAX_CHANNELS];   /* Used by tty/ip/voice       */
+	char              num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+	/* Remote number of active ch.*/
+	int               m_idx[ISDN_MAX_CHANNELS];   /* Index for mdm....          */
+	isdn_driver_t     *drv[ISDN_MAX_DRIVERS];     /* Array of drivers           */
+	isdn_net_dev      *netdev;		      /* Linked list of net-if's    */
+	char              drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID                 */
+	struct task_struct *profd;                    /* For iprofd                 */
+	isdn_modem_t      mdm;			      /* tty-driver-data            */
+	isdn_net_dev      *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers     */
+	isdn_net_dev      *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers   */
+	ulong             ibytes[ISDN_MAX_CHANNELS];  /* Statistics incoming bytes  */
+	ulong             obytes[ISDN_MAX_CHANNELS];  /* Statistics outgoing bytes  */
+	int               v110emu[ISDN_MAX_CHANNELS]; /* V.110 emulator-mode 0=none */
+	atomic_t          v110use[ISDN_MAX_CHANNELS]; /* Usage-Semaphore for stream */
+	isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];   /* V.110 private data         */
+	struct semaphore  sem;                        /* serialize list access*/
+	unsigned long     global_features;
+} isdn_dev;
+
+extern isdn_dev *dev;
 
-extern isdn_dev_t	*get_isdn_dev(void);
 
 #endif /* __KERNEL__ */
 
--- diff/include/linux/isdn/capilli.h	2003-09-17 12:28:12.000000000 +0100
+++ source/include/linux/isdn/capilli.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: capilli.h,v 1.4.8.1 2001/09/23 22:24:33 kai Exp $
+/* $Id: capilli.h,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
  * 
  * Kernel CAPI 2.0 Driver Interface for Linux
  * 
@@ -85,6 +85,22 @@
 void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb);
 
 // ---------------------------------------------------------------------------
+// needed for AVM capi drivers
+
+struct capi_driver {
+	char name[32];				/* driver name */
+	char revision[32];
+
+	int (*add_card)(struct capi_driver *driver, capicardparams *data);
+
+	/* management information for kcapi */
+	struct list_head list; 
+};
+
+void register_capi_driver(struct capi_driver *driver);
+void unregister_capi_driver(struct capi_driver *driver);
+
+// ---------------------------------------------------------------------------
 // library functions for use by hardware controller drivers
 
 void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize);
--- diff/include/linux/isdn_ppp.h	2003-06-30 10:07:34.000000000 +0100
+++ source/include/linux/isdn_ppp.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,46 +21,65 @@
 
 struct pppcallinfo
 {
-	int calltype;
-	unsigned char local_num[64];
-	unsigned char remote_num[64];
-	int charge_units;
+  int calltype;
+  unsigned char local_num[64];
+  unsigned char remote_num[64];
+  int charge_units;
 };
 
-#define PPPIOCGCALLINFO    _IOWR('t',128,struct pppcallinfo)
-#define PPPIOCBUNDLE       _IOW('t',129,int)
-#define PPPIOCGMPFLAGS     _IOR('t',130,int)
-#define PPPIOCSMPFLAGS     _IOW('t',131,int)
-#define PPPIOCSMPMTU       _IOW('t',132,int)
-#define PPPIOCSMPMRU       _IOW('t',133,int)
-#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long[8])
-#define PPPIOCSCOMPRESSOR  _IOW('t',135,int)
-#define PPPIOCGIFNAME      _IOR('t',136,char[IFNAMSIZ])
+#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
+#define PPPIOCBUNDLE   _IOW('t',129,int)
+#define PPPIOCGMPFLAGS _IOR('t',130,int)
+#define PPPIOCSMPFLAGS _IOW('t',131,int)
+#define PPPIOCSMPMTU   _IOW('t',132,int)
+#define PPPIOCSMPMRU   _IOW('t',133,int)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8])
+#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
+#define PPPIOCGIFNAME      _IOR('t',136, char [IFNAMSIZ] )
+
 
 #define SC_MP_PROT       0x00000200
 #define SC_REJ_MP_PROT   0x00000400
 #define SC_OUT_SHORT_SEQ 0x00000800
 #define SC_IN_SHORT_SEQ  0x00004000
 
+#define SC_DECOMP_ON		0x01
+#define SC_COMP_ON		0x02
+#define SC_DECOMP_DISCARD	0x04
+#define SC_COMP_DISCARD		0x08
+#define SC_LINK_DECOMP_ON	0x10
+#define SC_LINK_COMP_ON		0x20
+#define SC_LINK_DECOMP_DISCARD	0x40
+#define SC_LINK_COMP_DISCARD	0x80
+
 #define ISDN_PPP_COMP_MAX_OPTIONS 16
 
 #define IPPP_COMP_FLAG_XMIT 0x1
 #define IPPP_COMP_FLAG_LINK 0x2
 
 struct isdn_ppp_comp_data {
-	int num;
-	unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
-	int optlen;
-	int flags;
+  int num;
+  unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
+  int optlen;
+  int flags;
 };
 
 #ifdef __KERNEL__
 
-#include <linux/skbuff.h>
-#include <linux/ppp_defs.h>
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IPPP_FILTER
+#include <linux/filter.h>
+#endif
 
 #define DECOMP_ERR_NOMEM	(-10)
 
+#define MP_END_FRAG    0x40
+#define MP_BEGIN_FRAG  0x80
+
+#define MP_MAX_QUEUE_LEN	16
+
 /*
  * We need a way for the decompressor to influence the generation of CCP
  * Reset-Requests in a variety of ways. The decompressor is already returning
@@ -79,15 +98,15 @@
 #define IPPP_RESET_MAXDATABYTES	32
 
 struct isdn_ppp_resetparams {
-	unsigned char valid:1;	/* rw Is this structure filled at all ? */
-	unsigned char rsend:1;	/* rw Should we send one at all ? */
-	unsigned char idval:1;	/* rw Is the id field valid ? */
-	unsigned char dtval:1;	/* rw Is the data field valid ? */
-	unsigned char expra:1;	/* rw Is an Ack expected for this Req ? */
-	unsigned char id;		/* wo Send CCP ResetReq with this id */
-	unsigned short maxdlen;	/* ro Max bytes to be stored in data field */
-	unsigned short dlen;		/* rw Bytes stored in data field */
-	unsigned char *data;		/* wo Data for ResetReq info field */
+  unsigned char valid:1;	/* rw Is this structure filled at all ? */
+  unsigned char rsend:1;	/* rw Should we send one at all ? */
+  unsigned char idval:1;	/* rw Is the id field valid ? */
+  unsigned char dtval:1;	/* rw Is the data field valid ? */
+  unsigned char expra:1;	/* rw Is an Ack expected for this Req ? */
+  unsigned char id;		/* wo Send CCP ResetReq with this id */
+  unsigned short maxdlen;	/* ro Max bytes to be stored in data field */
+  unsigned short dlen;		/* rw Bytes stored in data field */
+  unsigned char *data;		/* wo Data for ResetReq info field */
 };
 
 /*
@@ -95,38 +114,135 @@
  * check the original include for more information
  */
 struct isdn_ppp_compressor {
-	struct module *owner;
-	struct list_head list;
-	int num; /* CCP compression protocol number */
-  
-	void *(*alloc) (struct isdn_ppp_comp_data *);
-	void (*free) (void *state);
-	int  (*init) (void *state, struct isdn_ppp_comp_data *,
-		      int unit,int debug);
-  
-	/* The reset entry needs to get more exact information about the
-	   ResetReq or ResetAck it was called with. The parameters are
-	   obvious. If reset is called without a Req or Ack frame which
-	   could be handed into it, code MUST be set to 0. Using rsparm,
-	   the reset entry can control if and how a ResetAck is returned. */
-  
-	void (*reset) (void *state, unsigned char code, unsigned char id,
-		       unsigned char *data, unsigned len,
-		       struct isdn_ppp_resetparams *rsparm);
+  struct isdn_ppp_compressor *next, *prev;
+  struct module *owner;
+  int num; /* CCP compression protocol number */
+  
+  void *(*alloc) (struct isdn_ppp_comp_data *);
+  void (*free) (void *state);
+  int  (*init) (void *state, struct isdn_ppp_comp_data *,
+		int unit,int debug);
+  
+  /* The reset entry needs to get more exact information about the
+     ResetReq or ResetAck it was called with. The parameters are
+     obvious. If reset is called without a Req or Ack frame which
+     could be handed into it, code MUST be set to 0. Using rsparm,
+     the reset entry can control if and how a ResetAck is returned. */
+  
+  void (*reset) (void *state, unsigned char code, unsigned char id,
+		 unsigned char *data, unsigned len,
+		 struct isdn_ppp_resetparams *rsparm);
   
-	int  (*compress) (void *state, struct sk_buff *in,
-			  struct sk_buff *skb_out, int proto);
+  int  (*compress) (void *state, struct sk_buff *in,
+		    struct sk_buff *skb_out, int proto);
   
 	int  (*decompress) (void *state,struct sk_buff *in,
 			    struct sk_buff *skb_out,
 			    struct isdn_ppp_resetparams *rsparm);
   
-	void (*incomp) (void *state, struct sk_buff *in,int proto);
-	void (*stat) (void *state, struct compstat *stats);
+  void (*incomp) (void *state, struct sk_buff *in,int proto);
+  void (*stat) (void *state, struct compstat *stats);
 };
 
 extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
 extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_hangup_slave(char *);
+
+typedef struct {
+  unsigned long seqerrs;
+  unsigned long frame_drops;
+  unsigned long overflows;
+  unsigned long max_queue_len;
+} isdn_mppp_stats;
+
+typedef struct {
+  int mp_mrru;                        /* unused                             */
+  struct sk_buff * frags;	/* fragments sl list -- use skb->next */
+  long frames;			/* number of frames in the frame list */
+  unsigned int seq;		/* last processed packet seq #: any packets
+  				 * with smaller seq # will be dropped
+				 * unconditionally */
+  spinlock_t lock;
+  int ref_ct;				 
+  /* statistics */
+  isdn_mppp_stats stats;
+} ippp_bundle;
+
+#define NUM_RCV_BUFFS     64
+
+struct ippp_buf_queue {
+  struct ippp_buf_queue *next;
+  struct ippp_buf_queue *last;
+  char *buf;                 /* NULL here indicates end of queue */
+  int len;
+};
+
+/* The data structure for one CCP reset transaction */
+enum ippp_ccp_reset_states {
+  CCPResetIdle,
+  CCPResetSentReq,
+  CCPResetRcvdReq,
+  CCPResetSentAck,
+  CCPResetRcvdAck
+};
+
+struct ippp_ccp_reset_state {
+  enum ippp_ccp_reset_states state;	/* State of this transaction */
+  struct ippp_struct *is;		/* Backlink to device stuff */
+  unsigned char id;			/* Backlink id index */
+  unsigned char ta:1;			/* The timer is active (flag) */
+  unsigned char expra:1;		/* We expect a ResetAck at all */
+  int dlen;				/* Databytes stored in data */
+  struct timer_list timer;		/* For timeouts/retries */
+  /* This is a hack but seems sufficient for the moment. We do not want
+     to have this be yet another allocation for some bytes, it is more
+     memory management overhead than the whole mess is worth. */
+  unsigned char data[IPPP_RESET_MAXDATABYTES];
+};
+
+/* The data structure keeping track of the currently outstanding CCP Reset
+   transactions. */
+struct ippp_ccp_reset {
+  struct ippp_ccp_reset_state *rs[256];	/* One per possible id */
+  unsigned char lastid;			/* Last id allocated by the engine */
+};
+
+struct ippp_struct {
+  struct ippp_struct *next_link;
+  int state;
+  spinlock_t buflock;
+  struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
+  struct ippp_buf_queue *first;  /* pointer to (current) first packet */
+  struct ippp_buf_queue *last;   /* pointer to (current) last used packet in queue */
+  wait_queue_head_t wq;
+  struct task_struct *tk;
+  unsigned int mpppcfg;
+  unsigned int pppcfg;
+  unsigned int mru;
+  unsigned int mpmru;
+  unsigned int mpmtu;
+  unsigned int maxcid;
+  struct isdn_net_local_s *lp;
+  int unit;
+  int minor;
+  unsigned int last_link_seqno;
+  long mp_seqno;
+#ifdef CONFIG_ISDN_PPP_VJ
+  unsigned char *cbuf;
+  struct slcompress *slcomp;
+#endif
+#ifdef CONFIG_IPPP_FILTER
+  struct sock_fprog pass_filter;	/* filter for packets to pass */
+  struct sock_fprog active_filter;	/* filter for pkts to reset idle */
+#endif
+  unsigned long debug;
+  struct isdn_ppp_compressor *compressor,*decompressor;
+  struct isdn_ppp_compressor *link_compressor,*link_decompressor;
+  void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
+  struct ippp_ccp_reset *reset;	/* Allocated on demand, may never be needed */
+  unsigned long compflags;
+};
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_ISDN_PPP_H */
--- diff/include/linux/isdnif.h	2003-02-13 11:46:55.000000000 +0000
+++ source/include/linux/isdnif.h	2004-02-18 09:04:02.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.37.6.6 2001/09/23 22:25:05 kai Exp $
+/* $Id: isdnif.h,v 1.43.2.2 2004/01/12 23:08:35 keil Exp $
  *
  * Linux ISDN subsystem
  * Definition of the interface between the subsystem and its low-level drivers.
@@ -166,8 +166,17 @@
 #define ISDN_CMD_HANGUP   4       /* Hangup                                */
 #define ISDN_CMD_CLREAZ   5       /* Clear EAZ(s) of channel               */
 #define ISDN_CMD_SETEAZ   6       /* Set EAZ(s) of channel                 */
+#define ISDN_CMD_GETEAZ   7       /* Get EAZ(s) of channel                 */
+#define ISDN_CMD_SETSIL   8       /* Set Service-Indicator-List of channel */
+#define ISDN_CMD_GETSIL   9       /* Get Service-Indicator-List of channel */
 #define ISDN_CMD_SETL2   10       /* Set B-Chan. Layer2-Parameter          */
+#define ISDN_CMD_GETL2   11       /* Get B-Chan. Layer2-Parameter          */
 #define ISDN_CMD_SETL3   12       /* Set B-Chan. Layer3-Parameter          */
+#define ISDN_CMD_GETL3   13       /* Get B-Chan. Layer3-Parameter          */
+// #define ISDN_CMD_LOCK    14       /* Signal usage by upper levels          */
+// #define ISDN_CMD_UNLOCK  15       /* Release usage-lock                    */
+#define ISDN_CMD_SUSPEND 16       /* Suspend connection                    */
+#define ISDN_CMD_RESUME  17       /* Resume connection                     */
 #define ISDN_CMD_PROCEED 18       /* Proceed with call establishment       */
 #define ISDN_CMD_ALERT   19       /* Alert after Proceeding                */
 #define ISDN_CMD_REDIR   20       /* Redir a incoming call                 */
@@ -193,12 +202,14 @@
 #define ISDN_STAT_LOAD    265    /* Signal new lowlevel-driver is loaded  */
 #define ISDN_STAT_UNLOAD  266    /* Signal unload of lowlevel-driver      */
 #define ISDN_STAT_BSENT   267    /* Signal packet sent                    */
+#define ISDN_STAT_NODCH   268    /* Signal no D-Channel                   */
 #define ISDN_STAT_ADDCH   269    /* Add more Channels                     */
 #define ISDN_STAT_CAUSE   270    /* Cause-Message                         */
 #define ISDN_STAT_ICALLW  271    /* Incoming call without B-chan waiting  */
 #define ISDN_STAT_REDIR   272    /* Redir result                          */
 #define ISDN_STAT_PROT    273    /* protocol IO specific callback         */
 #define ISDN_STAT_DISPLAY 274    /* deliver a received display message    */
+#define ISDN_STAT_L1ERR   275    /* Signal Layer-1 Error                  */
 #define ISDN_STAT_FAXIND  276    /* FAX indications from HL-driver        */
 #define ISDN_STAT_AUDIO   277    /* DTMF, DSP indications                 */
 #define ISDN_STAT_DISCH   278    /* Disable/Enable channel usage          */
@@ -210,6 +221,12 @@
 #define ISDN_AUDIO_DTMF		1	/* Rx/Tx DTMF                   */
 
 /*
+ * Values for errcode field
+ */
+#define ISDN_STAT_L1ERR_SEND 1
+#define ISDN_STAT_L1ERR_RECV 2
+
+/*
  * Values for feature-field of interface-struct.
  */
 /* Layer 2 */
@@ -258,6 +275,7 @@
 } setup_parm;
 
 
+#ifdef CONFIG_ISDN_TTY_FAX
 /* T.30 Fax G3 */
 
 #define FAXIDLEN 21
@@ -332,6 +350,8 @@
 #define ISDN_FAX_PHASE_D   	4
 #define ISDN_FAX_PHASE_E   	5
 
+#endif /* TTY_FAX */
+
 #define ISDN_FAX_CLASS1_FAE	0
 #define ISDN_FAX_CLASS1_FTS	1
 #define ISDN_FAX_CLASS1_FRS	2
@@ -398,7 +418,9 @@
 		char display[85];/* display message data		*/ 
 		isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result	*/
 		aux_s aux;	/* for modem commands/indications	*/
+#ifdef CONFIG_ISDN_TTY_FAX
 		T30_s	*fax;	/* Pointer to ttys fax struct		*/
+#endif
 		ulong userdata;	/* User Data */
 	} parm;
 } isdn_ctrl;
--- diff/include/linux/istallion.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/linux/istallion.h	2004-02-18 09:04:02.000000000 +0000
@@ -70,15 +70,9 @@
 	void			*argp;
 	unsigned int		rxmarkmsk;
 	struct tty_struct	*tty;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*raw_wait;
-#else
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 	wait_queue_head_t	raw_wait;
-#endif
 	struct work_struct	tqhangup;
 	asysigs_t		asig;
 	unsigned long		addr;
--- diff/include/linux/kernel.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/kernel.h	2004-02-18 09:04:02.000000000 +0000
@@ -72,6 +72,9 @@
 extern int snprintf(char * buf, size_t size, const char * fmt, ...)
 	__attribute__ ((format (printf, 3, 4)));
 extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
 
 extern int sscanf(const char *, const char *, ...)
 	__attribute__ ((format (scanf,2,3)));
--- diff/include/linux/lapb.h	2002-10-16 04:28:34.000000000 +0100
+++ source/include/linux/lapb.h	2004-02-18 09:04:02.000000000 +0000
@@ -24,12 +24,12 @@
 #define	LAPB_DCE		0x04
 
 struct lapb_register_struct {
-	void (*connect_confirmation)(void *token, int reason);
-	void (*connect_indication)(void *token, int reason);
-	void (*disconnect_confirmation)(void *token, int reason);
-	void (*disconnect_indication)(void *token, int reason);
-	int  (*data_indication)(void *token, struct sk_buff *skb);
-	void (*data_transmit)(void *token, struct sk_buff *skb);
+	void (*connect_confirmation)(struct net_device *dev, int reason);
+	void (*connect_indication)(struct net_device *dev, int reason);
+	void (*disconnect_confirmation)(struct net_device *dev, int reason);
+	void (*disconnect_indication)(struct net_device *dev, int reason);
+	int  (*data_indication)(struct net_device *dev, struct sk_buff *skb);
+	void (*data_transmit)(struct net_device *dev, struct sk_buff *skb);
 };
 
 struct lapb_parms_struct {
@@ -44,13 +44,13 @@
 	unsigned int mode;
 };
 
-extern int lapb_register(void *token, struct lapb_register_struct *callbacks);
-extern int lapb_unregister(void *token);
-extern int lapb_getparms(void *token, struct lapb_parms_struct *parms);
-extern int lapb_setparms(void *token, struct lapb_parms_struct *parms);
-extern int lapb_connect_request(void *token);
-extern int lapb_disconnect_request(void *token);
-extern int lapb_data_request(void *token, struct sk_buff *skb);
-extern int lapb_data_received(void *token, struct sk_buff *skb);
+extern int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks);
+extern int lapb_unregister(struct net_device *dev);
+extern int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms);
+extern int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms);
+extern int lapb_connect_request(struct net_device *dev);
+extern int lapb_disconnect_request(struct net_device *dev);
+extern int lapb_data_request(struct net_device *dev, struct sk_buff *skb);
+extern int lapb_data_received(struct net_device *dev, struct sk_buff *skb);
 
 #endif
--- diff/include/linux/limits.h	2002-10-16 04:29:02.000000000 +0100
+++ source/include/linux/limits.h	2004-02-18 09:04:02.000000000 +0000
@@ -3,7 +3,7 @@
 
 #define NR_OPEN	        1024
 
-#define NGROUPS_MAX       32	/* supplemental group IDs are available */
+#define NGROUPS_MAX    65536	/* supplemental group IDs are available */
 #define ARG_MAX       131072	/* # bytes of args + environ for exec() */
 #define CHILD_MAX        999    /* no limit :-) */
 #define OPEN_MAX         256	/* # open files a process may have */
--- diff/include/linux/list.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/list.h	2004-02-18 09:04:02.000000000 +0000
@@ -142,8 +142,11 @@
  * Note: list_empty on entry does not return true after this, the entry is
  * in an undefined state.
  */
+#include <linux/kernel.h>	/* BUG_ON */
 static inline void list_del(struct list_head *entry)
 {
+	BUG_ON(entry->prev->next != entry);
+	BUG_ON(entry->next->prev != entry);
 	__list_del(entry->prev, entry->next);
 	entry->next = LIST_POISON1;
 	entry->prev = LIST_POISON2;
--- diff/include/linux/loop.h	2003-08-20 14:16:34.000000000 +0100
+++ source/include/linux/loop.h	2004-02-18 09:04:02.000000000 +0000
@@ -34,8 +34,9 @@
 	loff_t		lo_sizelimit;
 	int		lo_flags;
 	int		(*transfer)(struct loop_device *, int cmd,
-				    char *raw_buf, char *loop_buf, int size,
-				    sector_t real_block);
+				    struct page *raw_page, unsigned raw_off,
+				    struct page *loop_page, unsigned loop_off,
+				    int size, sector_t real_block);
 	char		lo_file_name[LO_NAME_SIZE];
 	char		lo_crypt_name[LO_NAME_SIZE];
 	char		lo_encrypt_key[LO_KEY_SIZE];
@@ -70,8 +71,7 @@
 /*
  * Loop flags
  */
-#define LO_FLAGS_DO_BMAP	1
-#define LO_FLAGS_READ_ONLY	2
+#define LO_FLAGS_READ_ONLY	1
 
 #include <asm/posix_types.h>	/* for __kernel_old_dev_t */
 #include <asm/types.h>		/* for __u64 */
@@ -128,8 +128,10 @@
 /* Support for loadable transfer modules */
 struct loop_func_table {
 	int number;	/* filter type */ 
-	int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf,
-			char *loop_buf, int size, sector_t real_block);
+	int (*transfer)(struct loop_device *lo, int cmd,
+			struct page *raw_page, unsigned raw_off,
+			struct page *loop_page, unsigned loop_off,
+			int size, sector_t real_block);
 	int (*init)(struct loop_device *, const struct loop_info64 *); 
 	/* release is called from loop_unregister_transfer or clr_fd */
 	int (*release)(struct loop_device *); 
--- diff/include/linux/miscdevice.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/miscdevice.h	2004-02-18 09:04:02.000000000 +0000
@@ -3,7 +3,6 @@
 #include <linux/module.h>
 #include <linux/major.h>
 
-#define BUSMOUSE_MINOR 0
 #define PSMOUSE_MINOR  1
 #define MS_BUSMOUSE_MINOR 2
 #define ATIXL_BUSMOUSE_MINOR 3
--- diff/include/linux/mm.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/mm.h	2004-02-18 09:04:02.000000000 +0000
@@ -455,8 +455,6 @@
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-extern long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long nonblock);
-extern long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice);
 void put_dirty_page(struct task_struct *tsk, struct page *page,
 			unsigned long address, pgprot_t prot);
 
@@ -635,6 +633,39 @@
 extern int remap_page_range(struct vm_area_struct *vma, unsigned long from,
 		unsigned long to, unsigned long size, pgprot_t prot);
 
+/*
+ * Given a struct page, determine which node's memory it is from.
+ * TODO: There's probably a more efficient way to do this...
+ */
+static inline int page_to_nid(struct page *page)
+{
+	return pfn_to_nid(page_to_pfn(page));
+}
+
+#ifdef CONFIG_NUMA
+static inline void zero_rss(struct mm_struct *mm)
+{
+	mm->rss = 0;
+	memset(mm->pernode_rss, 0, MAX_NUMNODES * sizeof(*mm->pernode_rss));
+}
+
+static inline void inc_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss++;
+	mm->pernode_rss[page_to_nid(page)]++;
+}
+
+static inline void dec_rss(struct mm_struct *mm, struct page *page)
+{
+	mm->rss--;
+	mm->pernode_rss[page_to_nid(page)]--;
+}
+#else /* !CONFIG_NUMA */
+#define zero_rss(mm)		((mm)->rss = 0)
+#define inc_rss(mm, page)	((mm)->rss++)
+#define dec_rss(mm, page)	((mm)->rss--)
+#endif /* CONFIG_NUMA */
+
 #ifndef CONFIG_DEBUG_PAGEALLOC
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
--- diff/include/linux/mmzone.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/mmzone.h	2004-02-18 09:04:02.000000000 +0000
@@ -149,6 +149,12 @@
 	unsigned long		zone_start_pfn;
 
 	/*
+	 * dummy page used as place holder during scanning of
+	 * active_list in refill_inactive_zone()
+	 */
+	struct page *scan_page;
+
+	/*
 	 * rarely used fields:
 	 */
 	char			*name;
@@ -213,6 +219,7 @@
 	int node_id;
 	struct pglist_data *pgdat_next;
 	wait_queue_head_t       kswapd_wait;
+	struct task_struct *kswapd;
 } pg_data_t;
 
 #define node_present_pages(nid)	(NODE_DATA(nid)->node_present_pages)
@@ -304,6 +311,7 @@
 #define NODE_DATA(nid)		(&contig_page_data)
 #define NODE_MEM_MAP(nid)	mem_map
 #define MAX_NODES_SHIFT		1
+#define pfn_to_nid(pfn)		(0)
 
 #else /* CONFIG_DISCONTIGMEM */
 
--- diff/include/linux/msg.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/linux/msg.h	2004-02-18 09:04:02.000000000 +0000
@@ -93,11 +93,6 @@
 	struct list_head q_senders;
 };
 
-asmlinkage long sys_msgget (key_t key, int msgflg);
-asmlinkage long sys_msgsnd (int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg);
-asmlinkage long sys_msgrcv (int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg);
-asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf);
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_MSG_H */
--- diff/include/linux/netdevice.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/netdevice.h	2004-02-18 09:04:02.000000000 +0000
@@ -456,6 +456,12 @@
 						     unsigned char *haddr);
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
+#ifdef CONFIG_NETPOLL_RX
+	int			netpoll_rx;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	void                    (*poll_controller)(struct net_device *dev);
+#endif
 
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
@@ -545,6 +551,9 @@
 extern struct net_device	*dev_get_by_index(int ifindex);
 extern struct net_device	*__dev_get_by_index(int ifindex);
 extern int		dev_restart(struct net_device *dev);
+#ifdef CONFIG_NETPOLL_TRAP
+extern int		netpoll_trap(void);
+#endif
 
 typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len);
 extern int		register_gifconf(unsigned int family, gifconf_func_t * gifconf);
@@ -603,12 +612,20 @@
 
 static inline void netif_wake_queue(struct net_device *dev)
 {
+#ifdef CONFIG_NETPOLL_TRAP
+	if (netpoll_trap())
+		return;
+#endif
 	if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
 }
 
 static inline void netif_stop_queue(struct net_device *dev)
 {
+#ifdef CONFIG_NETPOLL_TRAP
+	if (netpoll_trap())
+		return;
+#endif
 	set_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
--- diff/include/linux/nfs_fs.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/nfs_fs.h	2004-02-18 09:04:02.000000000 +0000
@@ -99,7 +99,7 @@
 	/*
 	 * Various flags
 	 */
-	unsigned short		flags;
+	unsigned int		flags;
 
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode,
@@ -118,19 +118,22 @@
 	 *
 	 *	mtime != read_cache_mtime
 	 */
+	unsigned long		readdir_timestamp;
 	unsigned long		read_cache_jiffies;
-	struct timespec		read_cache_ctime;
-	struct timespec		read_cache_mtime;
-	__u64			read_cache_isize;
 	unsigned long		attrtimeo;
 	unsigned long		attrtimeo_timestamp;
 	__u64			change_attr;		/* v4 only */
 
+	/* "Generation counter" for the attribute cache. This is
+	 * bumped whenever we update the metadata on the
+	 * server.
+	 */
+	unsigned long		cache_change_attribute;
 	/*
-	 * Timestamp that dates the change made to read_cache_mtime.
-	 * This is of use for dentry revalidation
+	 * Counter indicating the number of outstanding requests that
+	 * will cause a file data update.
 	 */
-	unsigned long		cache_mtime_jiffies;
+	atomic_t		data_updates;
 
 	struct nfs_access_cache	cache_access;
 
@@ -170,7 +173,9 @@
 #define NFS_INO_STALE		0x0001		/* possible stale inode */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
-#define NFS_INO_FLUSH		0x0008		/* inode is due for flushing */
+#define NFS_INO_INVALID_ATTR	0x0008		/* cached attrs are invalid */
+#define NFS_INO_INVALID_DATA	0x0010		/* cached data is invalid */
+#define NFS_INO_INVALID_ATIME	0x0020		/* cached atime is invalid */
 #define NFS_INO_FAKE_ROOT	0x0080		/* root inode placeholder */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
@@ -186,15 +191,7 @@
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
 #define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
 #define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
-#define NFS_MTIME_UPDATE(inode)		(NFS_I(inode)->cache_mtime_jiffies)
-#define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
-#define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
 #define NFS_CHANGE_ATTR(inode)		(NFS_I(inode)->change_attr)
-#define NFS_CACHEINV(inode) \
-do { \
-	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
-} while (0)
 #define NFS_ATTRTIMEO(inode)		(NFS_I(inode)->attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
@@ -211,6 +208,17 @@
 
 #define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
 
+static inline int nfs_caches_unstable(struct inode *inode)
+{
+	return atomic_read(&NFS_I(inode)->data_updates) != 0;
+}
+
+static inline void NFS_CACHEINV(struct inode *inode)
+{
+	if (!nfs_caches_unstable(inode))
+		NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
+}
+
 static inline int nfs_server_capable(struct inode *inode, int cap)
 {
 	return NFS_SERVER(inode)->caps & cap;
@@ -227,13 +235,37 @@
 	return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
 }
 
+/**
+ * nfs_save_change_attribute - Returns the inode attribute change cookie
+ * @inode - pointer to inode
+ * The "change attribute" is updated every time we finish an operation
+ * that will result in a metadata change on the server.
+ */
+static inline long nfs_save_change_attribute(struct inode *inode)
+{
+	return NFS_I(inode)->cache_change_attribute;
+}
+
+/**
+ * nfs_verify_change_attribute - Detects NFS inode cache updates
+ * @inode - pointer to inode
+ * @chattr - previously saved change attribute
+ * Return "false" if metadata has been updated (or is in the process of
+ * being updated) since the change attribute was saved.
+ */
+static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+{
+	return !nfs_caches_unstable(inode)
+		&& chattr == NFS_I(inode)->cache_change_attribute;
+}
+
 /*
  * linux/fs/nfs/inode.c
  */
 extern void nfs_zap_caches(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 				struct nfs_fattr *);
-extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
 extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
@@ -241,6 +273,13 @@
 extern int nfs_release(struct inode *, struct file *);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_setattr(struct dentry *, struct iattr *);
+extern void nfs_begin_attr_update(struct inode *);
+extern void nfs_end_attr_update(struct inode *);
+extern void nfs_begin_data_update(struct inode *);
+extern void nfs_end_data_update(struct inode *);
+
+/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
+extern u32 root_nfs_parse_addr(char *name); /*__init*/
 
 /*
  * linux/fs/nfs/file.c
@@ -383,20 +422,27 @@
 /*
  * inline functions
  */
-static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+
+static inline int nfs_attribute_timeout(struct inode *inode)
 {
-	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-		return NFS_STALE(inode) ? -ESTALE : 0;
-	return __nfs_revalidate_inode(server, inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
 }
 
-static inline int
-nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+/**
+ * nfs_revalidate_inode - Revalidate the inode attributes
+ * @server - pointer to nfs_server struct
+ * @inode - pointer to inode struct
+ *
+ * Updates inode attribute information by retrieving the data from the server.
+ */
+static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		return 0;
-	return __nfs_refresh_inode(inode,fattr);
+	if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+			&& !nfs_attribute_timeout(inode))
+		return NFS_STALE(inode) ? -ESTALE : 0;
+	return __nfs_revalidate_inode(server, inode);
 }
 
 static inline loff_t
--- diff/include/linux/nfsd/auth.h	2002-10-16 04:27:48.000000000 +0100
+++ source/include/linux/nfsd/auth.h	2004-02-18 09:04:02.000000000 +0000
@@ -21,7 +21,7 @@
  * Set the current process's fsuid/fsgid etc to those of the NFS
  * client user
  */
-void		nfsd_setuser(struct svc_rqst *, struct svc_export *);
+int nfsd_setuser(struct svc_rqst *, struct svc_export *);
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_NFSD_AUTH_H */
--- diff/include/linux/nfsd/nfsd.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/linux/nfsd/nfsd.h	2004-02-18 09:04:02.000000000 +0000
@@ -86,7 +86,7 @@
 				struct svc_fh *res, int createmode,
 				u32 *verifier, int *truncp);
 int		nfsd_commit(struct svc_rqst *, struct svc_fh *,
-				off_t, unsigned long);
+				loff_t, unsigned long);
 #endif /* CONFIG_NFSD_V3 */
 int		nfsd_open(struct svc_rqst *, struct svc_fh *, int,
 				int, struct file *);
--- diff/include/linux/nfsd/syscall.h	2003-05-21 11:50:16.000000000 +0100
+++ source/include/linux/nfsd/syscall.h	2004-02-18 09:04:02.000000000 +0000
@@ -115,7 +115,6 @@
 /*
  * Kernel syscall implementation.
  */
-extern asmlinkage long	sys_nfsservctl(int, struct nfsctl_arg __user *, void __user *);
 extern int		exp_addclient(struct nfsctl_client *ncp);
 extern int		exp_delclient(struct nfsctl_client *ncp);
 extern int		exp_export(struct nfsctl_export *nxp);
--- diff/include/linux/notifier.h	2002-11-11 11:09:38.000000000 +0000
+++ source/include/linux/notifier.h	2004-02-18 09:04:02.000000000 +0000
@@ -63,7 +63,6 @@
 #define CPU_ONLINE	0x0002 /* CPU (unsigned)v is up */
 #define CPU_UP_PREPARE	0x0003 /* CPU (unsigned)v coming up */
 #define CPU_UP_CANCELED	0x0004 /* CPU (unsigned)v NOT coming up */
-#define CPU_OFFLINE	0x0005 /* CPU (unsigned)v offline (still scheduling) */
 #define CPU_DEAD	0x0006 /* CPU (unsigned)v dead */
 
 #endif /* __KERNEL__ */
--- diff/include/linux/pci.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/pci.h	2004-02-18 09:04:02.000000000 +0000
@@ -304,18 +304,60 @@
 #define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
 #define  PCI_X_CMD_MAX_READ	0x000c	/* Max Memory Read Byte Count */
 #define  PCI_X_CMD_MAX_SPLIT	0x0070	/* Max Outstanding Split Transactions */
-#define PCI_X_DEVFN		4	/* A copy of devfn. */
-#define PCI_X_BUSNR		5	/* Bus segment number */
-#define PCI_X_STATUS		6	/* PCI-X capabilities */
-#define  PCI_X_STATUS_64BIT	0x0001	/* 64-bit device */
-#define  PCI_X_STATUS_133MHZ	0x0002	/* 133 MHz capable */
-#define  PCI_X_STATUS_SPL_DISC	0x0004	/* Split Completion Discarded */
-#define  PCI_X_STATUS_UNX_SPL	0x0008	/* Unexpected Split Completion */
-#define  PCI_X_STATUS_COMPLEX	0x0010	/* Device Complexity */
-#define  PCI_X_STATUS_MAX_READ	0x0060	/* Designed Maximum Memory Read Count */
-#define  PCI_X_STATUS_MAX_SPLIT	0x0380	/* Design Max Outstanding Split Trans */
-#define  PCI_X_STATUS_MAX_CUM	0x1c00	/* Designed Max Cumulative Read Size */
-#define  PCI_X_STATUS_SPL_ERR	0x2000	/* Rcvd Split Completion Error Msg */
+#define PCI_X_STATUS		4	/* PCI-X capabilities */
+#define  PCI_X_STATUS_DEVFN	0x000000ff	/* A copy of devfn */
+#define  PCI_X_STATUS_BUS	0x0000ff00	/* A copy of bus nr */
+#define  PCI_X_STATUS_64BIT	0x00010000	/* 64-bit device */
+#define  PCI_X_STATUS_133MHZ	0x00020000	/* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC	0x00040000	/* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL	0x00080000	/* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX	0x00100000	/* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ	0x00600000	/* Designed Max Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT	0x03800000	/* Designed Max Outstanding Split Transactions */
+#define  PCI_X_STATUS_MAX_CUM	0x1c000000	/* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR	0x20000000	/* Rcvd Split Completion Error Msg */
+#define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
+#define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID_ERR	1
+#define PCI_EXT_CAP_ID_VC	2
+#define PCI_EXT_CAP_ID_DSN	3
+#define PCI_EXT_CAP_ID_PWR	4
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS	4
+#define PCI_ERR_UNCOR_MASK	8
+#define PCI_ERR_UNCOR_SEVER	12
+#define PCI_ERR_COR_STATUS	16
+#define PCI_ERR_COR_MASK	20
+#define PCI_ERR_CAP		24
+#define PCI_ERR_HEADER_LOG	28
+#define PCI_ERR_ROOT_COMMAND	44
+#define PCI_ERR_ROOT_STATUS	48
+#define PCI_ERR_ROOT_COR_SRC	52
+#define PCI_ERR_ROOT_SRC	54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1	4
+#define PCI_VC_PORT_REG2	8
+#define PCI_VC_PORT_CTRL	12
+#define PCI_VC_PORT_STATUS	14
+#define PCI_VC_RES_CAP		16
+#define PCI_VC_RES_CTRL		20
+#define PCI_VC_RES_STATUS	26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR		4	/* Data Select Register */
+#define PCI_PWR_DATA		8	/* Data Register */
+#define  PCI_PWR_DATA_BASE	0x000000ff	/* Base Power */
+#define  PCI_PWR_DATA_SCALE	0x00000300	/* Data Scale */
+#define  PCI_PWR_DATA_PM_SUB	0x00001c00	/* PM Sub State */
+#define  PCI_PWR_DATA_PM_STATE	0x00006000	/* PM State */
+#define  PCI_PWR_DATA_TYPE	0x00038000	/* Type */
+#define  PCI_PWR_DATA_RAIL	0x000c0000	/* Power Rail */
+#define PCI_PWR_CAP		12	/* Capability */
+#define  PCI_PWR_CAP_BUDGET	0x01	/* Already included in system budget */
 
 /* Include the ID list */
 
@@ -409,6 +451,8 @@
 	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
 	unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
 
+	int		cfg_size;	/* Size of configuration space */
+
 	/*
 	 * Instead of touching interrupt line and base address registers
 	 * directly, use the values stored here. They might be different!
@@ -606,6 +650,7 @@
 struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
+int pci_find_ext_capability (struct pci_dev *dev, int cap);
 struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
 
 struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
@@ -768,6 +813,7 @@
 static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
 static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
 static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; }
 
 /* Power management related routines */
--- diff/include/linux/quota.h	2004-01-19 10:22:59.000000000 +0000
+++ source/include/linux/quota.h	2004-02-18 09:04:02.000000000 +0000
@@ -138,6 +138,9 @@
 #include <linux/dqblk_v1.h>
 #include <linux/dqblk_v2.h>
 
+/* Maximal numbers of writes for quota operations (over all formats) */
+#define DQUOT_MAX_WRITES	6	/* Number of writes needed when quota structure is written */
+
 /*
  * Data for one user/group kept in memory
  */
@@ -168,22 +171,21 @@
 	} u;
 };
 
+struct super_block;
+
 #define DQF_MASK 0xffff		/* Mask for format specific flags */
 #define DQF_INFO_DIRTY_B 16
 #define DQF_ANY_DQUOT_DIRTY_B 17
 #define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B)	/* Is info dirty? */
 #define DQF_ANY_DQUOT_DIRTY (1 << DQF_ANY_DQUOT_DIRTY_B) /* Is any dquot dirty? */
 
-extern inline void mark_info_dirty(struct mem_dqinfo *info)
-{
-	set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
-}
-
+extern void mark_info_dirty(struct super_block *sb, int type);
 #define info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
 #define info_any_dquot_dirty(info) test_bit(DQF_ANY_DQUOT_DIRTY_B, &(info)->dqi_flags)
 #define info_any_dirty(info) (info_dirty(info) || info_any_dquot_dirty(info))
 
 #define sb_dqopt(sb) (&(sb)->s_dquot)
+#define sb_dqinfo(sb, type) (sb_dqopt(sb)->info+(type))
 
 struct dqstats {
 	int lookups;
@@ -238,19 +240,21 @@
 	int (*write_file_info)(struct super_block *sb, int type);	/* Write main info about file */
 	int (*free_file_info)(struct super_block *sb, int type);	/* Called on quotaoff() */
 	int (*read_dqblk)(struct dquot *dquot);		/* Read structure for one user */
-	int (*commit_dqblk)(struct dquot *dquot);	/* Write (or delete) structure for one user */
+	int (*commit_dqblk)(struct dquot *dquot, int init);	/* Write (or delete) structure for one user */
 };
 
 /* Operations working with dquots */
 struct dquot_operations {
-	void (*initialize) (struct inode *, int);
-	void (*drop) (struct inode *);
+	int (*initialize) (struct inode *, int);
+	int (*drop) (struct inode *);
 	int (*alloc_space) (struct inode *, qsize_t, int);
 	int (*alloc_inode) (const struct inode *, unsigned long);
-	void (*free_space) (struct inode *, qsize_t);
-	void (*free_inode) (const struct inode *, unsigned long);
+	int (*free_space) (struct inode *, qsize_t);
+	int (*free_inode) (const struct inode *, unsigned long);
 	int (*transfer) (struct inode *, struct iattr *);
-	int (*write_dquot) (struct dquot *);
+	int (*write_dquot) (struct dquot *, int);
+	int (*mark_dirty) (struct dquot *);
+	int (*write_info) (struct super_block *, int);
 };
 
 /* Operations handling requests from userspace */
@@ -289,10 +293,7 @@
 };
 
 /* Inline would be better but we need to dereference super_block which is not defined yet */
-#define mark_dquot_dirty(dquot) do {\
-	set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->info[(dquot)->dq_type].dqi_flags));\
-	set_bit(DQ_MOD_B, &(dquot)->dq_flags);\
-} while (0)
+int mark_dquot_dirty(struct dquot *dquot);
 
 #define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags)
 
@@ -304,7 +305,6 @@
 
 int register_quota_format(struct quota_format_type *fmt);
 void unregister_quota_format(struct quota_format_type *fmt);
-void init_dquot_operations(struct dquot_operations *fsdqops);
 
 struct quota_module_name {
 	int qm_fmt_id;
--- diff/include/linux/quotaops.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/quotaops.h	2004-02-18 09:04:02.000000000 +0000
@@ -22,16 +22,29 @@
  */
 extern void sync_dquots(struct super_block *sb, int type);
 
-extern void dquot_initialize(struct inode *inode, int type);
-extern void dquot_drop(struct inode *inode);
+extern int dquot_initialize(struct inode *inode, int type);
+extern int dquot_drop(struct inode *inode);
 
-extern int  dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
-extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
+extern int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
+extern int dquot_alloc_inode(const struct inode *inode, unsigned long number);
 
-extern void dquot_free_space(struct inode *inode, qsize_t number);
-extern void dquot_free_inode(const struct inode *inode, unsigned long number);
+extern int dquot_free_space(struct inode *inode, qsize_t number);
+extern int dquot_free_inode(const struct inode *inode, unsigned long number);
 
-extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
+extern int dquot_transfer(struct inode *inode, struct iattr *iattr);
+extern int dquot_commit(struct dquot *dquot, int init);
+extern int dquot_commit_info(struct super_block *sb, int type);
+extern int dquot_mark_dquot_dirty(struct dquot *dquot);
+
+extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path);
+extern int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry);
+extern int vfs_quota_off(struct super_block *sb, int type);
+extern int vfs_quota_off_mount(struct super_block *sb, int type);
+extern int vfs_quota_sync(struct super_block *sb, int type);
+extern int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+extern int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
+extern int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
+extern int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di);
 
 /*
  * Operations supported for diskquotas.
@@ -64,11 +77,9 @@
 		if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA)
 			return 1;
 	}
-	else {
-		spin_lock(&dq_data_lock);
+	else
+		/* inode->i_lock will guard the update */
 		inode_add_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 	return 0;
 }
 
@@ -87,11 +98,9 @@
 		if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA)
 			return 1;
 	}
-	else {
-		spin_lock(&dq_data_lock);
+	else
+		/* inode->i_lock will guard the update */
 		inode_add_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 	return 0;
 }
 
@@ -117,11 +126,9 @@
 {
 	if (sb_any_quota_enabled(inode->i_sb))
 		inode->i_sb->dq_op->free_space(inode, nr);
-	else {
-		spin_lock(&dq_data_lock);
+	else
+		/* inode->i_lock will guard the update */
 		inode_sub_bytes(inode, nr);
-		spin_unlock(&dq_data_lock);
-	}
 }
 
 static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
--- diff/include/linux/raid/md_k.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/raid/md_k.h	2004-02-18 09:04:02.000000000 +0000
@@ -186,7 +186,8 @@
 {
 	void				*private;
 	mdk_personality_t		*pers;
-	int				__minor;
+	dev_t				unit;
+	int				md_minor;
 	struct list_head 		disks;
 	int				sb_dirty;
 	int				ro;
@@ -235,6 +236,7 @@
 	struct semaphore		reconfig_sem;
 	atomic_t			active;
 
+	int				changed;	/* true if we might need to reread partition info */
 	int				degraded;	/* whether md should consider
 							 * adding a spare
 							 */
@@ -272,15 +274,6 @@
 };
 
 
-/*
- * Currently we index md_array directly, based on the minor
- * number. This will have to change to dynamic allocation
- * once we start supporting partitioning of md devices.
- */
-static inline int mdidx (mddev_t * mddev)
-{
-	return mddev->__minor;
-}
 static inline char * mdname (mddev_t * mddev)
 {
 	return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
--- diff/include/linux/raid/raid1.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/linux/raid/raid1.h	2004-02-18 09:04:02.000000000 +0000
@@ -54,8 +54,8 @@
 	atomic_t		remaining; /* 'have we finished' count,
 					    * used from IRQ handlers
 					    */
-	int			cmd;
 	sector_t		sector;
+	int			sectors;
 	unsigned long		state;
 	mddev_t			*mddev;
 	/*
@@ -63,21 +63,19 @@
 	 */
 	struct bio		*master_bio;
 	/*
-	 * if the IO is in READ direction, then this bio is used:
+	 * if the IO is in READ direction, then this is where we read
 	 */
-	struct bio		*read_bio;
 	int			read_disk;
 
-	r1bio_t			*next_r1; /* next for retry or in free list */
 	struct list_head	retry_list;
 	/*
 	 * if the IO is in WRITE direction, then multiple bios are used.
 	 * We choose the number when they are allocated.
 	 */
-	struct bio		*write_bios[0];
+	struct bio		*bios[0];
 };
 
 /* bits for r1bio.state */
-#define	R1BIO_Uptodate	1
-
+#define	R1BIO_Uptodate	0
+#define	R1BIO_IsSync	1
 #endif
--- diff/include/linux/sched.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sched.h	2004-02-18 09:04:02.000000000 +0000
@@ -147,10 +147,12 @@
 typedef struct task_struct task_t;
 
 extern void sched_init(void);
+extern void sched_init_smp(void);
 extern void init_idle(task_t *idle, int cpu);
 
 extern void show_state(void);
 extern void show_regs(struct pt_regs *);
+extern void show_trace_task(task_t *tsk);
 
 /*
  * TASK is a pointer to the task whose backtrace we want to see (or NULL for current
@@ -192,7 +194,7 @@
 	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
 	int map_count;				/* number of VMAs */
 	struct rw_semaphore mmap_sem;
-	spinlock_t page_table_lock;		/* Protects task page tables and mm->rss */
+	spinlock_t page_table_lock;		/* Protects task page tables and RSS data */
 
 	struct list_head mmlist;		/* List of all active mm's.  These are globally strung
 						 * together off init_mm.mmlist, and are protected
@@ -202,7 +204,11 @@
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
 	unsigned long arg_start, arg_end, env_start, env_end;
-	unsigned long rss, total_vm, locked_vm;
+	unsigned long total_vm, locked_vm;
+	unsigned long rss;
+#ifdef CONFIG_NUMA
+	unsigned long pernode_rss[MAX_NUMNODES];
+#endif
 	unsigned long def_flags;
 
 	unsigned long saved_auxv[40]; /* for /proc/PID/auxv */
@@ -330,6 +336,33 @@
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
 
+#define NGROUPS_SMALL		32
+#define NGROUPS_PER_BLOCK	((int)(EXEC_PAGESIZE / sizeof(gid_t)))
+struct group_info {
+	int ngroups;
+	atomic_t usage;
+	gid_t small_block[NGROUPS_SMALL];
+	int nblocks;
+	gid_t *blocks[0];
+};
+
+#define get_group_info(group_info) do { \
+	atomic_inc(&(group_info)->usage); \
+} while (0)
+
+#define put_group_info(group_info) do { \
+	if (atomic_dec_and_test(&(group_info)->usage)) \
+		groups_free(group_info); \
+} while (0)
+
+struct group_info *groups_alloc(int gidsetsize);
+void groups_free(struct group_info *group_info);
+int set_current_groups(struct group_info *group_info);
+/* access the groups "array" with this macro */
+#define GROUP_AT(gi, i) \
+    ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
+
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -404,8 +437,7 @@
 /* process credentials */
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
-	int ngroups;
-	gid_t	groups[NGROUPS];
+	struct group_info *group_info;
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	int keep_capabilities:1;
 	struct user_struct *user;
@@ -500,8 +532,96 @@
 #define PF_SWAPOFF	0x00080000	/* I am in swapoff */
 #define PF_LESS_THROTTLE 0x00100000	/* Throttle me less: I clean memory */
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
+#define PF_FUTEX_DEBUG	0x00400000
 
 #ifdef CONFIG_SMP
+#define SD_FLAG_NEWIDLE		1	/* Balance when about to become idle */
+#define SD_FLAG_EXEC		2	/* Balance on exec */
+#define SD_FLAG_WAKE		4	/* Balance on task wakeup */
+#define SD_FLAG_FASTMIGRATE	8	/* Sync wakes put task on waking CPU */
+#define SD_FLAG_IDLE		16	/* Should not have all CPUs idle */
+
+struct sched_group {
+	struct sched_group *next;	/* Must be a circular list */
+	cpumask_t cpumask;
+};
+
+struct sched_domain {
+	/* These fields must be setup */
+	struct sched_domain *parent;	/* top domain must be null terminated */
+	struct sched_group *groups;	/* the balancing groups of the domain */
+	cpumask_t span;			/* span of all CPUs in this domain */
+	unsigned long min_interval;	/* Minimum balance interval ms */
+	unsigned long max_interval;	/* Maximum balance interval ms */
+	unsigned int busy_factor;	/* less balancing by factor if busy */
+	unsigned int imbalance_pct;	/* No balance until over watermark */
+	unsigned long long cache_hot_time; /* Task considered cache hot (ns) */
+	unsigned int cache_nice_tries;	/* Leave cache hot tasks for # tries */
+	int flags;			/* See SD_FLAG_* */
+
+	/* Runtime fields. */
+	unsigned long last_balance;	/* init to jiffies. units in jiffies */
+	unsigned int balance_interval;	/* initialise to 1. units in ms. */
+	unsigned int nr_balance_failed; /* initialise to 0 */
+};
+
+/* Common values for SMT siblings */
+#define SD_SIBLING_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 1,			\
+	.max_interval		= 2,			\
+	.busy_factor		= 8,			\
+	.imbalance_pct		= 110,			\
+	.cache_hot_time		= 0,			\
+	.cache_nice_tries	= 0,			\
+	.flags			= SD_FLAG_FASTMIGRATE | SD_FLAG_NEWIDLE | SD_FLAG_WAKE,\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+
+/* Common values for CPUs */
+#define SD_CPU_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 1,			\
+	.max_interval		= 8,			\
+	.busy_factor		= 32,			\
+	.imbalance_pct		= 125,			\
+	.cache_hot_time		= (5*1000000),		\
+	.cache_nice_tries	= 2,			\
+	.flags			= SD_FLAG_FASTMIGRATE | SD_FLAG_NEWIDLE,\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+
+#ifdef CONFIG_NUMA
+/* Common values for NUMA nodes */
+#define SD_NODE_INIT (struct sched_domain) {		\
+	.span			= CPU_MASK_NONE,	\
+	.parent			= NULL,			\
+	.groups			= NULL,			\
+	.min_interval		= 20,			\
+	.max_interval		= 1000*fls(num_online_cpus()),\
+	.busy_factor		= 4,			\
+	.imbalance_pct		= 125,			\
+	.cache_hot_time		= (5*1000000),		\
+	.cache_nice_tries	= 1,			\
+	.flags			= SD_FLAG_EXEC,		\
+	.last_balance		= jiffies,		\
+	.balance_interval	= 1,			\
+	.nr_balance_failed	= 0,			\
+}
+#endif
+
+DECLARE_PER_CPU(struct sched_domain, base_domains);
+#define cpu_sched_domain(cpu)	(&per_cpu(base_domains, (cpu)))
+#define this_sched_domain()	(&__get_cpu_var(base_domains))
+
 extern int set_cpus_allowed(task_t *p, cpumask_t new_mask);
 #else
 static inline int set_cpus_allowed(task_t *p, cpumask_t new_mask)
@@ -514,12 +634,14 @@
 
 #ifdef CONFIG_NUMA
 extern void sched_balance_exec(void);
-extern void node_nr_running_init(void);
 #else
 #define sched_balance_exec()   {}
-#define node_nr_running_init() {}
 #endif
 
+/* Move tasks off this (offline) CPU onto another. */
+extern void migrate_all_tasks(void);
+/* Try to move me here, if possible. */
+void migrate_to_cpu(int dest_cpu);
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(task_t *p);
 extern int task_nice(task_t *p);
@@ -583,8 +705,6 @@
 extern void FASTCALL(sched_fork(task_t * p));
 extern void FASTCALL(sched_exit(task_t * p));
 
-asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
-
 extern int in_group_p(gid_t);
 extern int in_egroup_p(gid_t);
 
--- diff/include/linux/security.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/security.h	2004-02-18 09:04:02.000000000 +0000
@@ -564,9 +564,8 @@
  *	Return 0 if permission is granted.
  * @task_setgroups:
  *	Check permission before setting the supplementary group set of the
- *	current process to @grouplist.
- *	@gidsetsize contains the number of elements in @grouplist.
- *	@grouplist contains the array of gids.
+ *	current process.
+ *	@group_info contains the new group information.
  *	Return 0 if permission is granted.
  * @task_setnice:
  *	Check permission before setting the nice value of @p to @nice.
@@ -1127,7 +1126,7 @@
 	int (*task_setpgid) (struct task_struct * p, pid_t pgid);
 	int (*task_getpgid) (struct task_struct * p);
 	int (*task_getsid) (struct task_struct * p);
-	int (*task_setgroups) (int gidsetsize, gid_t * grouplist);
+	int (*task_setgroups) (struct group_info *group_info);
 	int (*task_setnice) (struct task_struct * p, int nice);
 	int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim);
 	int (*task_setscheduler) (struct task_struct * p, int policy,
@@ -1686,9 +1685,9 @@
 	return security_ops->task_getsid (p);
 }
 
-static inline int security_task_setgroups (int gidsetsize, gid_t *grouplist)
+static inline int security_task_setgroups (struct group_info *group_info)
 {
-	return security_ops->task_setgroups (gidsetsize, grouplist);
+	return security_ops->task_setgroups (group_info);
 }
 
 static inline int security_task_setnice (struct task_struct *p, int nice)
@@ -2320,7 +2319,7 @@
 	return 0;
 }
 
-static inline int security_task_setgroups (int gidsetsize, gid_t *grouplist)
+static inline int security_task_setgroups (struct group_info *group_info)
 {
 	return 0;
 }
--- diff/include/linux/sem.h	2003-07-11 09:39:50.000000000 +0100
+++ source/include/linux/sem.h	2004-02-18 09:04:02.000000000 +0000
@@ -134,12 +134,6 @@
 	struct sem_undo_list *undo_list;
 };
 
-asmlinkage long sys_semget (key_t key, int nsems, int semflg);
-asmlinkage long sys_semop (int semid, struct sembuf __user *sops, unsigned nsops);
-asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg);
-asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
-			unsigned nsops, const struct timespec __user *timeout);
-
 void exit_sem(struct task_struct *p);
 
 #endif /* __KERNEL__ */
--- diff/include/linux/serial_core.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/serial_core.h	2004-02-18 09:04:02.000000000 +0000
@@ -158,7 +158,9 @@
 	unsigned char		x_char;			/* xon/xoff char */
 	unsigned char		regshift;		/* reg offset shift */
 	unsigned char		iotype;			/* io access style */
-
+#ifdef CONFIG_KGDB
+	int			kgdb;			/* in use by kgdb */
+#endif
 #define UPIO_PORT		(0)
 #define UPIO_HUB6		(1)
 #define UPIO_MEM		(2)
--- diff/include/linux/shm.h	2003-06-09 14:18:20.000000000 +0100
+++ source/include/linux/shm.h	2004-02-18 09:04:02.000000000 +0000
@@ -90,11 +90,6 @@
 #define SHM_LOCKED      02000   /* segment will not be swapped */
 #define SHM_HUGETLB     04000   /* segment will use huge TLB pages */
 
-long sys_shmat (int shmid, char __user *shmaddr, int shmflg, unsigned long *addr);
-asmlinkage long sys_shmget (key_t key, size_t size, int flag);
-asmlinkage long sys_shmdt (char __user *shmaddr);
-asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf);
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SHM_H_ */
--- diff/include/linux/smp_lock.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/smp_lock.h	2004-02-18 09:04:02.000000000 +0000
@@ -5,7 +5,9 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 
-#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
+#define BKL_DEBUG /* For testing for sleep_on() abuse */
+
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) || defined(BKL_DEBUG)
 
 extern spinlock_t kernel_flag;
 
--- diff/include/linux/socket.h	2003-11-25 15:24:59.000000000 +0000
+++ source/include/linux/socket.h	2004-02-18 09:04:02.000000000 +0000
@@ -245,10 +245,6 @@
 #define MSG_CMSG_COMPAT	0		/* We never have 32 bit fixups */
 #endif
 
-extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
-extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
-
-
 
 /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
 #define SOL_IP		0
--- diff/include/linux/spinlock.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/spinlock.h	2004-02-18 09:04:02.000000000 +0000
@@ -15,6 +15,12 @@
 
 #include <asm/processor.h>	/* for cpu relax */
 #include <asm/system.h>
+#ifdef CONFIG_KGDB
+#include <asm/current.h>
+#define SET_WHO(x, him) (x)->who = him;
+#else
+#define SET_WHO(x, him)
+#endif
 
 /*
  * Must define these before including other files, inline functions need them
@@ -55,6 +61,9 @@
 	const char *module;
 	char *owner;
 	int oline;
+#ifdef CONFIG_KGDB
+	struct task_struct *who;
+#endif
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
 
@@ -66,6 +75,7 @@
 		(x)->module = __FILE__; \
 		(x)->owner = NULL; \
 		(x)->oline = 0; \
+                SET_WHO(x, NULL) \
 	} while (0)
 
 #define CHECK_LOCK(x) \
@@ -88,6 +98,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 	} while (0)
 
 /* without debugging, spin_is_locked on UP always says
@@ -118,6 +129,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 		1; \
 	})
 
@@ -184,6 +196,17 @@
 
 #endif /* !SMP */
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock   (spinlock_t *lock);
+extern void _metered_spin_unlock (spinlock_t *lock);
+extern int  _metered_spin_trylock(spinlock_t *lock);
+extern void _metered_read_lock    (rwlock_t *lock);
+extern void _metered_read_unlock  (rwlock_t *lock);
+extern void _metered_write_lock   (rwlock_t *lock);
+extern void _metered_write_unlock (rwlock_t *lock);
+extern int  _metered_write_trylock(rwlock_t *lock);
+#endif
+
 /*
  * Define the various spin_lock and rw_lock methods.  Note we define these
  * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
@@ -389,6 +412,141 @@
 				_raw_spin_trylock(lock) ? 1 : \
 				({preempt_enable(); local_bh_enable(); 0;});})
 
+#ifdef CONFIG_LOCKMETER
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#undef spin_lock_irqsave
+#undef spin_lock_irq
+#undef spin_lock_bh
+#undef read_lock
+#undef read_unlock
+#undef write_lock
+#undef write_unlock
+#undef write_trylock
+#undef spin_unlock_bh
+#undef read_lock_irqsave
+#undef read_lock_irq
+#undef read_lock_bh
+#undef read_unlock_bh
+#undef write_lock_irqsave
+#undef write_lock_irq
+#undef write_lock_bh
+#undef write_unlock_bh
+
+#define spin_lock(lock) \
+do { \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while(0)
+
+#define spin_trylock(lock)     ({preempt_disable(); _metered_spin_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+} while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_unlock_bh(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+
+#define read_lock(lock)                ({preempt_disable(); _metered_read_lock(lock);})
+#define read_unlock(lock)      ({_metered_read_unlock(lock); preempt_enable();})
+#define write_lock(lock)       ({preempt_disable(); _metered_write_lock(lock);})
+#define write_unlock(lock)     ({_metered_write_unlock(lock); preempt_enable();})
+#define write_trylock(lock)    ({preempt_disable();_metered_write_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock_no_resched(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable_no_resched(); \
+} while (0)
+
+#define read_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_unlock_bh(lock) \
+do { \
+	_metered_read_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define write_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_unlock_bh(lock) \
+do { \
+	_metered_write_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#endif /* !CONFIG_LOCKMETER */
+
 /* "lock on reference count zero" */
 #ifndef ATOMIC_DEC_AND_LOCK
 #include <asm/atomic.h>
--- diff/include/linux/stallion.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/linux/stallion.h	2004-02-18 09:04:02.000000000 +0000
@@ -95,13 +95,8 @@
 	unsigned long		hwid;
 	void			*uartp;
 	struct tty_struct	*tty;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-#else
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
-#endif
 	struct work_struct	tqueue;
 	comstats_t		stats;
 	stlrq_t			tx;
--- diff/include/linux/sunrpc/auth.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sunrpc/auth.h	2004-02-18 09:04:02.000000000 +0000
@@ -28,8 +28,7 @@
 struct auth_cred {
 	uid_t	uid;
 	gid_t	gid;
-	int	ngroups;
-	gid_t	*groups;
+	struct group_info *group_info;
 };
 
 /*
--- diff/include/linux/sunrpc/cache.h	2004-02-09 10:36:12.000000000 +0000
+++ source/include/linux/sunrpc/cache.h	2004-02-18 09:04:02.000000000 +0000
@@ -132,12 +132,14 @@
  * If "set" == 0 :
  *    If an entry is found, it is returned
  *    If no entry is found, a new non-VALID entry is created.
- * If "set" == 1 :
+ * If "set" == 1 and INPLACE == 0 :
  *    If no entry is found a new one is inserted with data from "template"
  *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
  *    If a CACHE_VALID entry is found, a new entry is swapped in with data
  *       from "template"
- * If set == 2, we UPDATE, but don't swap. i.e. update in place
+ * If set == 1, and INPLACE == 1 :
+ *    As above, except that if a CACHE_VALID entry is found, we UPDATE in place
+ *       instead of swapping in a new entry.
  *
  * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
  * run but insteead CACHE_NEGATIVE is set in any new item.
@@ -164,8 +166,8 @@
 	RTN *tmp, *new=NULL;								\
 	struct cache_head **hp, **head;							\
 	SETUP;										\
- retry:											\
 	head = &(DETAIL)->hash_table[HASHFN];						\
+ retry:											\
 	if (set||new) write_lock(&(DETAIL)->hash_lock);					\
 	else read_lock(&(DETAIL)->hash_lock);						\
 	for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) {				\
@@ -175,6 +177,8 @@
 			if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
 				break;							\
 											\
+			if (new)							\
+				{INIT;}							\
 			cache_get(&tmp->MEMBER);					\
 			if (set) {							\
 				if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
@@ -203,6 +207,7 @@
 	}										\
 	/* Didn't find anything */							\
 	if (new) {									\
+		INIT;									\
 		new->MEMBER.next = *head;						\
 		*head = &new->MEMBER;							\
 		(DETAIL)->entries ++;							\
@@ -224,8 +229,6 @@
 	if (new) {									\
 		cache_init(&new->MEMBER);						\
 		cache_get(&new->MEMBER);						\
-		INIT;									\
-		tmp = new;								\
 		goto retry;								\
 	}										\
 	return NULL;									\
--- diff/include/linux/sunrpc/stats.h	2002-12-11 11:50:26.000000000 +0000
+++ source/include/linux/sunrpc/stats.h	2004-02-18 09:04:02.000000000 +0000
@@ -48,14 +48,13 @@
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry *	rpc_proc_register(struct rpc_stat *);
 void			rpc_proc_unregister(const char *);
-int			rpc_proc_read(char *, char **, off_t, int,
-					int *, void *);
 void			rpc_proc_zero(struct rpc_program *);
-struct proc_dir_entry *	svc_proc_register(struct svc_stat *);
+struct proc_dir_entry *	svc_proc_register(struct svc_stat *,
+					  struct file_operations *);
 void			svc_proc_unregister(const char *);
-int			svc_proc_read(char *, char **, off_t, int,
-					int *, void *);
-void			svc_proc_zero(struct svc_program *);
+
+void			svc_seq_show(struct seq_file *,
+				     const struct svc_stat *);
 
 extern struct proc_dir_entry	*proc_net_rpc;
 
@@ -63,13 +62,14 @@
 
 static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
 static inline void rpc_proc_unregister(const char *p) {}
-static inline int rpc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f) { return 0; }
 static inline void rpc_proc_zero(struct rpc_program *p) {}
 
-static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s) { return NULL; }
+static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
+						       struct file_operations *f) { return NULL; }
 static inline void svc_proc_unregister(const char *p) {}
-static inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f) { return 0; }
-static inline void svc_proc_zero(struct svc_program *p) {}
+
+static inline void svc_seq_show(struct seq_file *seq,
+				const struct svc_stat *st) {}
 
 #define proc_net_rpc NULL
 
--- diff/include/linux/sunrpc/svcauth.h	2003-01-16 11:30:37.000000000 +0000
+++ source/include/linux/sunrpc/svcauth.h	2004-02-18 09:04:02.000000000 +0000
@@ -16,10 +16,11 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
 
+#define SVC_CRED_NGROUPS	32
 struct svc_cred {
 	uid_t			cr_uid;
 	gid_t			cr_gid;
-	gid_t			cr_groups[NGROUPS];
+	gid_t			cr_groups[SVC_CRED_NGROUPS];
 };
 
 struct svc_rqst;		/* forward decl */
--- diff/include/linux/sysctl.h	2004-02-18 08:54:13.000000000 +0000
+++ source/include/linux/sysctl.h	2004-02-18 09:04:02.000000000 +0000
@@ -129,6 +129,7 @@
 	KERN_HPPA_UNALIGNED=59,	/* int: hppa unaligned-trap enable */
 	KERN_PRINTK_RATELIMIT=60, /* int: tune printk ratelimiting */
 	KERN_PRINTK_RATELIMIT_BURST=61,	/* int: tune printk ratelimiting */
+	KERN_PTY=62,		/* dir: pty driver */
 };
 
 
@@ -156,6 +157,8 @@
 	VM_SWAPPINESS=19,	/* Tendency to steal mapped memory */
 	VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
 	VM_MIN_FREE_KBYTES=21,	/* Minimum free kilobytes to maintain */
+	VM_LAPTOP_MODE=22,      /* vm laptop mode */
+	VM_BLOCK_DUMP=23,       /* block dump mode */
 };
 
 
@@ -192,6 +195,13 @@
 	RANDOM_UUID=6
 };
 
+/* /proc/sys/kernel/pty */
+enum
+{
+	PTY_MAX=1,
+	PTY_NR=2
+};
+
 /* /proc/sys/bus/isa */
 enum
 {
@@ -617,6 +627,8 @@
 	FS_LEASE_TIME=15,	/* int: maximum time to wait for a lease break */
 	FS_DQSTATS=16,	/* disc quota usage statistics */
 	FS_XFS=17,	/* struct: control xfs parameters */
+	FS_AIO_NR=18,	/* current system-wide number of aio requests */
+	FS_AIO_MAX_NR=19,	/* system-wide maximum number of aio requests */
 };
 
 /* /proc/sys/fs/quota/ */
@@ -719,7 +731,6 @@
 
 #ifdef __KERNEL__
 
-extern asmlinkage long sys_sysctl(struct __sysctl_args __user *);
 extern void sysctl_init(void);
 
 typedef struct ctl_table ctl_table;
--- diff/include/linux/sysfs.h	2003-08-26 10:00:54.000000000 +0100
+++ source/include/linux/sysfs.h	2004-02-18 09:04:02.000000000 +0000
@@ -18,6 +18,12 @@
 	mode_t			mode;
 };
 
+struct attribute_group {
+	char			* name;
+	struct attribute	** attrs;
+};
+
+
 struct bin_attribute {
 	struct attribute	attr;
 	size_t			size;
@@ -25,14 +31,13 @@
 	ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
 };
 
-int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
-int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
-
 struct sysfs_ops {
 	ssize_t	(*show)(struct kobject *, struct attribute *,char *);
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
+#ifdef CONFIG_SYSFS
+
 extern int
 sysfs_create_dir(struct kobject *);
 
@@ -57,13 +62,75 @@
 extern void
 sysfs_remove_link(struct kobject *, char * name);
 
-
-struct attribute_group {
-	char			* name;
-	struct attribute	** attrs;
-};
+int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
+int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
 
 int sysfs_create_group(struct kobject *, const struct attribute_group *);
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
 
+#else /* CONFIG_SYSFS */
+
+static inline int sysfs_create_dir(struct kobject * k)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_dir(struct kobject * k)
+{
+	;
+}
+
+static inline void sysfs_rename_dir(struct kobject * k, const char *new_name)
+{
+	;
+}
+
+static inline int sysfs_create_file(struct kobject * k, const struct attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_update_file(struct kobject * k, const struct attribute * a)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_file(struct kobject * k, const struct attribute * a)
+{
+	;
+}
+
+static inline int sysfs_create_link(struct kobject * k, struct kobject * t, char * n)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_link(struct kobject * k, char * name)
+{
+	;
+}
+
+
+static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a)
+{
+	return 0;
+}
+
+static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
+{
+	;
+}
+
+#endif /* CONFIG_SYSFS */
+
 #endif /* _SYSFS_H_ */
--- diff/include/linux/tty.h	2003-09-30 15:46:20.000000000 +0100
+++ source/include/linux/tty.h	2004-02-18 09:04:03.000000000 +0000
@@ -28,29 +28,13 @@
 
 
 /*
- * Note: don't mess with NR_PTYS until you understand the tty minor 
- * number allocation game...
  * (Note: the *_driver.minor_start values 1, 64, 128, 192 are
  * hardcoded at present.)
  */
-#define NR_PTYS		256	/* ptys/major */
-#define NR_LDISCS	16
-
-/*
- * Unix98 PTY's can be defined as any multiple of NR_PTYS up to
- * UNIX98_PTY_MAJOR_COUNT; this section defines what we need from the
- * config options
- */
-#ifdef CONFIG_UNIX98_PTYS
-# define UNIX98_NR_MAJORS ((CONFIG_UNIX98_PTY_COUNT+NR_PTYS-1)/NR_PTYS)
-# if UNIX98_NR_MAJORS <= 0
-#  undef CONFIG_UNIX98_PTYS
-# elif UNIX98_NR_MAJORS > UNIX98_PTY_MAJOR_COUNT
-#  error  Too many Unix98 ptys defined
-#  undef  UNIX98_NR_MAJORS
-#  define UNIX98_NR_MAJORS UNIX98_PTY_MAJOR_COUNT
-# endif
-#endif
+#define NR_PTYS	CONFIG_LEGACY_PTY_COUNT   /* Number of legacy ptys */
+#define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
+#define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
+#define NR_LDISCS		16
 
 /*
  * These are set up by the setup-routine at boot-time:
--- diff/include/linux/tty_driver.h	2003-06-30 10:07:24.000000000 +0100
+++ source/include/linux/tty_driver.h	2004-02-18 09:04:03.000000000 +0000
@@ -160,9 +160,10 @@
 	const char	*devfs_name;
 	const char	*name;
 	int	name_base;	/* offset of printed name */
-	short	major;		/* major device number */
-	short	minor_start;	/* start of minor device number*/
-	short	num;		/* number of devices */
+	int	major;		/* major device number */
+	int	minor_start;	/* start of minor device number */
+	int	minor_num;	/* number of *possible* devices */
+	int	num;		/* number of devices allocated */
 	short	type;		/* type of tty driver */
 	short	subtype;	/* subtype of tty driver */
 	struct termios init_termios; /* Initial termios */
@@ -244,11 +245,15 @@
  * TTY_DRIVER_NO_DEVFS --- if set, do not create devfs entries. This
  *	is only used by tty_register_driver().
  *
+ * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead
+ *	use dynamic memory keyed through the devpts filesystem.  This
+ *	is only applicable to the pty driver.
  */
 #define TTY_DRIVER_INSTALLED		0x0001
 #define TTY_DRIVER_RESET_TERMIOS	0x0002
 #define TTY_DRIVER_REAL_RAW		0x0004
 #define TTY_DRIVER_NO_DEVFS		0x0008
+#define TTY_DRIVER_DEVPTS_MEM		0x0010
 
 /* tty driver types */
 #define TTY_DRIVER_TYPE_SYSTEM		0x0001
--- diff/include/linux/workqueue.h	2003-05-21 11:50:10.000000000 +0100
+++ source/include/linux/workqueue.h	2004-02-18 09:04:03.000000000 +0000
@@ -60,6 +60,7 @@
 extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay));
 extern void flush_scheduled_work(void);
 extern int current_is_keventd(void);
+extern int keventd_up(void);
 
 extern void init_workqueues(void);
 
--- diff/include/linux/writeback.h	2003-10-09 09:47:17.000000000 +0100
+++ source/include/linux/writeback.h	2004-02-18 09:04:03.000000000 +0000
@@ -71,12 +71,15 @@
  * mm/page-writeback.c
  */
 int wakeup_bdflush(long nr_pages);
+void disk_is_spun_up(int postpone_writeback);
 
-/* These 5 are exported to sysctl. */
+/* These are exported to sysctl. */
 extern int dirty_background_ratio;
 extern int vm_dirty_ratio;
 extern int dirty_writeback_centisecs;
 extern int dirty_expire_centisecs;
+extern int block_dump;
+extern int laptop_mode;
 
 struct ctl_table;
 struct file;
--- diff/include/net/lapb.h	2003-10-09 09:47:34.000000000 +0100
+++ source/include/net/lapb.h	2004-02-18 09:04:03.000000000 +0000
@@ -80,7 +80,7 @@
  */
 struct lapb_cb {
 	struct list_head	node;
-	void			*token;
+	struct net_device	*dev;
 
 	/* Link status fields */
 	unsigned int		mode;
--- diff/init/Kconfig	2004-01-19 10:22:59.000000000 +0000
+++ source/init/Kconfig	2004-02-18 09:04:03.000000000 +0000
@@ -43,7 +43,7 @@
 
 config STANDALONE
 	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
-	default y
+	default n
 	help
 	  Select this option if you don't have magic firmware for drivers that
 	  need it.
@@ -285,4 +285,10 @@
 	  runs modprobe with the appropriate arguments, thereby
 	  loading the module if it is available.  If unsure, say Y.
 
+config STOP_MACHINE
+	bool
+	default y
+	depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
+	help
+	  Need stop_machine() primitive.
 endmenu
--- diff/init/Makefile	2003-05-21 11:50:16.000000000 +0100
+++ source/init/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -23,4 +23,4 @@
 
 include/linux/compile.h: FORCE
 	@echo '  CHK     $@'
-	@sh $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+	@$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
--- diff/init/do_mounts.c	2004-01-19 10:22:59.000000000 +0000
+++ source/init/do_mounts.c	2004-02-18 09:04:03.000000000 +0000
@@ -141,9 +141,11 @@
 	dev_t res = 0;
 	int part;
 
+#ifdef CONFIG_SYSFS
 	sys_mkdir("/sys", 0700);
 	if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
 		goto out;
+#endif
 
 	if (strncmp(name, "/dev/", 5) != 0) {
 		unsigned maj, min;
--- diff/init/do_mounts.h	2003-10-09 09:47:34.000000000 +0100
+++ source/init/do_mounts.h	2004-02-18 09:04:03.000000000 +0000
@@ -3,25 +3,13 @@
 #include <linux/kernel.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/init.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
 #include <linux/major.h>
 #include <linux/root_dev.h>
 
-asmlinkage long sys_unlink(const char *name);
-asmlinkage long sys_mknod(const char *name, int mode, unsigned dev);
-asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
-asmlinkage long sys_ioctl(int fd, int cmd, unsigned long arg);
-asmlinkage long sys_mkdir(const char *name, int mode);
-asmlinkage long sys_rmdir(const char *name);
-asmlinkage long sys_chdir(const char *name);
-asmlinkage long sys_fchdir(int fd);
-asmlinkage long sys_chroot(const char *name);
-asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
-				 unsigned long flags, void *data);
-asmlinkage long sys_umount(char *name, int flags);
-
 dev_t name_to_dev_t(char *name);
 void  change_floppy(char *fmt, ...);
 void  mount_block_root(char *name, int flags);
@@ -49,7 +37,6 @@
 #endif
 
 #if BITS_PER_LONG == 32
-asmlinkage long sys_stat64(char *name, struct stat64 *stat);
 static inline u32 bstat(char *name)
 {
 	struct stat64 stat;
--- diff/init/do_mounts_devfs.c	2003-09-30 15:46:21.000000000 +0100
+++ source/init/do_mounts_devfs.c	2004-02-18 09:04:03.000000000 +0000
@@ -2,14 +2,10 @@
 #include <linux/kernel.h>
 #include <linux/dirent.h>
 #include <linux/string.h>
+#include <linux/syscalls.h>
 
 #include "do_mounts.h"
 
-extern asmlinkage long sys_symlink(const char *old, const char *new);
-extern asmlinkage long sys_access(const char * filename, int mode);
-extern asmlinkage long sys_getdents64(unsigned int fd, void * dirent,
-				      unsigned int count);
-
 void __init mount_devfs(void)
 {
 	sys_mount("devfs", "/dev", "devfs", 0, NULL);
@@ -31,7 +27,8 @@
 	lseek(fd, 0, 0);
 
 	for (bytes = 0; bytes < len; bytes += n) {
-		n = sys_getdents64(fd, p + bytes, len - bytes);
+		n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes),
+					len - bytes);
 		if (n < 0)
 			return n;
 		if (n == 0)
--- diff/init/initramfs.c	2003-10-27 09:20:44.000000000 +0000
+++ source/init/initramfs.c	2004-02-18 09:04:03.000000000 +0000
@@ -7,6 +7,7 @@
 #include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/syscalls.h>
 
 static __initdata char *message;
 static void __init error(char *x)
@@ -25,17 +26,6 @@
 	kfree(where);
 }
 
-asmlinkage long sys_mkdir(char *name, int mode);
-asmlinkage long sys_mknod(char *name, int mode, unsigned dev);
-asmlinkage long sys_symlink(char *old, char *new);
-asmlinkage long sys_link(char *old, char *new);
-asmlinkage long sys_write(int fd, const char *buf, size_t size);
-asmlinkage long sys_chown(char *name, uid_t uid, gid_t gid);
-asmlinkage long sys_lchown(char *name, uid_t uid, gid_t gid);
-asmlinkage long sys_fchown(int fd, uid_t uid, gid_t gid);
-asmlinkage long sys_chmod(char *name, mode_t mode);
-asmlinkage long sys_fchmod(int fd, mode_t mode);
-
 /* link hash */
 
 static struct hash {
--- diff/init/main.c	2004-02-18 08:54:13.000000000 +0000
+++ source/init/main.c	2004-02-18 09:04:03.000000000 +0000
@@ -12,10 +12,12 @@
 #define __KERNEL_SYSCALLS__
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/kernel.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
@@ -141,6 +143,7 @@
 
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+static const char *panic_later, *panic_param;
 
 __setup("profile=", profile_setup);
 
@@ -253,20 +256,27 @@
 		return 0;
 	}
 
+	if (panic_later)
+		return 0;
+
 	if (val) {
 		/* Environment option */
 		unsigned int i;
 		for (i = 0; envp_init[i]; i++) {
-			if (i == MAX_INIT_ENVS)
-				panic("Too many boot env vars at `%s'", param);
+			if (i == MAX_INIT_ENVS) {
+				panic_later = "Too many boot env vars at `%s'";
+				panic_param = param;
+			}
 		}
 		envp_init[i] = param;
 	} else {
 		/* Command line option */
 		unsigned int i;
 		for (i = 0; argv_init[i]; i++) {
-			if (i == MAX_INIT_ARGS)
-				panic("Too many boot init vars at `%s'",param);
+			if (i == MAX_INIT_ARGS) {
+				panic_later = "Too many boot init vars at `%s'";
+				panic_param = param;
+			}
 		}
 		argv_init[i] = param;
 	}
@@ -289,6 +299,15 @@
 }
 __setup("init=", init_setup);
 
+static char *kinit_command;
+
+static int __init kinit_setup(char *str)
+{
+	kinit_command = str;
+	return 1;
+}
+__setup("kinit=", kinit_setup);
+
 extern void setup_arch(char **);
 extern void cpu_idle(void);
 
@@ -370,9 +389,11 @@
  * between the root thread and the init thread may cause start_kernel to
  * be reaped by free_initmem before the root thread has proceeded to
  * cpu_idle.
+ *
+ * gcc-3.4 accidentally inlines this function, so use noinline.
  */
 
-static void rest_init(void)
+static void noinline rest_init(void)
 {
 	kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
 	unlock_kernel();
@@ -405,12 +426,12 @@
 
 	build_all_zonelists();
 	page_alloc_init();
+	trap_init();
 	printk("Kernel command line: %s\n", saved_command_line);
 	parse_args("Booting kernel", command_line, __start___param,
 		   __stop___param - __start___param,
 		   &unknown_bootoption);
 	sort_main_extable();
-	trap_init();
 	rcu_init();
 	init_IRQ();
 	pidhash_init();
@@ -424,6 +445,8 @@
 	 * this. But we do want output early, in case something goes wrong.
 	 */
 	console_init();
+	if (panic_later)
+		panic(panic_later, panic_param);
 	profile_init();
 	local_irq_enable();
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -450,6 +473,7 @@
 	fork_init(num_physpages);
 	proc_caches_init();
 	buffer_init();
+	unnamed_dev_init();
 	security_scaffolding_startup();
 	vfs_caches_init(num_physpages);
 	radix_tree_init();
@@ -519,6 +543,7 @@
 	flush_scheduled_work();
 }
 
+asmlinkage long sys_access(const char __user * filename, int mode);
 /*
  * Ok, the machine is now initialized. None of the devices
  * have been touched yet, but the CPU subsystem is up and
@@ -549,7 +574,6 @@
 
 	migration_init();
 #endif
-	node_nr_running_init();
 	spawn_ksoftirqd();
 }
 
@@ -580,8 +604,16 @@
 	do_pre_smp_initcalls();
 
 	smp_init();
+	sched_init_smp();
 	do_basic_setup();
 
+	/*
+	 * check if there is an early userspace init, if yes
+	 * let it do all the work
+	 */
+	if (kinit_command || sys_access("/sbin/init", 0) == 0)
+		execute_command = kinit_command ? kinit_command : 0;
+	else
 	prepare_namespace();
 
 	/*
--- diff/ipc/Makefile	2002-12-16 09:26:07.000000000 +0000
+++ source/ipc/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -4,4 +4,5 @@
 
 obj-y   := util.o
 
-obj-$(CONFIG_SYSVIPC) += msg.o sem.o shm.o
+compat_ipc-$(CONFIG_COMPAT) := compat.o
+obj-$(CONFIG_SYSVIPC) += msg.o sem.o shm.o $(compat_ipc-y)
--- diff/ipc/sem.c	2004-01-19 10:22:59.000000000 +0000
+++ source/ipc/sem.c	2004-02-18 09:04:03.000000000 +0000
@@ -1011,11 +1011,6 @@
 	return un;
 }
 
-asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops)
-{
-	return sys_semtimedop(semid, tsops, nsops, NULL);
-}
-
 asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
 			unsigned nsops, const struct timespec __user *timeout)
 {
@@ -1181,6 +1176,11 @@
 	return error;
 }
 
+asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops)
+{
+	return sys_semtimedop(semid, tsops, nsops, NULL);
+}
+
 /* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between
  * parent and child tasks.
  *
--- diff/kernel/Makefile	2003-10-09 09:47:34.000000000 +0100
+++ source/kernel/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -6,19 +6,22 @@
 	    exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
-	    rcupdate.o intermodule.o extable.o params.o posix-timers.o
+	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
+	    kthread.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
+obj-$(CONFIG_LOCKMETER) += lockmeter.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
-obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_COMPAT) += compat.o compat_signal.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
+obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
--- diff/kernel/compat.c	2004-01-19 10:22:59.000000000 +0000
+++ source/kernel/compat.c	2004-02-18 09:04:03.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>	/* for MAX_SCHEDULE_TIMEOUT */
 #include <linux/futex.h>	/* for FUTEX_WAIT */
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 
 #include <asm/uaccess.h>
@@ -172,8 +173,6 @@
  * types that can be passed to put_user()/get_user().
  */
 
-extern asmlinkage long sys_sigpending(old_sigset_t *);
-
 asmlinkage long compat_sys_sigpending(compat_old_sigset_t *set)
 {
 	old_sigset_t s;
@@ -188,8 +187,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_sigprocmask(int, old_sigset_t *, old_sigset_t *);
-
 asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t *set,
 		compat_old_sigset_t *oset)
 {
@@ -230,8 +227,6 @@
 }
 #endif
 
-asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-
 asmlinkage long compat_sys_setrlimit(unsigned int resource, struct compat_rlimit *rlim)
 {
 	struct rlimit r;
@@ -257,7 +252,6 @@
 }
 
 #ifdef COMPAT_RLIM_OLD_INFINITY
-asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
 
 asmlinkage long compat_sys_old_getrlimit(unsigned int resource, struct compat_rlimit *rlim)
 {
@@ -282,9 +276,8 @@
 	}
 	return ret;
 }
-#endif
 
-asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);
+#endif
 
 asmlinkage long compat_sys_getrlimit (unsigned int resource, struct compat_rlimit *rlim)
 {
@@ -334,8 +327,6 @@
 	return 0;
 }
 
-asmlinkage long sys_getrusage(int who, struct rusage *ru);
-
 asmlinkage long compat_sys_getrusage(int who, struct compat_rusage *ru)
 {
 	struct rusage r;
@@ -381,9 +372,6 @@
 	}
 }
 
-extern asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
-					    unsigned long *user_mask_ptr);
-
 asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, 
 					     unsigned int len,
 					     compat_ulong_t *user_mask_ptr)
@@ -405,9 +393,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
-					    unsigned long *user_mask_ptr);
-
 asmlinkage int compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
 					    compat_ulong_t *user_mask_ptr)
 {
@@ -449,12 +434,6 @@
 	return 0;
 } 
 
-extern asmlinkage long sys_timer_settime(timer_t timer_id, int flags,
-				  struct itimerspec __user *new_setting,
-				 struct itimerspec __user *old_setting);
-extern asmlinkage long sys_timer_gettime(timer_t timer_id, 
-					 struct itimerspec __user *setting);
-
 long compat_timer_settime(timer_t timer_id, int flags, 
 			  struct compat_itimerspec *new, 
 			  struct compat_itimerspec *old)
@@ -487,9 +466,6 @@
 	return err;
 } 
 
-extern asmlinkage long
-sys_clock_settime(clockid_t which_clock, struct timespec __user *tp);
-
 long compat_clock_settime(clockid_t which_clock,  struct compat_timespec *tp)
 {
 	long err;
@@ -504,9 +480,6 @@
 	return err;
 } 
 
-extern asmlinkage long
-sys_clock_gettime(clockid_t which_clock, struct timespec __user *tp);
-
 long compat_clock_gettime(clockid_t which_clock,  struct compat_timespec *tp)
 {
 	long err;
@@ -521,9 +494,6 @@
 	return err;
 } 
 
-extern asmlinkage long
-sys_clock_getres(clockid_t which_clock, struct timespec __user *tp);
-
 long compat_clock_getres(clockid_t which_clock,  struct compat_timespec *tp)
 {
 	long err;
@@ -538,11 +508,6 @@
 	return err;
 } 
 
-extern asmlinkage long
-sys_clock_nanosleep(clockid_t which_clock, int flags,
-		     struct timespec __user *rqtp,
-		    struct timespec __user *rmtp);
-
 long compat_clock_nanosleep(clockid_t which_clock, int flags,
 			    struct compat_timespec __user *rqtp,
 			    struct compat_timespec __user *rmtp)
--- diff/kernel/cpu.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/cpu.c	2004-02-18 09:04:03.000000000 +0000
@@ -1,14 +1,19 @@
 /* CPU control.
- * (C) 2001 Rusty Russell
+ * (C) 2001, 2002, 2003, 2004 Rusty Russell
+ *
  * This code is licenced under the GPL.
  */
 #include <linux/proc_fs.h>
 #include <linux/smp.h>
 #include <linux/init.h>
-#include <linux/notifier.h>
 #include <linux/sched.h>
 #include <linux/unistd.h>
+#include <linux/kmod.h>		/* for hotplug_path */
 #include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/stop_machine.h>
 #include <asm/semaphore.h>
 
 /* This protects CPUs going up and down... */
@@ -19,20 +24,149 @@
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&cpu_chain, nb);
+	int ret;
+
+	if ((ret = down_interruptible(&cpucontrol)) != 0)
+		return ret;
+	ret = notifier_chain_register(&cpu_chain, nb);
+	up(&cpucontrol);
+	return ret;
 }
+EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
 {
-	notifier_chain_unregister(&cpu_chain,nb);
+	down(&cpucontrol);
+	notifier_chain_unregister(&cpu_chain, nb);
+	up(&cpucontrol);
+}
+EXPORT_SYMBOL(unregister_cpu_notifier);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static inline void check_for_tasks(int cpu, struct task_struct *k)
+{
+	struct task_struct *p;
+
+	write_lock_irq(&tasklist_lock);
+	for_each_process(p) {
+		if (task_cpu(p) == cpu && p != k)
+			printk(KERN_WARNING "Task %s is on cpu %d\n",
+				p->comm, cpu);
+	}
+	write_unlock_irq(&tasklist_lock);
+}
+
+/* Notify userspace when a cpu event occurs, by running '/sbin/hotplug
+ * cpu' with certain environment variables set.  */
+static int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	char *argv[3], *envp[5], cpu_str[12], action_str[32];
+	int i;
+
+	sprintf(cpu_str, "CPU=%d", cpu);
+	sprintf(action_str, "ACTION=%s", action);
+	/* FIXME: Add DEVPATH. --RR */
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "cpu";
+	argv[i] = NULL;
+
+	i = 0;
+	/* minimal command environment */
+	envp [i++] = "HOME=/";
+	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp [i++] = cpu_str;
+	envp [i++] = action_str;
+	envp [i] = NULL;
+
+	return call_usermodehelper(argv[0], argv, envp, 0);
+}
+
+/* Take this CPU down. */
+static int take_cpu_down(void *unused)
+{
+	int err;
+
+	/* Take offline: makes arch_cpu_down somewhat easier. */
+	cpu_clear(smp_processor_id(), cpu_online_map);
+
+	/* Ensure this CPU doesn't handle any more interrupts. */
+	err = __cpu_disable();
+	if (err < 0)
+		cpu_set(smp_processor_id(), cpu_online_map);
+	else
+		/* Everyone else gets kicked off. */
+		migrate_all_tasks();
+
+	return err;
+}
+
+int cpu_down(unsigned int cpu)
+{
+	int err;
+	struct task_struct *p;
+
+	if ((err = lock_cpu_hotplug_interruptible()) != 0)
+		return err;
+
+	if (num_online_cpus() == 1) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (!cpu_online(cpu)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	p = __stop_machine_run(take_cpu_down, NULL, cpu);
+	if (IS_ERR(p)) {
+		err = PTR_ERR(p);
+		goto out;
+	}
+
+	if (cpu_online(cpu))
+		goto out_thread;
+
+	check_for_tasks(cpu, p);
+
+	/* Wait for it to sleep (leaving idle task). */
+	while (!idle_cpu(cpu))
+		yield();
+
+	/* This actually kills the CPU. */
+	__cpu_die(cpu);
+
+	/* Move it here so it can run. */
+	kthread_bind(p, smp_processor_id());
+
+	/* CPU is completely dead: tell everyone.  Too late to complain. */
+	if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu)
+	    == NOTIFY_BAD)
+		BUG();
+
+	cpu_run_sbin_hotplug(cpu, "offline");
+
+out_thread:
+	err = kthread_stop(p);
+out:
+	unlock_cpu_hotplug();
+	return err;
+}
+#else
+static inline int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	return 0;
 }
+#endif /*CONFIG_HOTPLUG_CPU*/
 
 int __devinit cpu_up(unsigned int cpu)
 {
 	int ret;
 	void *hcpu = (void *)(long)cpu;
 
-	if ((ret = down_interruptible(&cpucontrol)) != 0)
+	if ((ret = lock_cpu_hotplug_interruptible()) != 0)
 		return ret;
 
 	if (cpu_online(cpu)) {
@@ -61,6 +195,6 @@
 	if (ret != 0)
 		notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu);
 out:
-	up(&cpucontrol);
+	unlock_cpu_hotplug();
 	return ret;
 }
--- diff/kernel/fork.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/fork.c	2004-02-18 09:04:03.000000000 +0000
@@ -26,6 +26,7 @@
 #include <linux/mman.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 #include <linux/jiffies.h>
 #include <linux/futex.h>
 #include <linux/ptrace.h>
@@ -86,6 +87,7 @@
 
 	security_task_free(tsk);
 	free_uid(tsk->user);
+	put_group_info(tsk->group_info);
 	free_task(tsk);
 }
 
@@ -273,7 +275,7 @@
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->map_count = 0;
-	mm->rss = 0;
+	zero_rss(mm);
 	cpus_clear(mm->cpu_vm_mask);
 	pprev = &mm->mmap;
 
@@ -878,6 +880,7 @@
 
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
+	get_group_info(p->group_info);
 
 	/*
 	 * If multiple threads are within copy_process(), then this check
@@ -1084,6 +1087,7 @@
 bad_fork_cleanup_put_domain:
 	module_put(p->thread_info->exec_domain->module);
 bad_fork_cleanup_count:
+	put_group_info(p->group_info);
 	atomic_dec(&p->user->processes);
 	free_uid(p->user);
 bad_fork_free:
--- diff/kernel/futex.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/futex.c	2004-02-18 09:04:03.000000000 +0000
@@ -269,7 +269,11 @@
 	 * The lock in wake_up_all() is a crucial memory barrier after the
 	 * list_del_init() and also before assigning to q->lock_ptr.
 	 */
+
+	current->flags |= PF_FUTEX_DEBUG;
 	wake_up_all(&q->waiters);
+	current->flags &= ~PF_FUTEX_DEBUG;
+
 	/*
 	 * The waiting task can free the futex_q as soon as this is written,
 	 * without taking any locks.  This must come last.
@@ -490,8 +494,11 @@
 	 * !list_empty() is safe here without any lock.
 	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
 	 */
-	if (likely(!list_empty(&q.list)))
+	if (likely(!list_empty(&q.list))) {
+		current->flags |= PF_FUTEX_DEBUG;
 		time = schedule_timeout(time);
+		current->flags &= ~PF_FUTEX_DEBUG;
+	}
 	__set_current_state(TASK_RUNNING);
 
 	/*
@@ -505,7 +512,11 @@
 	if (time == 0)
 		return -ETIMEDOUT;
 	/* A spurious wakeup should never happen. */
-	WARN_ON(!signal_pending(current));
+	if (!signal_pending(current)) {
+		printk("futex_wait woken: %lu %i %lu\n",
+		       uaddr, val, time);
+		WARN_ON(1);
+	}
 	return -EINTR;
 
  out_unqueue:
--- diff/kernel/kmod.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/kmod.c	2004-02-18 09:04:03.000000000 +0000
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/kmod.h>
 #include <linux/smp_lock.h>
@@ -149,6 +150,7 @@
 {
 	struct subprocess_info *sub_info = data;
 	int retval;
+	cpumask_t mask = CPU_MASK_ALL;
 
 	/* Unblock all signals. */
 	flush_signals(current);
@@ -158,6 +160,9 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
+	/* We can run anywhere, unlike our parent keventd(). */
+	set_cpus_allowed(current, mask);
+
 	retval = -EPERM;
 	if (current->fs->root)
 		retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
--- diff/kernel/module.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/module.c	2004-02-18 09:04:03.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
 #include <linux/seq_file.h>
+#include <linux/syscalls.h>
 #include <linux/fcntl.h>
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
@@ -32,6 +33,7 @@
 #include <linux/err.h>
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
+#include <linux/stop_machine.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/pgalloc.h>
@@ -457,157 +459,51 @@
 	}
 }
 
-#ifdef CONFIG_SMP
-/* Thread to stop each CPU in user context. */
-enum stopref_state {
-	STOPREF_WAIT,
-	STOPREF_PREPARE,
-	STOPREF_DISABLE_IRQ,
-	STOPREF_EXIT,
-};
-
-static enum stopref_state stopref_state;
-static unsigned int stopref_num_threads;
-static atomic_t stopref_thread_ack;
-
-static int stopref(void *cpu)
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+static inline int try_force(unsigned int flags)
 {
-	int irqs_disabled = 0;
-	int prepared = 0;
-
-	sprintf(current->comm, "kmodule%lu\n", (unsigned long)cpu);
-
-	/* Highest priority we can manage, and move to right CPU. */
-#if 0 /* FIXME */
-	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-	setscheduler(current->pid, SCHED_FIFO, &param);
-#endif
-	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
-
-	/* Ack: we are alive */
-	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
-	atomic_inc(&stopref_thread_ack);
-
-	/* Simple state machine */
-	while (stopref_state != STOPREF_EXIT) {
-		if (stopref_state == STOPREF_DISABLE_IRQ && !irqs_disabled) {
-			local_irq_disable();
-			irqs_disabled = 1;
-			/* Ack: irqs disabled. */
-			mb(); /* Must read state first. */
-			atomic_inc(&stopref_thread_ack);
-		} else if (stopref_state == STOPREF_PREPARE && !prepared) {
-			/* Everyone is in place, hold CPU. */
-			preempt_disable();
-			prepared = 1;
-			mb(); /* Must read state first. */
-			atomic_inc(&stopref_thread_ack);
-		}
-		if (irqs_disabled || prepared)
-			cpu_relax();
-		else
-			yield();
-	}
-
-	/* Ack: we are exiting. */
-	mb(); /* Must read state first. */
-	atomic_inc(&stopref_thread_ack);
-
-	if (irqs_disabled)
-		local_irq_enable();
-	if (prepared)
-		preempt_enable();
-
-	return 0;
+	int ret = (flags & O_TRUNC);
+	if (ret)
+		tainted |= TAINT_FORCED_MODULE;
+	return ret;
 }
-
-/* Change the thread state */
-static void stopref_set_state(enum stopref_state state, int sleep)
+#else
+static inline int try_force(unsigned int flags)
 {
-	atomic_set(&stopref_thread_ack, 0);
-	wmb();
-	stopref_state = state;
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads) {
-		if (sleep)
-			yield();
-		else
-			cpu_relax();
-	}
+	return 0;
 }
+#endif /* CONFIG_MODULE_FORCE_UNLOAD */
 
-/* Stop the machine.  Disables irqs. */
-static int stop_refcounts(void)
+struct stopref
 {
-	unsigned int i, cpu;
-	cpumask_t old_allowed;
-	int ret = 0;
-
-	/* One thread per cpu.  We'll do our own. */
-	cpu = smp_processor_id();
-
-	/* FIXME: racy with set_cpus_allowed. */
-	old_allowed = current->cpus_allowed;
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
-
-	atomic_set(&stopref_thread_ack, 0);
-	stopref_num_threads = 0;
-	stopref_state = STOPREF_WAIT;
-
-	/* No CPUs can come up or down during this. */
-	lock_cpu_hotplug();
-
-	for (i = 0; i < NR_CPUS; i++) {
-		if (i == cpu || !cpu_online(i))
-			continue;
-		ret = kernel_thread(stopref, (void *)(long)i, CLONE_KERNEL);
-		if (ret < 0)
-			break;
-		stopref_num_threads++;
-	}
+	struct module *mod;
+	int flags;
+	int *forced;
+};
 
-	/* Wait for them all to come to life. */
-	while (atomic_read(&stopref_thread_ack) != stopref_num_threads)
-		yield();
+/* Whole machine is stopped with interrupts off when this runs. */
+static inline int __try_stop_module(void *_sref)
+{
+	struct stopref *sref = _sref;
 
-	/* If some failed, kill them all. */
-	if (ret < 0) {
-		stopref_set_state(STOPREF_EXIT, 1);
-		unlock_cpu_hotplug();
-		return ret;
+	/* If it's not unused, quit unless we are told to block. */
+	if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) {
+		if (!(*sref->forced = try_force(sref->flags)))
+			return -EWOULDBLOCK;
 	}
 
-	/* Don't schedule us away at this point, please. */
-	preempt_disable();
-
-	/* Now they are all scheduled, make them hold the CPUs, ready. */
-	stopref_set_state(STOPREF_PREPARE, 0);
-
-	/* Make them disable irqs. */
-	stopref_set_state(STOPREF_DISABLE_IRQ, 0);
-
-	local_irq_disable();
+	/* Mark it as dying. */
+	sref->mod->waiter = current;
+	sref->mod->state = MODULE_STATE_GOING;
 	return 0;
 }
 
-/* Restart the machine.  Re-enables irqs. */
-static void restart_refcounts(void)
-{
-	stopref_set_state(STOPREF_EXIT, 0);
-	local_irq_enable();
-	preempt_enable();
-	unlock_cpu_hotplug();
-}
-#else /* ...!SMP */
-static inline int stop_refcounts(void)
-{
-	local_irq_disable();
-	return 0;
-}
-static inline void restart_refcounts(void)
+static int try_stop_module(struct module *mod, int flags, int *forced)
 {
-	local_irq_enable();
+	struct stopref sref = { mod, flags, forced };
+
+	return stop_machine_run(__try_stop_module, &sref, NR_CPUS);
 }
-#endif
 
 unsigned int module_refcount(struct module *mod)
 {
@@ -622,21 +518,6 @@
 /* This exists whether we can unload or not */
 static void free_module(struct module *mod);
 
-#ifdef CONFIG_MODULE_FORCE_UNLOAD
-static inline int try_force(unsigned int flags)
-{
-	int ret = (flags & O_TRUNC);
-	if (ret)
-		tainted |= TAINT_FORCED_MODULE;
-	return ret;
-}
-#else
-static inline int try_force(unsigned int flags)
-{
-	return 0;
-}
-#endif /* CONFIG_MODULE_FORCE_UNLOAD */
-
 /* Stub function for modules which don't have an exitfn */
 void cleanup_module(void)
 {
@@ -706,33 +587,18 @@
 			goto out;
 		}
 	}
-	/* Stop the machine so refcounts can't move: irqs disabled. */
-	DEBUGP("Stopping refcounts...\n");
-	ret = stop_refcounts();
-	if (ret != 0)
-		goto out;
-
-	/* If it's not unused, quit unless we are told to block. */
-	if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) {
-		forced = try_force(flags);
-		if (!forced) {
-			ret = -EWOULDBLOCK;
-			restart_refcounts();
-			goto out;
-		}
-	}
 
-	/* Mark it as dying. */
-	mod->waiter = current;
-	mod->state = MODULE_STATE_GOING;
-	restart_refcounts();
+	/* Stop the machine so refcounts can't move and disable module. */
+	ret = try_stop_module(mod, flags, &forced);
 
 	/* Never wait if forced. */
 	if (!forced && module_refcount(mod) != 0)
 		wait_for_zero_refcount(mod);
 
 	/* Final destruction now noone is using it. */
+	up(&module_mutex);
 	mod->exit();
+	down(&module_mutex);
 	free_module(mod);
 
  out:
--- diff/kernel/panic.c	2003-10-09 09:47:34.000000000 +0100
+++ source/kernel/panic.c	2004-02-18 09:04:03.000000000 +0000
@@ -16,11 +16,10 @@
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <linux/sysrq.h>
+#include <linux/syscalls.h>
 #include <linux/interrupt.h>
 #include <linux/nmi.h>
 
-asmlinkage void sys_sync(void);	/* it's really int */
-
 int panic_timeout;
 int panic_on_oops;
 int tainted;
--- diff/kernel/pid.c	2003-10-27 09:20:39.000000000 +0000
+++ source/kernel/pid.c	2004-02-18 09:04:03.000000000 +0000
@@ -122,6 +122,8 @@
 	}
 	
 	if (!offset || !atomic_read(&map->nr_free)) {
+		if (!offset)
+			map--;
 next_map:
 		map = next_free_map(map, &max_steps);
 		if (!map)
@@ -268,6 +270,9 @@
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
  * more.
  */
+#ifdef CONFIG_KGDB
+int kgdb_pid_init_done; /* so we don't call prior to... */
+#endif
 void __init pidhash_init(void)
 {
 	int i, j, pidhash_size;
@@ -289,6 +294,9 @@
 		for (j = 0; j < pidhash_size; j++)
 			INIT_LIST_HEAD(&pid_hash[i][j]);
 	}
+#ifdef CONFIG_KGDB
+	kgdb_pid_init_done++;
+#endif
 }
 
 void __init pidmap_init(void)
--- diff/kernel/posix-timers.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/posix-timers.c	2004-02-18 09:04:03.000000000 +0000
@@ -426,7 +426,7 @@
 
 	spin_lock_init(&new_timer->it_lock);
 	do {
-		if (unlikely(!idr_pre_get(&posix_timers_id))) {
+		if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
 			error = -EAGAIN;
 			new_timer->it_id = (timer_t)-1;
 			goto out;
--- diff/kernel/power/disk.c	2003-10-27 09:20:39.000000000 +0000
+++ source/kernel/power/disk.c	2004-02-18 09:04:03.000000000 +0000
@@ -12,6 +12,7 @@
 
 
 #include <linux/suspend.h>
+#include <linux/syscalls.h>
 #include <linux/reboot.h>
 #include <linux/string.h>
 #include <linux/delay.h>
@@ -28,8 +29,6 @@
 extern int pmdisk_restore(void);
 extern int pmdisk_free(void);
 
-extern long sys_sync(void);
-
 
 /**
  *	power_down - Shut machine down for hibernate.
--- diff/kernel/power/swsusp.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/power/swsusp.c	2004-02-18 09:04:03.000000000 +0000
@@ -59,6 +59,7 @@
 #include <linux/buffer_head.h>
 #include <linux/swapops.h>
 #include <linux/bootmem.h>
+#include <linux/syscalls.h>
 #include <linux/console.h>
 
 #include <asm/uaccess.h>
@@ -68,8 +69,6 @@
 
 #include "power.h"
 
-extern long sys_sync(void);
-
 unsigned char software_suspend_enabled = 0;
 
 extern void do_magic(int resume);
--- diff/kernel/printk.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/printk.c	2004-02-18 09:04:03.000000000 +0000
@@ -501,7 +501,7 @@
 
 	/* Emit the output into the temporary buffer */
 	va_start(args, fmt);
-	printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 	va_end(args);
 
 	/*
@@ -522,7 +522,7 @@
 			log_level_unknown = 1;
 	}
 
-	if (!cpu_online(smp_processor_id())) {
+	if (!cpu_online(smp_processor_id()) && !system_running) {
 		/*
 		 * Some console drivers may assume that per-cpu resources have
 		 * been allocated.  So don't allow them to be called by this
--- diff/kernel/rcupdate.c	2003-10-09 09:47:34.000000000 +0100
+++ source/kernel/rcupdate.c	2004-02-18 09:04:03.000000000 +0000
@@ -110,6 +110,7 @@
 	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
 		return;
 	}
+	/* Can't change, since spin lock held. */
 	rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
 }
 
@@ -154,6 +155,60 @@
 }
 
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
+ * locking requirements, the list it's pulling from has to belong to a cpu
+ * which is dead and hence not processing interrupts.
+ */
+static void rcu_move_batch(struct list_head *list)
+{
+	struct list_head *entry;
+	int cpu = smp_processor_id();
+
+	local_irq_disable();
+	while (!list_empty(list)) {
+		entry = list->next;
+		list_del(entry);
+		list_add_tail(entry, &RCU_nxtlist(cpu));
+	}
+	local_irq_enable();
+}
+
+static void rcu_offline_cpu(int cpu)
+{
+	/* if the cpu going offline owns the grace period
+	 * we can block indefinitely waiting for it, so flush
+	 * it here
+	 */
+	spin_lock_irq(&rcu_ctrlblk.mutex);
+	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
+		goto unlock;
+
+	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
+	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
+		rcu_ctrlblk.curbatch++;
+		/* We may avoid calling start batch if
+		 * we are starting the batch only
+		 * because of the DEAD CPU (the current
+		 * CPU will start a new batch anyway for
+		 * the callbacks we will move to current CPU).
+		 * However, we will avoid this optimisation
+		 * for now.
+		 */
+		rcu_start_batch(rcu_ctrlblk.maxbatch);
+	}
+unlock:
+	spin_unlock_irq(&rcu_ctrlblk.mutex);
+
+	rcu_move_batch(&RCU_curlist(cpu));
+	rcu_move_batch(&RCU_nxtlist(cpu));
+
+	tasklet_kill_immediate(&RCU_tasklet(cpu), cpu);
+}
+
+#endif
+
 /*
  * This does the RCU processing work from tasklet context. 
  */
@@ -214,7 +269,11 @@
 	case CPU_UP_PREPARE:
 		rcu_online_cpu(cpu);
 		break;
-	/* Space reserved for CPU_OFFLINE :) */
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		rcu_offline_cpu(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
--- diff/kernel/resource.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/resource.c	2004-02-18 09:04:03.000000000 +0000
@@ -475,6 +475,8 @@
 	p = &parent->child;
 	end = start + n - 1;
 
+	write_lock(&resource_lock);
+
 	for (;;) {
 		struct resource *res = *p;
 
@@ -488,11 +490,15 @@
 			if (res->start != start || res->end != end)
 				break;
 			*p = res->sibling;
+			write_unlock(&resource_lock);
 			kfree(res);
 			return;
 		}
 		p = &res->sibling;
 	}
+
+	write_unlock(&resource_lock);
+
 	printk(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
 }
 
--- diff/kernel/sched.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/sched.c	2004-02-18 09:04:03.000000000 +0000
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/smp_lock.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
@@ -37,6 +38,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/kthread.h>
 
 #ifdef CONFIG_NUMA
 #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu))
@@ -89,7 +91,6 @@
 #define MAX_SLEEP_AVG		(AVG_TIMESLICE * MAX_BONUS)
 #define STARVATION_LIMIT	(MAX_SLEEP_AVG)
 #define NS_MAX_SLEEP_AVG	(JIFFIES_TO_NS(MAX_SLEEP_AVG))
-#define NODE_THRESHOLD		125
 #define CREDIT_LIMIT		100
 
 /*
@@ -185,11 +186,14 @@
 typedef struct runqueue runqueue_t;
 
 struct prio_array {
-	int nr_active;
+	unsigned int nr_active;
 	unsigned long bitmap[BITMAP_SIZE];
 	struct list_head queue[MAX_PRIO];
 };
 
+#define SCHED_LOAD_SHIFT 7	/* increase resolution of load calculations */
+#define SCHED_LOAD_SCALE (1 << SCHED_LOAD_SHIFT)
+
 /*
  * This is the main, per-CPU runqueue data structure.
  *
@@ -200,23 +204,33 @@
 struct runqueue {
 	spinlock_t lock;
 	unsigned long nr_running, nr_switches, expired_timestamp,
-		      nr_uninterruptible, timestamp_last_tick;
+		      nr_uninterruptible;
+	unsigned long long timestamp_last_tick;
 	task_t *curr, *idle;
 	struct mm_struct *prev_mm;
 	prio_array_t *active, *expired, arrays[2];
-	int best_expired_prio, prev_cpu_load[NR_CPUS];
-#ifdef CONFIG_NUMA
-	atomic_t *node_nr_running;
-	int prev_node_load[MAX_NUMNODES];
+	int best_expired_prio;
+
+	atomic_t nr_iowait;
+
+#ifdef CONFIG_SMP
+	unsigned long cpu_load[NR_CPUS];
 #endif
+	/* For active balancing */
+	int active_balance;
+	int push_cpu;
+
 	task_t *migration_thread;
 	struct list_head migration_queue;
-
-	atomic_t nr_iowait;
 };
 
 static DEFINE_PER_CPU(struct runqueue, runqueues);
 
+#ifdef CONFIG_SMP
+/* Mandatory scheduling domains */
+DEFINE_PER_CPU(struct sched_domain, base_domains);
+#endif
+
 #define cpu_rq(cpu)		(&per_cpu(runqueues, (cpu)))
 #define this_rq()		(&__get_cpu_var(runqueues))
 #define task_rq(p)		cpu_rq(task_cpu(p))
@@ -231,51 +245,16 @@
 # define task_running(rq, p)		((rq)->curr == (p))
 #endif
 
-#ifdef CONFIG_NUMA
-
-/*
- * Keep track of running tasks.
- */
-
-static atomic_t node_nr_running[MAX_NUMNODES] ____cacheline_maxaligned_in_smp =
-	{[0 ...MAX_NUMNODES-1] = ATOMIC_INIT(0)};
-
-static inline void nr_running_init(struct runqueue *rq)
-{
-	rq->node_nr_running = &node_nr_running[0];
-}
-
 static inline void nr_running_inc(runqueue_t *rq)
 {
-	atomic_inc(rq->node_nr_running);
 	rq->nr_running++;
 }
 
 static inline void nr_running_dec(runqueue_t *rq)
 {
-	atomic_dec(rq->node_nr_running);
 	rq->nr_running--;
 }
 
-__init void node_nr_running_init(void)
-{
-	int i;
-
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_possible(i))
-			cpu_rq(i)->node_nr_running =
-				&node_nr_running[cpu_to_node(i)];
-	}
-}
-
-#else /* !CONFIG_NUMA */
-
-# define nr_running_init(rq)	do { } while (0)
-# define nr_running_inc(rq)	do { (rq)->nr_running++; } while (0)
-# define nr_running_dec(rq)	do { (rq)->nr_running--; } while (0)
-
-#endif /* CONFIG_NUMA */
-
 /*
  * task_rq_lock - lock the runqueue a given task resides on and disable
  * interrupts.  Note the ordering: we can safely lookup the task_rq without
@@ -543,37 +522,30 @@
 typedef struct {
 	struct list_head list;
 	task_t *task;
+	int dest_cpu;
 	struct completion done;
 } migration_req_t;
 
 /*
- * The task's runqueue lock must be held, and the new mask must be valid.
+ * The task's runqueue lock must be held.
  * Returns true if you have to wait for migration thread.
  */
-static int __set_cpus_allowed(task_t *p, cpumask_t new_mask,
-				migration_req_t *req)
+static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req)
 {
 	runqueue_t *rq = task_rq(p);
 
-	p->cpus_allowed = new_mask;
-	/*
-	 * Can the task run on the task's current CPU? If not then
-	 * migrate the thread off to a proper CPU.
-	 */
-	if (cpu_isset(task_cpu(p), new_mask))
-		return 0;
-
 	/*
 	 * If the task is not on a runqueue (and not running), then
 	 * it is sufficient to simply update the task's cpu field.
 	 */
 	if (!p->array && !task_running(rq, p)) {
-		set_task_cpu(p, any_online_cpu(p->cpus_allowed));
+		set_task_cpu(p, dest_cpu);
 		return 0;
 	}
 
 	init_completion(&req->done);
 	req->task = p;
+	req->dest_cpu = dest_cpu;
 	list_add(&req->list, &rq->migration_queue);
 	return 1;
 }
@@ -634,9 +606,79 @@
 }
 
 EXPORT_SYMBOL_GPL(kick_process);
+/*
+ * Return a low guess at the load of cpu. Update previous history if update
+ * is true
+ */
+static inline unsigned long get_low_cpu_load(int cpu, int update)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	runqueue_t *this_rq = this_rq();
+	unsigned long nr = rq->nr_running << SCHED_LOAD_SHIFT;
+	unsigned long load = this_rq->cpu_load[cpu];
+	unsigned long ret = min(nr, load);
+
+	if (update)
+		this_rq->cpu_load[cpu] = (nr + load) / 2;
+
+	return ret;
+}
+
+static inline unsigned long get_high_cpu_load(int cpu, int update)
+{
+	runqueue_t *rq = cpu_rq(cpu);
+	runqueue_t *this_rq = this_rq();
+	unsigned long nr = rq->nr_running << SCHED_LOAD_SHIFT;
+	unsigned long load = this_rq->cpu_load[cpu];
+	unsigned long ret = max(nr, load);
+
+	if (update)
+		this_rq->cpu_load[cpu] = (nr + load) / 2;
+
+	return ret;
+}
 
 #endif
 
+/*
+ * sched_balance_wake can be used with SMT architectures to wake a
+ * task onto an idle sibling if cpu is not idle. Returns cpu if
+ * cpu is idle or no siblings are idle, otherwise returns an idle
+ * sibling.
+ */
+#if defined(CONFIG_SMP) && defined(ARCH_HAS_SCHED_WAKE_BALANCE)
+static int sched_balance_wake(int cpu, task_t *p)
+{
+	struct sched_domain *domain;
+	int i;
+
+	if (idle_cpu(cpu))
+		return cpu;
+
+	domain = cpu_sched_domain(cpu);
+	if (!(domain->flags & SD_FLAG_WAKE))
+		return cpu;
+
+	for_each_cpu_mask(i, domain->span) {
+		if (!cpu_online(i))
+			continue;
+
+		if (!cpu_isset(i, p->cpus_allowed))
+			continue;
+
+		if (idle_cpu(i))
+			return i;
+	}
+
+	return cpu;
+}
+#else
+static inline int sched_balance_wake(int cpu, task_t *p)
+{
+	return cpu;
+}
+#endif
+
 /***
  * try_to_wake_up - wake up a thread
  * @p: the to-be-woken-up thread
@@ -657,44 +699,117 @@
 	int success = 0;
 	long old_state;
 	runqueue_t *rq;
+	int cpu, this_cpu;
+#ifdef CONFIG_SMP
+	unsigned long long now;
+	unsigned long load, this_load;
+	int new_cpu;
+	struct sched_domain *sd;
+	runqueue_t *this_rq;
+#endif
 
-repeat_lock_task:
 	rq = task_rq_lock(p, &flags);
 	old_state = p->state;
-	if (old_state & state) {
-		if (!p->array) {
-			/*
-			 * Fast-migrate the task if it's not running or runnable
-			 * currently. Do not violate hard affinity.
-			 */
-			if (unlikely(sync && !task_running(rq, p) &&
-				(task_cpu(p) != smp_processor_id()) &&
-					cpu_isset(smp_processor_id(),
-							p->cpus_allowed))) {
-
-				set_task_cpu(p, smp_processor_id());
-				task_rq_unlock(rq, &flags);
-				goto repeat_lock_task;
-			}
-			if (old_state == TASK_UNINTERRUPTIBLE) {
-				rq->nr_uninterruptible--;
-				/*
-				 * Tasks on involuntary sleep don't earn
-				 * sleep_avg beyond just interactive state.
-				 */
-				p->activated = -1;
-			}
-			if (sync && (task_cpu(p) == smp_processor_id()))
-				__activate_task(p, rq);
-			else {
-				activate_task(p, rq);
-				if (TASK_PREEMPTS_CURR(p, rq))
-					resched_task(rq->curr);
-			}
-			success = 1;
+	if (!(old_state & state))
+		goto out;
+
+	if (p->array)
+		goto out_running;
+
+	this_cpu = smp_processor_id();
+	cpu = task_cpu(p);
+
+#ifdef CONFIG_SMP
+	if (cpu == this_cpu)
+		goto out_activate;
+
+	if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)
+		     || task_running(rq, p)
+		     || cpu_is_offline(this_cpu)))
+		goto out_activate;
+
+	/* Passive load balancing */
+	load = get_low_cpu_load(cpu, 1);
+	this_load = get_high_cpu_load(this_cpu, 1) + SCHED_LOAD_SCALE;
+	if (load > this_load) {
+		new_cpu = sched_balance_wake(this_cpu, p);
+		set_task_cpu(p, new_cpu);
+		goto repeat_lock_task;
+	}
+
+	this_rq = this_rq();
+	now = sched_clock();
+	sd = cpu_sched_domain(this_cpu);
+
+	/*
+	 * Fast-migrate the task if it's not running or
+	 * runnable currently. Do not violate hard affinity.
+	 */
+	do {
+		if (!(sd->flags & SD_FLAG_FASTMIGRATE))
+			break;
+		if (now - p->timestamp < sd->cache_hot_time)
+			break;
+
+		if (cpu_isset(cpu, sd->span)) {
+			new_cpu = sched_balance_wake(this_cpu, p);
+			set_task_cpu(p, new_cpu);
+			goto repeat_lock_task;
 		}
-		p->state = TASK_RUNNING;
+		sd = sd->parent;
+	} while (sd);
+
+	new_cpu = sched_balance_wake(cpu, p);
+	if (new_cpu != cpu) {
+		set_task_cpu(p, new_cpu);
+		goto repeat_lock_task;
+	}
+	goto out_activate;
+
+	if ((p->flags & PF_FUTEX_DEBUG)
+	    && !(current->flags & PF_FUTEX_DEBUG)) {
+		printk("%s %i waking %s: %i %i\n",
+		       current->comm, (int)in_interrupt(),
+		       p->comm, p->tgid, p->pid);
+		WARN_ON(1);
 	}
+
+repeat_lock_task:
+	task_rq_unlock(rq, &flags);
+	rq = task_rq_lock(p, &flags);
+	old_state = p->state;
+	if (!(old_state & state))
+		goto out;
+
+	if (p->array)
+		goto out_running;
+
+	this_cpu = smp_processor_id();
+	cpu = task_cpu(p);
+
+out_activate:
+#endif /* CONFIG_SMP */
+	if (old_state == TASK_UNINTERRUPTIBLE) {
+		rq->nr_uninterruptible--;
+		/*
+		 * Tasks on involuntary sleep don't earn
+		 * sleep_avg beyond just interactive state.
+		 */
+		p->activated = -1;
+	}
+
+	if (sync && cpu == this_cpu) {
+		__activate_task(p, rq);
+	} else {
+		activate_task(p, rq);
+		if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	success = 1;
+
+out_running:
+	p->state = TASK_RUNNING;
+out:
 	task_rq_unlock(rq, &flags);
 
 	return success;
@@ -753,8 +868,8 @@
 	p->timestamp = sched_clock();
 	if (!current->time_slice) {
 		/*
-	 	 * This case is rare, it happens when the parent has only
-	 	 * a single jiffy left from its timeslice. Taking the
+		 * This case is rare, it happens when the parent has only
+		 * a single jiffy left from its timeslice. Taking the
 		 * runqueue lock is not a problem.
 		 */
 		current->time_slice = 1;
@@ -870,7 +985,7 @@
 	 * still held, otherwise prev could be scheduled on another cpu, die
 	 * there before we look at prev->state, and then the reference would
 	 * be dropped twice.
-	 * 		Manfred Spraul <manfred@colorfullife.com>
+	 *		Manfred Spraul <manfred@colorfullife.com>
 	 */
 	prev_task_flags = prev->flags;
 	finish_arch_switch(rq, prev);
@@ -932,7 +1047,7 @@
 {
 	unsigned long i, sum = 0;
 
-	for (i = 0; i < NR_CPUS; i++)
+	for_each_cpu(i)
 		sum += cpu_rq(i)->nr_running;
 
 	return sum;
@@ -1002,40 +1117,44 @@
 		spin_unlock(&rq2->lock);
 }
 
+enum idle_type
+{
+	IDLE,
+	NOT_IDLE,
+	NEWLY_IDLE,
+};
+
+#ifdef CONFIG_SMP
+
 #ifdef CONFIG_NUMA
 /*
- * If dest_cpu is allowed for this process, migrate the task to it.
- * This is accomplished by forcing the cpu_allowed mask to only
- * allow dest_cpu, which will force the cpu onto dest_cpu.  Then
- * the cpu_allowed mask is restored.
+ * If dest_cpu is allowed for this process, migrate us to it.
  */
-static void sched_migrate_task(task_t *p, int dest_cpu)
+void migrate_to_cpu(int dest_cpu)
 {
 	runqueue_t *rq;
 	migration_req_t req;
 	unsigned long flags;
-	cpumask_t old_mask, new_mask = cpumask_of_cpu(dest_cpu);
 
-	rq = task_rq_lock(p, &flags);
-	old_mask = p->cpus_allowed;
-	if (!cpu_isset(dest_cpu, old_mask) || !cpu_online(dest_cpu))
+	rq = task_rq_lock(current, &flags);
+	if (!cpu_isset(dest_cpu, current->cpus_allowed))
 		goto out;
 
 	/* force the process onto the specified CPU */
-	if (__set_cpus_allowed(p, new_mask, &req)) {
+	if (migrate_task(current, dest_cpu, &req)) {
 		/* Need to wait for migration thread. */
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
 		wait_for_completion(&req.done);
 
-		/* If we raced with sys_sched_setaffinity, don't
-		 * restore mask. */
-		rq = task_rq_lock(p, &flags);
-		if (likely(cpus_equal(p->cpus_allowed, new_mask))) {
-			/* Restore old mask: won't need migration
-			 * thread, since current cpu is allowed. */
-			BUG_ON(__set_cpus_allowed(p, old_mask, NULL));
-		}
+		/*
+		 * we want a new context here. This eliminates TLB
+		 * flushes on the cpus where the process executed prior to
+		 * the migration.
+		 */
+		tlb_migrate_prepare(current->mm);
+
+		return;
 	}
 out:
 	task_rq_unlock(rq, &flags);
@@ -1045,215 +1164,82 @@
  * Find the least loaded CPU.  Slightly favor the current CPU by
  * setting its runqueue length as the minimum to start.
  */
-static int sched_best_cpu(struct task_struct *p)
+static int sched_best_cpu(struct task_struct *p, struct sched_domain *domain)
 {
-	int i, minload, load, best_cpu, node = 0;
-	cpumask_t cpumask;
-
-	best_cpu = task_cpu(p);
-	if (cpu_rq(best_cpu)->nr_running <= 2)
-		return best_cpu;
+	int i, min_load, this_cpu, best_cpu;
 
-	minload = 10000000;
-	for_each_node_with_cpus(i) {
-		/*
-		 * Node load is always divided by nr_cpus_node to normalise
-		 * load values in case cpu count differs from node to node.
-		 * We first multiply node_nr_running by 10 to get a little
-		 * better resolution.
-		 */
-		load = 10 * atomic_read(&node_nr_running[i]) / nr_cpus_node(i);
-		if (load < minload) {
-			minload = load;
-			node = i;
-		}
-	}
+	best_cpu = this_cpu = task_cpu(p);
+	min_load = INT_MAX;
 
-	minload = 10000000;
-	cpumask = node_to_cpumask(node);
-	for (i = 0; i < NR_CPUS; ++i) {
-		if (!cpu_isset(i, cpumask))
+	for_each_online_cpu(i) {
+		unsigned long load;
+		if (!cpu_isset(i, domain->span))
 			continue;
-		if (cpu_rq(i)->nr_running < minload) {
+
+		if (i == this_cpu)
+			load = get_low_cpu_load(i, 0);
+		else
+			load = get_high_cpu_load(i, 0) + SCHED_LOAD_SCALE;
+
+		if (min_load > load) {
 			best_cpu = i;
-			minload = cpu_rq(i)->nr_running;
+			min_load = load;
 		}
+
 	}
 	return best_cpu;
 }
 
 void sched_balance_exec(void)
 {
+	struct sched_domain *domain = this_sched_domain();
 	int new_cpu;
+	int this_cpu = smp_processor_id();
+	if (numnodes == 1)
+		return;
 
-	if (numnodes > 1) {
-		new_cpu = sched_best_cpu(current);
-		if (new_cpu != smp_processor_id())
-			sched_migrate_task(current, new_cpu);
-	}
-}
+	if (this_rq()->nr_running <= 1)
+		return;
 
-/*
- * Find the busiest node. All previous node loads contribute with a
- * geometrically deccaying weight to the load measure:
- *      load_{t} = load_{t-1}/2 + nr_node_running_{t}
- * This way sudden load peaks are flattened out a bit.
- * Node load is divided by nr_cpus_node() in order to compare nodes
- * of different cpu count but also [first] multiplied by 10 to
- * provide better resolution.
- */
-static int find_busiest_node(int this_node)
-{
-	int i, node = -1, load, this_load, maxload;
-
-	if (!nr_cpus_node(this_node))
-		return node;
-	this_load = maxload = (this_rq()->prev_node_load[this_node] >> 1)
-		+ (10 * atomic_read(&node_nr_running[this_node])
-		/ nr_cpus_node(this_node));
-	this_rq()->prev_node_load[this_node] = this_load;
-	for_each_node_with_cpus(i) {
-		if (i == this_node)
-			continue;
-		load = (this_rq()->prev_node_load[i] >> 1)
-			+ (10 * atomic_read(&node_nr_running[i])
-			/ nr_cpus_node(i));
-		this_rq()->prev_node_load[i] = load;
-		if (load > maxload && (100*load > NODE_THRESHOLD*this_load)) {
-			maxload = load;
-			node = i;
-		}
+	while (domain->parent && !(domain->flags & SD_FLAG_EXEC))
+		domain = domain->parent;
+
+	if (domain->flags & SD_FLAG_EXEC) {
+		new_cpu = sched_best_cpu(current, domain);
+		if (new_cpu != this_cpu)
+			migrate_to_cpu(new_cpu);
 	}
-	return node;
 }
-
 #endif /* CONFIG_NUMA */
 
-#ifdef CONFIG_SMP
-
 /*
- * double_lock_balance - lock the busiest runqueue
- *
- * this_rq is locked already. Recalculate nr_running if we have to
- * drop the runqueue lock.
+ * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
  */
-static inline
-unsigned int double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest,
-				 int this_cpu, int idle,
-				 unsigned int nr_running)
+static inline void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
 {
 	if (unlikely(!spin_trylock(&busiest->lock))) {
 		if (busiest < this_rq) {
 			spin_unlock(&this_rq->lock);
 			spin_lock(&busiest->lock);
 			spin_lock(&this_rq->lock);
-			/* Need to recalculate nr_running */
-			if (idle || (this_rq->nr_running >
-					this_rq->prev_cpu_load[this_cpu]))
-				nr_running = this_rq->nr_running;
-			else
-				nr_running = this_rq->prev_cpu_load[this_cpu];
 		} else
 			spin_lock(&busiest->lock);
 	}
-	return nr_running;
-}
-
-/*
- * find_busiest_queue - find the busiest runqueue among the cpus in cpumask.
- */
-static inline
-runqueue_t *find_busiest_queue(runqueue_t *this_rq, int this_cpu, int idle,
-			       int *imbalance, cpumask_t cpumask)
-{
-	int nr_running, load, max_load, i;
-	runqueue_t *busiest, *rq_src;
-
-	/*
-	 * We search all runqueues to find the most busy one.
-	 * We do this lockless to reduce cache-bouncing overhead,
-	 * we re-check the 'best' source CPU later on again, with
-	 * the lock held.
-	 *
-	 * We fend off statistical fluctuations in runqueue lengths by
-	 * saving the runqueue length (as seen by the balancing CPU) during
-	 * the previous load-balancing operation and using the smaller one
-	 * of the current and saved lengths. If a runqueue is long enough
-	 * for a longer amount of time then we recognize it and pull tasks
-	 * from it.
-	 *
-	 * The 'current runqueue length' is a statistical maximum variable,
-	 * for that one we take the longer one - to avoid fluctuations in
-	 * the other direction. So for a load-balance to happen it needs
-	 * stable long runqueue on the target CPU and stable short runqueue
-	 * on the local runqueue.
-	 *
-	 * We make an exception if this CPU is about to become idle - in
-	 * that case we are less picky about moving a task across CPUs and
-	 * take what can be taken.
-	 */
-	if (idle || (this_rq->nr_running > this_rq->prev_cpu_load[this_cpu]))
-		nr_running = this_rq->nr_running;
-	else
-		nr_running = this_rq->prev_cpu_load[this_cpu];
-
-	busiest = NULL;
-	max_load = 1;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!cpu_isset(i, cpumask))
-			continue;
-
-		rq_src = cpu_rq(i);
-		if (idle || (rq_src->nr_running < this_rq->prev_cpu_load[i]))
-			load = rq_src->nr_running;
-		else
-			load = this_rq->prev_cpu_load[i];
-		this_rq->prev_cpu_load[i] = rq_src->nr_running;
-
-		if ((load > max_load) && (rq_src != this_rq)) {
-			busiest = rq_src;
-			max_load = load;
-		}
-	}
-
-	if (likely(!busiest))
-		goto out;
-
-	*imbalance = max_load - nr_running;
-
-	/* It needs an at least ~25% imbalance to trigger balancing. */
-	if (!idle && ((*imbalance)*4 < max_load)) {
-		busiest = NULL;
-		goto out;
-	}
-
-	nr_running = double_lock_balance(this_rq, busiest, this_cpu,
-					 idle, nr_running);
-	/*
-	 * Make sure nothing changed since we checked the
-	 * runqueue length.
-	 */
-	if (busiest->nr_running <= nr_running) {
-		spin_unlock(&busiest->lock);
-		busiest = NULL;
-	}
-out:
-	return busiest;
 }
 
 /*
  * pull_task - move a task from a remote runqueue to the local runqueue.
  * Both runqueues must be locked.
  */
-static inline
-void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
-	       runqueue_t *this_rq, int this_cpu)
+static inline void pull_task(runqueue_t *src_rq, prio_array_t *src_array,
+		task_t *p, runqueue_t *this_rq, prio_array_t *this_array,
+		int this_cpu)
 {
 	dequeue_task(p, src_array);
 	nr_running_dec(src_rq);
 	set_task_cpu(p, this_cpu);
 	nr_running_inc(this_rq);
-	enqueue_task(p, this_rq->active);
+	enqueue_task(p, this_array);
 	p->timestamp = sched_clock() -
 				(src_rq->timestamp_last_tick - p->timestamp);
 	/*
@@ -1261,69 +1247,71 @@
 	 * to be always true for them.
 	 */
 	if (TASK_PREEMPTS_CURR(p, this_rq))
-		set_need_resched();
+		resched_task(this_rq->curr);
 }
 
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
  */
 static inline
-int can_migrate_task(task_t *tsk, runqueue_t *rq, int this_cpu, int idle)
+int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
+		struct sched_domain *domain, enum idle_type idle)
 {
-	unsigned long delta = rq->timestamp_last_tick - tsk->timestamp;
-
 	/*
 	 * We do not migrate tasks that are:
 	 * 1) running (obviously), or
 	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
 	 * 3) are cache-hot on their current CPU.
 	 */
-	if (task_running(rq, tsk))
-		return 0;
-	if (!cpu_isset(this_cpu, tsk->cpus_allowed))
+	if (task_running(rq, p))
 		return 0;
-	if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks)))
+	if (!cpu_isset(this_cpu, p->cpus_allowed))
 		return 0;
+
+	/* Aggressive migration if we've failed balancing */
+	if (idle == NEWLY_IDLE ||
+			domain->nr_balance_failed < domain->cache_nice_tries) {
+		if ((rq->timestamp_last_tick - p->timestamp)
+						< domain->cache_hot_time)
+			return 0;
+	}
+
 	return 1;
 }
 
 /*
- * Current runqueue is empty, or rebalance tick: if there is an
- * inbalance (current runqueue is too short) then pull from
- * busiest runqueue(s).
- *
- * We call this with the current runqueue locked,
- * irqs disabled.
- */
-static void load_balance(runqueue_t *this_rq, int idle, cpumask_t cpumask)
+ * move_tasks tries to move up to max_nr_move tasks from busiest to this_rq,
+ * as part of a balancing operation within "domain". Returns the number of
+ * tasks moved.
+ *
+ * Called with both runqueues locked.
+ */
+static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
+			unsigned long max_nr_move, struct sched_domain *domain,
+			enum idle_type idle)
 {
-	int imbalance, idx, this_cpu = smp_processor_id();
-	runqueue_t *busiest;
-	prio_array_t *array;
+	int idx;
+	int pulled = 0;
+	prio_array_t *array, *dst_array;
 	struct list_head *head, *curr;
 	task_t *tmp;
 
-	busiest = find_busiest_queue(this_rq, this_cpu, idle,
-				     &imbalance, cpumask);
-	if (!busiest)
+	if (max_nr_move <= 0 || busiest->nr_running <= 1)
 		goto out;
 
 	/*
-	 * We only want to steal a number of tasks equal to 1/2 the imbalance,
-	 * otherwise we'll just shift the imbalance to the new queue:
-	 */
-	imbalance /= 2;
-
-	/*
 	 * We first consider expired tasks. Those will likely not be
 	 * executed in the near future, and they are most likely to
 	 * be cache-cold, thus switching CPUs has the least effect
 	 * on them.
 	 */
-	if (busiest->expired->nr_active)
+	if (busiest->expired->nr_active) {
 		array = busiest->expired;
-	else
+		dst_array = this_rq->expired;
+	} else {
 		array = busiest->active;
+		dst_array = this_rq->active;
+	}
 
 new_array:
 	/* Start searching at priority 0: */
@@ -1336,9 +1324,10 @@
 	if (idx >= MAX_PRIO) {
 		if (array == busiest->expired) {
 			array = busiest->active;
+			dst_array = this_rq->active;
 			goto new_array;
 		}
-		goto out_unlock;
+		goto out;
 	}
 
 	head = array->queue + idx;
@@ -1348,100 +1337,449 @@
 
 	curr = curr->prev;
 
-	if (!can_migrate_task(tmp, busiest, this_cpu, idle)) {
+	if (!can_migrate_task(tmp, busiest, this_cpu, domain, idle)) {
 		if (curr != head)
 			goto skip_queue;
 		idx++;
 		goto skip_bitmap;
 	}
-	pull_task(busiest, array, tmp, this_rq, this_cpu);
+	pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
+	pulled++;
 
-	/* Only migrate one task if we are idle */
-	if (!idle && --imbalance) {
+	/* We only want to steal up to the prescribed number of tasks. */
+	if (pulled < max_nr_move) {
 		if (curr != head)
 			goto skip_queue;
 		idx++;
 		goto skip_bitmap;
 	}
-out_unlock:
-	spin_unlock(&busiest->lock);
 out:
-	;
+	return pulled;
 }
 
 /*
- * One of the idle_cpu_tick() and busy_cpu_tick() functions will
- * get called every timer tick, on every CPU. Our balancing action
- * frequency and balancing agressivity depends on whether the CPU is
- * idle or not.
+ * find_busiest_group finds and returns the busiest CPU group within the
+ * domain. It calculates and returns the number of tasks which should be
+ * moved to restore balance via the imbalance parameter.
+ */
+static struct sched_group *
+find_busiest_group(struct sched_domain *domain, int this_cpu,
+				unsigned long *imbalance, enum idle_type idle)
+{
+	unsigned long max_load, avg_load, total_load, this_load;
+	int modify, total_nr_cpus, busiest_nr_cpus, this_nr_cpus;
+	enum idle_type package_idle = IDLE;
+	struct sched_group *busiest = NULL, *group = domain->groups;
+
+	max_load = 0;
+	this_load = 0;
+	total_load = 0;
+	total_nr_cpus = 0;
+	busiest_nr_cpus = 0;
+	this_nr_cpus = 0;
+
+	if (group == NULL)
+		goto out_balanced;
+
+	/*
+	 * Don't modify when we newly become idle because that ruins our
+	 * statistics: its triggered by some value of nr_running (ie. 0).
+	 * Timer based balancing is a good statistic though.
+	 */
+	if (idle == NEWLY_IDLE)
+		modify = 0;
+	else
+		modify = 1;
+
+	do {
+		unsigned long load;
+		int local_group;
+		int i, nr_cpus = 0;
+
+		local_group = cpu_isset(this_cpu, group->cpumask);
+
+		/* Tally up the load of all CPUs in the group */
+		avg_load = 0;
+		for_each_cpu_mask(i, group->cpumask) {
+			if (!cpu_online(i))
+				continue;
+
+			/* Bias balancing toward cpus of our domain */
+			if (local_group) {
+				load = get_high_cpu_load(i, modify);
+				if (!idle_cpu(i))
+					package_idle = NOT_IDLE;
+			} else
+				load = get_low_cpu_load(i, modify);
+
+			nr_cpus++;
+			avg_load += load;
+		}
+
+		if (!nr_cpus)
+			goto nextgroup;
+
+		total_load += avg_load;
+
+		/*
+		 * Load is cumulative over SD_FLAG_IDLE domains, but
+		 * spread over !SD_FLAG_IDLE domains. For example, 2
+		 * processes running on an SMT CPU puts a load of 2 on
+		 * that CPU, however 2 processes running on 2 CPUs puts
+		 * a load of 1 on that domain.
+		 *
+		 * This should be configurable so as SMT siblings become
+		 * more powerful, they can "spread" more load - for example,
+		 * the above case might only count as a load of 1.7.
+		 */
+		if (!(domain->flags & SD_FLAG_IDLE)) {
+			avg_load /= nr_cpus;
+			total_nr_cpus += nr_cpus;
+		} else
+			total_nr_cpus++;
+
+		if (avg_load > max_load)
+			max_load = avg_load;
+
+		if (local_group) {
+			this_load = avg_load;
+			this_nr_cpus = nr_cpus;
+		} else if (avg_load >= max_load) {
+			busiest = group;
+			busiest_nr_cpus = nr_cpus;
+		}
+nextgroup:
+		group = group->next;
+	} while (group != domain->groups);
+
+	if (!busiest)
+		goto out_balanced;
+
+	avg_load = total_load / total_nr_cpus;
+
+	if (this_load >= avg_load)
+		goto out_balanced;
+
+	if (idle == NOT_IDLE && 100*max_load <= domain->imbalance_pct*this_load)
+		goto out_balanced;
+
+	/*
+	 * We're trying to get all the cpus to the average_load, so we don't
+	 * want to push ourselves above the average load, nor do we wish to
+	 * reduce the max loaded cpu below the average load, as either of these
+	 * actions would just result in more rebalancing later, and ping-pong
+	 * tasks around. Thus we look for the minimum possible imbalance.
+	 * Negative imbalances (*we* are more loaded than anyone else) will
+	 * be counted as no imbalance for these purposes -- we can't fix that
+	 * by pulling tasks to us.  Be careful of negative numbers as they'll
+	 * appear as very large values with unsigned longs.
+	 */
+	*imbalance = (min(max_load - avg_load, avg_load - this_load) + 1) / 2;
+	/* Get rid of the scaling factor, rounding *up* as we divide */
+	*imbalance = (*imbalance + SCHED_LOAD_SCALE/2 + 1)
+					>> SCHED_LOAD_SHIFT;
+
+	if (*imbalance == 0)
+		goto out_balanced;
+
+	/* How many tasks to actually move to equalise the imbalance */
+	*imbalance *= min(busiest_nr_cpus, this_nr_cpus);
+
+	return busiest;
+
+out_balanced:
+	*imbalance = 0;
+	return NULL;
+}
+
+/*
+ * find_busiest_queue - find the busiest runqueue among the cpus in group.
+ */
+static runqueue_t *find_busiest_queue(struct sched_group *group)
+{
+	int i;
+	unsigned long max_load = 0;
+	runqueue_t *busiest = NULL;
+
+	for_each_cpu_mask(i, group->cpumask) {
+		unsigned long load;
+
+		if (!cpu_online(i))
+			continue;
+
+		load = get_low_cpu_load(i, 0);
+
+		if (load >= max_load) {
+			max_load = load;
+			busiest = cpu_rq(i);
+		}
+	}
+
+	return busiest;
+}
+
+/*
+ * Check this_cpu to ensure it is balanced within domain. Attempt to move
+ * tasks if there is an imbalance.
  *
- * busy-rebalance every 200 msecs. idle-rebalance every 1 msec. (or on
- * systems with HZ=100, every 10 msecs.)
+ * Called with this_rq unlocked.
+ */
+static int load_balance(int this_cpu, runqueue_t *this_rq,
+			struct sched_domain *domain, enum idle_type idle)
+{
+	struct sched_group *group;
+	runqueue_t *busiest = NULL;
+	unsigned long imbalance;
+	int balanced = 0, failed = 0;
+	int nr_moved = 0;
+
+	spin_lock(&this_rq->lock);
+
+	group = find_busiest_group(domain, this_cpu, &imbalance, idle);
+	if (!group) {
+		balanced = 1;
+		goto out;
+	}
+
+	busiest = find_busiest_queue(group);
+	if (!busiest || busiest == this_rq) {
+		balanced = 1;
+		goto out;
+	}
+
+	/* Attempt to move tasks */
+	double_lock_balance(this_rq, busiest);
+
+	nr_moved = move_tasks(this_rq, this_cpu, busiest,
+					imbalance, domain, idle);
+	spin_unlock(&busiest->lock);
+out:
+	spin_unlock(&this_rq->lock);
+
+	if (!balanced && nr_moved == 0)
+		failed = 1;
+
+	if (domain->flags & SD_FLAG_IDLE && failed && busiest &&
+	   		domain->nr_balance_failed > domain->cache_nice_tries) {
+		int i;
+		for_each_cpu_mask(i, group->cpumask) {
+			int wake = 0;
+
+			if (!cpu_online(i))
+				continue;
+
+			busiest = cpu_rq(i);
+			spin_lock(&busiest->lock);
+			if (!busiest->active_balance) {
+				busiest->active_balance = 1;
+				busiest->push_cpu = this_cpu;
+				wake = 1;
+			}
+			spin_unlock(&busiest->lock);
+			if (wake)
+				wake_up_process(busiest->migration_thread);
+		}
+	}
+
+	if (failed)
+		domain->nr_balance_failed++;
+	else
+		domain->nr_balance_failed = 0;
+
+	if (balanced) {
+		if (domain->balance_interval < domain->max_interval)
+			domain->balance_interval *= 2;
+	} else {
+		domain->balance_interval = domain->min_interval;
+	}
+
+	return nr_moved;
+}
+
+/*
+ * Check this_cpu to ensure it is balanced within domain. Attempt to move
+ * tasks if there is an imbalance.
  *
- * On NUMA, do a node-rebalance every 400 msecs.
+ * Called from schedule when this_rq is about to become idle (NEWLY_IDLE).
+ * this_rq is locked.
  */
-#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
-#define BUSY_REBALANCE_TICK (HZ/5 ?: 1)
-#define IDLE_NODE_REBALANCE_TICK (IDLE_REBALANCE_TICK * 5)
-#define BUSY_NODE_REBALANCE_TICK (BUSY_REBALANCE_TICK * 2)
+static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
+			struct sched_domain *domain)
+{
+	struct sched_group *group;
+	runqueue_t *busiest = NULL;
+	unsigned long imbalance;
+	int nr_moved = 0;
 
-#ifdef CONFIG_NUMA
-static void balance_node(runqueue_t *this_rq, int idle, int this_cpu)
+	group = find_busiest_group(domain, this_cpu, &imbalance, NEWLY_IDLE);
+	if (!group)
+		goto out;
+
+	busiest = find_busiest_queue(group);
+	if (!busiest || busiest == this_rq)
+		goto out;
+
+	/* Attempt to move tasks */
+	double_lock_balance(this_rq, busiest);
+
+	nr_moved = move_tasks(this_rq, this_cpu, busiest,
+					imbalance, domain, NEWLY_IDLE);
+
+	spin_unlock(&busiest->lock);
+
+out:
+	return nr_moved;
+}
+
+/*
+ * idle_balance is called by schedule() if this_cpu is about to become
+ * idle. Attempts to pull tasks from other CPUs.
+ */
+static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
 {
-	int node = find_busiest_node(cpu_to_node(this_cpu));
+	struct sched_domain *domain = this_sched_domain();
 
-	if (node >= 0) {
-		cpumask_t cpumask = node_to_cpumask(node);
-		cpu_set(this_cpu, cpumask);
-		spin_lock(&this_rq->lock);
-		load_balance(this_rq, idle, cpumask);
-		spin_unlock(&this_rq->lock);
-	}
+	if (cpu_is_offline(this_cpu))
+		return;
+
+	do {
+		if (unlikely(!domain->groups))
+			/* hasn't been setup yet */
+			break;
+
+		if (domain->flags & SD_FLAG_NEWIDLE) {
+			if (load_balance_newidle(this_cpu, this_rq, domain)) {
+				/* We've pulled tasks over so stop searching */
+				break;
+			}
+		}
+
+		domain = domain->parent;
+	} while (domain);
 }
-#endif
 
-static void rebalance_tick(runqueue_t *this_rq, int idle)
+/*
+ * active_load_balance is run by migration threads. It pushes a running
+ * task off the cpu. It can be required to correctly have at least 1 task
+ * running on each physical CPU where possible, and not have a physical /
+ * logical imbalance.
+ *
+ * Called with busiest locked.
+ */
+static void active_load_balance(runqueue_t *busiest, int busiest_cpu)
 {
-#ifdef CONFIG_NUMA
-	int this_cpu = smp_processor_id();
-#endif
-	unsigned long j = jiffies;
+	int i;
+	struct sched_domain *sd = cpu_sched_domain(busiest_cpu);
+	struct sched_group *group, *busy_group;
 
-	/*
-	 * First do inter-node rebalancing, then intra-node rebalancing,
-	 * if both events happen in the same tick. The inter-node
-	 * rebalancing does not necessarily have to create a perfect
-	 * balance within the node, since we load-balance the most loaded
-	 * node with the current CPU. (ie. other CPUs in the local node
-	 * are not balanced.)
-	 */
-	if (idle) {
-#ifdef CONFIG_NUMA
-		if (!(j % IDLE_NODE_REBALANCE_TICK))
-			balance_node(this_rq, idle, this_cpu);
-#endif
-		if (!(j % IDLE_REBALANCE_TICK)) {
-			spin_lock(&this_rq->lock);
-			load_balance(this_rq, idle, cpu_to_node_mask(this_cpu));
-			spin_unlock(&this_rq->lock);
+	if (busiest->nr_running <= 1)
+		return;
+
+	/* sd->parent should never cause a NULL dereference, if it did so,
+ 	 * then push_cpu was set to a buggy value */
+	while (!cpu_isset(busiest->push_cpu, sd->span)) {
+ 		sd = sd->parent;
+		if (!sd->parent && !cpu_isset(busiest->push_cpu, sd->span)) {
+			WARN_ON(1);
+			return;
 		}
+	}
+
+	if (!sd->groups) {
+		WARN_ON(1);
 		return;
 	}
-#ifdef CONFIG_NUMA
-	if (!(j % BUSY_NODE_REBALANCE_TICK))
-		balance_node(this_rq, idle, this_cpu);
-#endif
-	if (!(j % BUSY_REBALANCE_TICK)) {
-		spin_lock(&this_rq->lock);
-		load_balance(this_rq, idle, cpu_to_node_mask(this_cpu));
-		spin_unlock(&this_rq->lock);
+
+ 	group = sd->groups;
+	while (!cpu_isset(busiest_cpu, group->cpumask)) {
+ 		group = group->next;
+		if (group == sd->groups) {
+			WARN_ON(1);
+			return;
+		}
 	}
+ 	busy_group = group;
+
+ 	group = sd->groups;
+ 	do {
+		runqueue_t *rq;
+ 		int push_cpu = 0, nr = 0;
+
+ 		if (group == busy_group)
+ 			goto next_group;
+
+ 		for_each_cpu_mask(i, group->cpumask) {
+			if (!cpu_online(i))
+				continue;
+
+			if (!idle_cpu(i))
+				goto next_group;
+ 			push_cpu = i;
+ 			nr++;
+ 		}
+ 		if (nr == 0)
+ 			goto next_group;
+
+		rq = cpu_rq(push_cpu);
+		double_lock_balance(busiest, rq);
+		move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
+		spin_unlock(&rq->lock);
+next_group:
+		group = group->next;
+	} while (group != sd->groups);
+}
+
+/*
+ * rebalance_tick will get called every timer tick, on every CPU.
+ *
+ * It checks each scheduling domain to see if it is due to be balanced,
+ * and initiates a balancing operation if so.
+ *
+ * Balancing parameters are set up in arch_init_sched_domains.
+ */
+
+/* Don't have all balancing operations going off at once */
+#define CPU_OFFSET(cpu) (HZ * cpu / NR_CPUS)
+
+static void rebalance_tick(int this_cpu, runqueue_t *this_rq, enum idle_type idle)
+{
+	unsigned long j = jiffies + CPU_OFFSET(this_cpu);
+	struct sched_domain *domain = this_sched_domain();
+
+	BUG_ON(cpu_is_offline(this_cpu) && system_running);
+
+	/* Run through all this CPU's domains */
+	do {
+		unsigned long interval;
+
+		if (unlikely(!domain->groups))
+			break;
+
+		interval = domain->balance_interval;
+		if (idle != IDLE)
+			interval *= domain->busy_factor;
+
+		/* scale ms to jiffies */
+		interval = interval * HZ / 1000;
+		if (unlikely(interval == 0))
+			interval = 1;
+
+		if (j - domain->last_balance >= interval) {
+			if (load_balance(this_cpu, this_rq, domain, idle)) {
+				/* We've pulled tasks over so no longer idle */
+				idle = NOT_IDLE;
+			}
+			domain->last_balance += interval;
+		}
+
+		domain = domain->parent;
+	} while (domain);
 }
 #else
 /*
  * on UP we do not need to balance between CPUs:
  */
-static inline void rebalance_tick(runqueue_t *this_rq, int idle)
+static inline void rebalance_tick(int this_cpu, runqueue_t *this_rq, enum idle_type idle)
 {
 }
 #endif
@@ -1499,7 +1837,7 @@
 			cpustat->iowait += sys_ticks;
 		else
 			cpustat->idle += sys_ticks;
-		rebalance_tick(rq, 1);
+		rebalance_tick(cpu, rq, IDLE);
 		return;
 	}
 	if (TASK_NICE(p) > 0)
@@ -1583,7 +1921,7 @@
 out_unlock:
 	spin_unlock(&rq->lock);
 out:
-	rebalance_tick(rq, 0);
+	rebalance_tick(cpu, rq, NOT_IDLE);
 }
 
 void scheduling_functions_start_here(void) { }
@@ -1652,7 +1990,7 @@
 
 	if (unlikely(!rq->nr_running)) {
 #ifdef CONFIG_SMP
-		load_balance(rq, 1, cpu_to_node_mask(smp_processor_id()));
+		idle_balance(smp_processor_id(), rq);
 #endif
 		if (!rq->nr_running) {
 			next = rq->idle;
@@ -1906,10 +2244,21 @@
 	__remove_wait_queue(q, &wait);			\
 	spin_unlock_irqrestore(&q->lock, flags);
 
+#define SLEEP_ON_BKLCHECK				\
+	if (unlikely(!kernel_locked()) &&		\
+	    sleep_on_bkl_warnings < 10) {		\
+		sleep_on_bkl_warnings++;		\
+		WARN_ON(1);				\
+	}
+
+static int sleep_on_bkl_warnings;
+
 void interruptible_sleep_on(wait_queue_head_t *q)
 {
 	SLEEP_ON_VAR
 
+	SLEEP_ON_BKLCHECK
+
 	current->state = TASK_INTERRUPTIBLE;
 
 	SLEEP_ON_HEAD
@@ -1923,6 +2272,8 @@
 {
 	SLEEP_ON_VAR
 
+	SLEEP_ON_BKLCHECK
+
 	current->state = TASK_INTERRUPTIBLE;
 
 	SLEEP_ON_HEAD
@@ -1938,6 +2289,8 @@
 {
 	SLEEP_ON_VAR
 
+	SLEEP_ON_BKLCHECK
+
 	current->state = TASK_UNINTERRUPTIBLE;
 
 	SLEEP_ON_HEAD
@@ -2013,6 +2366,13 @@
 
 EXPORT_SYMBOL(set_user_nice);
 
+#if defined( CONFIG_KGDB)
+struct task_struct * kgdb_get_idle(int this_cpu)
+{
+        return cpu_rq(this_cpu)->idle;
+}
+#endif
+
 #ifndef __alpha__
 
 /*
@@ -2310,11 +2670,13 @@
 	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
 		return -EFAULT;
 
+	lock_cpu_hotplug();
 	read_lock(&tasklist_lock);
 
 	p = find_process_by_pid(pid);
 	if (!p) {
 		read_unlock(&tasklist_lock);
+		unlock_cpu_hotplug();
 		return -ESRCH;
 	}
 
@@ -2335,6 +2697,7 @@
 
 out_unlock:
 	put_task_struct(p);
+	unlock_cpu_hotplug();
 	return retval;
 }
 
@@ -2364,7 +2727,7 @@
 		goto out_unlock;
 
 	retval = 0;
-	cpus_and(mask, p->cpus_allowed, cpu_online_map);
+	cpus_and(mask, p->cpus_allowed, cpu_possible_map);
 
 out_unlock:
 	read_unlock(&tasklist_lock);
@@ -2568,35 +2931,28 @@
 
 static void show_task(task_t * p)
 {
-	unsigned long free = 0;
 	task_t *relative;
-	int state;
-	static const char * stat_nam[] = { "R", "S", "D", "T", "Z", "W" };
+	unsigned state;
+	static const char *stat_nam[] = { "R", "S", "D", "T", "Z", "W" };
 
 	printk("%-13.13s ", p->comm);
 	state = p->state ? __ffs(p->state) + 1 : 0;
-	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
+	if (state < ARRAY_SIZE(stat_nam))
 		printk(stat_nam[state]);
 	else
-		printk(" ");
+		printk("?");
 #if (BITS_PER_LONG == 32)
-	if (p == current)
-		printk(" current  ");
+	if (state == TASK_RUNNING)
+		printk(" running ");
 	else
 		printk(" %08lX ", thread_saved_pc(p));
 #else
-	if (p == current)
-		printk("   current task   ");
+	if (state == TASK_RUNNING)
+		printk("  running task   ");
 	else
 		printk(" %016lx ", thread_saved_pc(p));
 #endif
-	{
-		unsigned long * n = (unsigned long *) (p->thread_info+1);
-		while (!*n)
-			n++;
-		free = (unsigned long) n - (unsigned long)(p->thread_info+1);
-	}
-	printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
+	printk("%5d %6d ", p->pid, p->parent->pid);
 	if ((relative = eldest_child(p)))
 		printk("%5d ", relative->pid);
 	else
@@ -2614,7 +2970,8 @@
 	else
 		printk(" (NOTLB)\n");
 
-	show_stack(p, NULL);
+	if (state != TASK_RUNNING)
+		show_stack(p, NULL);
 }
 
 void show_state(void)
@@ -2623,12 +2980,12 @@
 
 #if (BITS_PER_LONG == 32)
 	printk("\n"
-	       "                         free                        sibling\n");
-	printk("  task             PC    stack   pid father child younger older\n");
+	       "                                               sibling\n");
+	printk("  task             PC      pid father child younger older\n");
 #else
 	printk("\n"
-	       "                                 free                        sibling\n");
-	printk("  task                 PC        stack   pid father child younger older\n");
+	       "                                                       sibling\n");
+	printk("  task                 PC          pid father child younger older\n");
 #endif
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
@@ -2708,7 +3065,12 @@
 		goto out;
 	}
 
-	if (__set_cpus_allowed(p, new_mask, &req)) {
+	p->cpus_allowed = new_mask;
+	/* Can the task run on the task's current CPU? If so, we're done */
+	if (cpu_isset(task_cpu(p), new_mask))
+		goto out;
+
+	if (migrate_task(p, any_online_cpu(new_mask), &req)) {
 		/* Need help from migration thread: drop lock and wait. */
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
@@ -2722,8 +3084,16 @@
 
 EXPORT_SYMBOL_GPL(set_cpus_allowed);
 
-/* Move (not current) task off this cpu, onto dest cpu. */
-static void move_task_away(struct task_struct *p, int dest_cpu)
+/*
+ * Move (not current) task off this cpu, onto dest cpu.  We're doing
+ * this because either it can't run here any more (set_cpus_allowed()
+ * away from this CPU, or CPU going down), or because we're
+ * attempting to rebalance this task on exec (sched_balance_exec).
+ *
+ * So we race with normal scheduler movements, but that's OK, as long
+ * as the task is no longer on this CPU.
+ */
+static void __migrate_task(struct task_struct *p, int dest_cpu)
 {
 	runqueue_t *rq_dest;
 	unsigned long flags;
@@ -2732,14 +3102,21 @@
 
 	local_irq_save(flags);
 	double_rq_lock(this_rq(), rq_dest);
+	/* Already moved. */
 	if (task_cpu(p) != smp_processor_id())
-		goto out; /* Already moved */
+		goto out;
+	/* Affinity changed (again). */
+	if (!cpu_isset(dest_cpu, p->cpus_allowed))
+		goto out;
+	/* CPU went down. */
+	if (cpu_is_offline(dest_cpu))
+		goto out;
 
 	set_task_cpu(p, dest_cpu);
 	if (p->array) {
 		deactivate_task(p, this_rq());
 		activate_task(p, rq_dest);
-		if (p->prio < rq_dest->curr->prio)
+		if (TASK_PREEMPTS_CURR(p, rq_dest))
 			resched_task(rq_dest->curr);
 	}
 	p->timestamp = rq_dest->timestamp_last_tick;
@@ -2749,12 +3126,6 @@
 	local_irq_restore(flags);
 }
 
-typedef struct {
-	int cpu;
-	struct completion startup_done;
-	task_t *task;
-} migration_startup_t;
-
 /*
  * migration_thread - this is a highprio system thread that performs
  * thread migration by bumping thread off CPU then 'pushing' onto
@@ -2764,27 +3135,16 @@
 {
 	/* Marking "param" __user is ok, since we do a set_fs(KERNEL_DS); */
 	struct sched_param __user param = { .sched_priority = MAX_RT_PRIO-1 };
-	migration_startup_t *startup = data;
-	int cpu = startup->cpu;
 	runqueue_t *rq;
+	int cpu = (long)data;
 	int ret;
 
-	startup->task = current;
-	complete(&startup->startup_done);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule();
-
-	BUG_ON(smp_processor_id() != cpu);
-
-	daemonize("migration/%d", cpu);
-	set_fs(KERNEL_DS);
-
 	ret = setscheduler(0, SCHED_FIFO, &param);
 
-	rq = this_rq();
-	rq->migration_thread = current;
+	rq = cpu_rq(cpu);
+	BUG_ON(rq->migration_thread != current);
 
-	for (;;) {
+	while (!kthread_should_stop()) {
 		struct list_head *head;
 		migration_req_t *req;
 
@@ -2792,7 +3152,13 @@
 			refrigerator(PF_IOTHREAD);
 
 		spin_lock_irq(&rq->lock);
+		if (rq->active_balance) {
+			active_load_balance(rq, cpu);
+			rq->active_balance = 0;
+		}
+
 		head = &rq->migration_queue;
+
 		current->state = TASK_INTERRUPTIBLE;
 		if (list_empty(head)) {
 			spin_unlock_irq(&rq->lock);
@@ -2803,11 +3169,68 @@
 		list_del_init(head->next);
 		spin_unlock_irq(&rq->lock);
 
-		move_task_away(req->task,
-			       any_online_cpu(req->task->cpus_allowed));
+		__migrate_task(req->task, req->dest_cpu);
 		complete(&req->done);
 	}
+	return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* migrate_all_tasks - function to migrate all the tasks from the
+ * current cpu caller must have already scheduled this to the target
+ * cpu via set_cpus_allowed.  Machine is stopped.  */
+void migrate_all_tasks(void)
+{
+	struct task_struct *tsk, *t;
+	int dest_cpu, src_cpu;
+	unsigned int node;
+
+	/* We're nailed to this CPU. */
+	src_cpu = smp_processor_id();
+
+	/* Not required, but here for neatness. */
+	write_lock(&tasklist_lock);
+
+	/* watch out for per node tasks, let's stay on this node */
+	node = cpu_to_node(src_cpu);
+
+	do_each_thread(t, tsk) {
+		cpumask_t mask;
+		if (tsk == current)
+			continue;
+
+		if (task_cpu(tsk) != src_cpu)
+			continue;
+
+		/* Figure out where this task should go (attempting to
+		 * keep it on-node), and check if it can be migrated
+		 * as-is.  NOTE that kernel threads bound to more than
+		 * one online cpu will be migrated. */
+		mask = node_to_cpumask(node);
+		cpus_and(mask, mask, tsk->cpus_allowed);
+		dest_cpu = any_online_cpu(mask);
+		if (dest_cpu == NR_CPUS)
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+		if (dest_cpu == NR_CPUS) {
+			cpus_clear(tsk->cpus_allowed);
+			cpus_complement(tsk->cpus_allowed);
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+
+			/* Don't tell them about moving exiting tasks
+			   or kernel threads (both mm NULL), since
+			   they never leave kernel. */
+			if (tsk->mm && printk_ratelimit())
+				printk(KERN_INFO "process %d (%s) no "
+				       "longer affine to cpu%d\n",
+				       tsk->pid, tsk->comm, src_cpu);
+		}
+
+		__migrate_task(tsk, dest_cpu);
+	} while_each_thread(t, tsk);
+
+	write_unlock(&tasklist_lock);
 }
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*
  * migration_call - callback that gets triggered when a CPU is added.
@@ -2816,43 +3239,45 @@
 static int migration_call(struct notifier_block *nfb, unsigned long action,
 			  void *hcpu)
 {
-	long cpu = (long)hcpu;
-	migration_startup_t startup;
+	int cpu = (long)hcpu;
+	struct task_struct *p;
 
 	switch (action) {
+	case CPU_UP_PREPARE:
+		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
+		if (IS_ERR(p))
+			return NOTIFY_BAD;
+		kthread_bind(p, cpu);
+		cpu_rq(cpu)->migration_thread = p;
+		break;
 	case CPU_ONLINE:
-
-		printk("Starting migration thread for cpu %li\n", cpu);
-
-		startup.cpu = cpu;
-		startup.task = NULL;
-		init_completion(&startup.startup_done);
-
-		kernel_thread(migration_thread, &startup, CLONE_KERNEL);
-		wait_for_completion(&startup.startup_done);
-		wait_task_inactive(startup.task);
-
-		startup.task->thread_info->cpu = cpu;
-		startup.task->cpus_allowed = cpumask_of_cpu(cpu);
-
-		wake_up_process(startup.task);
-
-		while (!cpu_rq(cpu)->migration_thread)
-			yield();
-
+		/* Strictly unneccessary, as first user will wake it. */
+		wake_up_process(cpu_rq(cpu)->migration_thread);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind it from offline cpu so it can run.  Fall thru. */
+		kthread_bind(cpu_rq(cpu)->migration_thread,smp_processor_id());
+	case CPU_DEAD:
+		kthread_stop(cpu_rq(cpu)->migration_thread);
+		cpu_rq(cpu)->migration_thread = NULL;
+ 		BUG_ON(cpu_rq(cpu)->nr_running != 0);
+ 		break;
+#endif
 	}
 	return NOTIFY_OK;
 }
 
-static struct notifier_block migration_notifier
-			= { .notifier_call = &migration_call };
+static struct notifier_block __devinitdata migration_notifier = {
+	.notifier_call = migration_call,
+};
 
-__init int migration_init(void)
+int __init migration_init(void)
 {
+	void *cpu = (void *)(long)smp_processor_id();
 	/* Start one for boot CPU. */
-	migration_call(&migration_notifier, CPU_ONLINE,
-		       (void *)(long)smp_processor_id());
+	migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
+	migration_call(&migration_notifier, CPU_ONLINE, cpu);
 	register_cpu_notifier(&migration_notifier);
 	return 0;
 }
@@ -2874,47 +3299,219 @@
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 EXPORT_SYMBOL(kernel_flag);
 
-static void kstat_init_cpu(int cpu)
+#ifdef CONFIG_SMP
+#ifdef ARCH_HAS_SCHED_DOMAIN
+extern void __init arch_init_sched_domains(void);
+#else
+static struct sched_group sched_group_cpus[NR_CPUS];
+#ifdef CONFIG_NUMA
+static struct sched_group sched_group_nodes[MAX_NUMNODES];
+DEFINE_PER_CPU(struct sched_domain, node_domains);
+static void __init arch_init_sched_domains(void)
 {
-	/* Add any initialisation to kstat here */
-	/* Useful when cpu offlining logic is added.. */
+	int i;
+	struct sched_group *first_node = NULL, *last_node = NULL;
+
+	/* Set up domains */
+	for_each_cpu_mask(i, cpu_online_map) {
+		int node = cpu_to_node(i);
+		cpumask_t nodemask = node_to_cpumask(node);
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		*node_domain = SD_NODE_INIT;
+		node_domain->span = cpu_online_map;
+
+		*cpu_domain = SD_CPU_INIT;
+		cpus_and(cpu_domain->span, nodemask, cpu_online_map);
+		cpu_domain->parent = node_domain;
+	}
+
+	/* Set up groups */
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+		int j;
+		cpumask_t nodemask;
+		struct sched_group *node = &sched_group_nodes[i];
+		cpumask_t tmp = node_to_cpumask(i);
+
+		cpus_and(nodemask, tmp, cpu_online_map);
+
+		if (cpus_empty(nodemask))
+			continue;
+
+		node->cpumask = nodemask;
+
+		for_each_cpu_mask(j, node->cpumask) {
+			struct sched_group *cpu = &sched_group_cpus[j];
+
+			cpus_clear(cpu->cpumask);
+			cpu_set(j, cpu->cpumask);
+
+			if (!first_cpu)
+				first_cpu = cpu;
+			if (last_cpu)
+				last_cpu->next = cpu;
+			last_cpu = cpu;
+		}
+		last_cpu->next = first_cpu;
+
+		if (!first_node)
+			first_node = node;
+		if (last_node)
+			last_node->next = node;
+		last_node = node;
+	}
+	last_node->next = first_node;
+
+	mb();
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *node_domain = &per_cpu(node_domains, i);
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		node_domain->groups = &sched_group_nodes[cpu_to_node(i)];
+		cpu_domain->groups = &sched_group_cpus[i];
+	}
 }
 
-static int __devinit kstat_cpu_notify(struct notifier_block *self,
-				      unsigned long action, void *hcpu)
+#else /* CONFIG_NUMA */
+static void __init arch_init_sched_domains(void)
 {
-	int cpu = (unsigned long)hcpu;
-	switch(action) {
-	case CPU_UP_PREPARE:
-		kstat_init_cpu(cpu);
-		break;
-	default:
-		break;
+	int i;
+	struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+
+	/* Set up domains */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		*cpu_domain = SD_CPU_INIT;
+		cpu_domain->span = cpu_online_map;
+	}
+
+	/* Set up CPU groups */
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_group *cpu = &sched_group_cpus[i];
+
+		cpus_clear(cpu->cpumask);
+		cpu_set(i, cpu->cpumask);
+
+		if (!first_cpu)
+			first_cpu = cpu;
+		if (last_cpu)
+			last_cpu->next = cpu;
+		last_cpu = cpu;
+	}
+	last_cpu->next = first_cpu;
+
+	mb();
+	for_each_cpu_mask(i, cpu_online_map) {
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+		cpu_domain->groups = &sched_group_cpus[i];
 	}
-	return NOTIFY_OK;
 }
 
-static struct notifier_block __devinitdata kstat_nb = {
-	.notifier_call	= kstat_cpu_notify,
-	.next		= NULL,
-};
+#endif /* CONFIG_NUMA */
+#endif /* ARCH_HAS_SCHED_DOMAIN */
+
+#undef SCHED_DOMAIN_DEBUG
+#ifdef SCHED_DOMAIN_DEBUG
+void sched_domain_debug(void)
+{
+	int i;
+
+	for_each_cpu(i) {
+		int level = 0;
+		struct sched_domain *cpu_domain = cpu_sched_domain(i);
+
+		printk(KERN_DEBUG "CPU%d: %s\n",
+				i, (cpu_online(i) ? " online" : "offline"));
+
+		do {
+			int j;
+			char str[NR_CPUS];
+			struct sched_group *group = cpu_domain->groups;
+			cpumask_t groupmask, tmp;
+
+			cpumask_scnprintf(str, NR_CPUS, cpu_domain->span);
+			cpus_clear(groupmask);
+
+			printk(KERN_DEBUG);
+			for (j = 0; j < level + 1; j++)
+				printk(" ");
+			printk("domain %d: span %s\n", level, str);
+
+			if (!cpu_isset(i, cpu_domain->span))
+				printk(KERN_DEBUG "ERROR domain->span does not contain CPU%d\n", i);
+			if (!cpu_isset(i, group->cpumask))
+				printk(KERN_DEBUG "ERROR domain->groups does not contain CPU%d\n", i);
+
+			printk(KERN_DEBUG);
+			for (j = 0; j < level + 2; j++)
+				printk(" ");
+			printk("groups:");
+			do {
+				if (group == NULL) {
+					printk(" ERROR: NULL");
+					break;
+				}
+
+				if (cpus_weight(group->cpumask) == 0)
+					printk(" ERROR empty group:");
+
+				cpus_and(tmp, groupmask, group->cpumask);
+				if (cpus_weight(tmp) > 0)
+					printk(" ERROR repeated CPUs:");
+
+				cpus_or(groupmask, groupmask, group->cpumask);
+
+				cpumask_scnprintf(str, NR_CPUS, group->cpumask);
+				printk(" %s", str);
 
-__init static void init_kstat(void)
+				group = group->next;
+			} while (group != cpu_domain->groups);
+			printk("\n");
+
+			if (!cpus_equal(cpu_domain->span, groupmask))
+				printk(KERN_DEBUG "ERROR groups don't span domain->span\n");
+
+			level++;
+			cpu_domain = cpu_domain->parent;
+
+			if (cpu_domain) {
+				cpus_and(tmp, groupmask, cpu_domain->span);
+				if (!cpus_equal(tmp, groupmask))
+					printk(KERN_DEBUG "ERROR parent span is not a superset of domain->span\n");
+			}
+
+		} while (cpu_domain);
+	}
+}
+#else
+#define sched_domain_debug() {}
+#endif
+
+void __init sched_init_smp(void)
 {
-	kstat_cpu_notify(&kstat_nb, (unsigned long)CPU_UP_PREPARE,
-			 (void *)(long)smp_processor_id());
-	register_cpu_notifier(&kstat_nb);
+	arch_init_sched_domains();
+	sched_domain_debug();
 }
+#else
+void __init sched_init_smp(void)
+{
+}
+#endif /* CONFIG_SMP */
 
 void __init sched_init(void)
 {
 	runqueue_t *rq;
 	int i, j, k;
 
-	/* Init the kstat counters */
-	init_kstat();
 	for (i = 0; i < NR_CPUS; i++) {
 		prio_array_t *array;
+#ifdef CONFIG_SMP
+		struct sched_domain *domain;
+		domain = cpu_sched_domain(i);
+		memset(domain, 0, sizeof(struct sched_domain));
+#endif
 
 		rq = cpu_rq(i);
 		rq->active = rq->arrays;
@@ -2924,7 +3521,6 @@
 		spin_lock_init(&rq->lock);
 		INIT_LIST_HEAD(&rq->migration_queue);
 		atomic_set(&rq->nr_iowait, 0);
-		nr_running_init(rq);
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
--- diff/kernel/signal.c	2003-11-25 15:24:59.000000000 +0000
+++ source/kernel/signal.c	2004-02-18 09:04:03.000000000 +0000
@@ -24,6 +24,7 @@
 #include <linux/binfmts.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/compat_siginfo.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/siginfo.h>
@@ -2006,6 +2007,12 @@
 	if (from->si_code < 0)
 		return __copy_to_user(to, from, sizeof(siginfo_t))
 			? -EFAULT : 0;
+
+	/* Use compat_siginfo_t with 32-bit signals */
+	if(is_compat_task(current)){
+		return compat_copy_siginfo_to_user((compat_siginfo_t __user *)to,from);
+	}
+
 	/*
 	 * If you change siginfo_t structure, please be sure
 	 * this code is fixed accordingly.
--- diff/kernel/softirq.c	2003-10-09 09:47:34.000000000 +0100
+++ source/kernel/softirq.c	2004-02-18 09:04:03.000000000 +0000
@@ -14,6 +14,7 @@
 #include <linux/notifier.h>
 #include <linux/percpu.h>
 #include <linux/cpu.h>
+#include <linux/kthread.h>
 
 /*
    - No shared variables, all the data are CPU local.
@@ -117,11 +118,22 @@
 
 void local_bh_enable(void)
 {
+	if (in_irq()) {
+		printk("local_bh_enable() was called in hard irq context.   "
+			"This is probably a bug\n");
+		dump_stack();
+	}
+
 	__local_bh_enable();
-	WARN_ON(irqs_disabled());
-	if (unlikely(!in_interrupt() &&
-		     local_softirq_pending()))
+	if (unlikely(!in_interrupt() && local_softirq_pending())) {
+		if (irqs_disabled()) {
+			printk("local_bh_enable() was called with local "
+				"interrupts disabled.  This is probably a"
+				" bug\n");
+			dump_stack();
+		}
 		invoke_softirq();
+	}
 	preempt_check_resched();
 }
 EXPORT_SYMBOL(local_bh_enable);
@@ -299,86 +311,136 @@
 
 EXPORT_SYMBOL(tasklet_kill);
 
-static void tasklet_init_cpu(int cpu)
-{
-	per_cpu(tasklet_vec, cpu).list = NULL;
-	per_cpu(tasklet_hi_vec, cpu).list = NULL;
-}
-	
-static int tasklet_cpu_notify(struct notifier_block *self, 
-				unsigned long action, void *hcpu)
-{
-	long cpu = (long)hcpu;
-	switch(action) {
-	case CPU_UP_PREPARE:
-		tasklet_init_cpu(cpu);
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-static struct notifier_block tasklet_nb = {
-	.notifier_call	= tasklet_cpu_notify,
-	.next		= NULL,
-};
-
 void __init softirq_init(void)
 {
 	open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
 	open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
-	tasklet_cpu_notify(&tasklet_nb, (unsigned long)CPU_UP_PREPARE,
-				(void *)(long)smp_processor_id());
-	register_cpu_notifier(&tasklet_nb);
 }
 
 static int ksoftirqd(void * __bind_cpu)
 {
-	int cpu = (int) (long) __bind_cpu;
-
-	daemonize("ksoftirqd/%d", cpu);
 	set_user_nice(current, 19);
 	current->flags |= PF_IOTHREAD;
 
-	/* Migrate to the right CPU */
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
-	BUG_ON(smp_processor_id() != cpu);
+	set_current_state(TASK_INTERRUPTIBLE);
 
-	__set_current_state(TASK_INTERRUPTIBLE);
-	mb();
-
-	__get_cpu_var(ksoftirqd) = current;
-
-	for (;;) {
+	while (!kthread_should_stop()) {
 		if (!local_softirq_pending())
 			schedule();
 
 		__set_current_state(TASK_RUNNING);
 
 		while (local_softirq_pending()) {
+			/* Preempt disable stops cpu going offline.
+			   If already offline, we'll be on wrong CPU:
+			   don't process */
+			preempt_disable();
+			if (cpu_is_offline((long)__bind_cpu))
+				goto wait_to_die;
 			do_softirq();
+			preempt_enable();
 			cond_resched();
 		}
 
 		__set_current_state(TASK_INTERRUPTIBLE);
 	}
+	return 0;
+
+wait_to_die:
+	preempt_enable();
+	/* Wait for kthread_stop */
+	while (!signal_pending(current)) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * tasklet_kill_immediate is called to remove a tasklet which can already be
+ * scheduled for execution on @cpu.
+ *
+ * Unlike tasklet_kill, this function removes the tasklet
+ * _immediately_, even if the tasklet is in TASKLET_STATE_SCHED state.
+ *
+ * When this function is called, @cpu must be in the CPU_DEAD state.
+ */
+void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	BUG_ON(cpu_online(cpu));
+	BUG_ON(test_bit(TASKLET_STATE_RUN, &t->state));
+
+	if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+		return;
+
+	/* CPU is dead, so no lock needed. */
+	for (i = &per_cpu(tasklet_vec, cpu).list; *i; i = &(*i)->next) {
+		if (*i == t) {
+			*i = t->next;
+			return;
+		}
+	}
+	BUG();
+}
+
+static void takeover_tasklets(unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	/* CPU is dead, so no lock needed. */
+	local_irq_disable();
+
+	/* Find end, append list for that CPU. */
+	for (i = &__get_cpu_var(tasklet_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_vec, cpu).list;
+	per_cpu(tasklet_vec, cpu).list = NULL;
+	raise_softirq_irqoff(TASKLET_SOFTIRQ);
+
+	for (i = &__get_cpu_var(tasklet_hi_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_hi_vec, cpu).list;
+	per_cpu(tasklet_hi_vec, cpu).list = NULL;
+	raise_softirq_irqoff(HI_SOFTIRQ);
+
+	local_irq_enable();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit cpu_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
 {
 	int hotcpu = (unsigned long)hcpu;
+	struct task_struct *p;
 
-	if (action == CPU_ONLINE) {
-		if (kernel_thread(ksoftirqd, hcpu, CLONE_KERNEL) < 0) {
+	switch (action) {
+	case CPU_UP_PREPARE:
+		BUG_ON(per_cpu(tasklet_vec, hotcpu).list);
+		BUG_ON(per_cpu(tasklet_hi_vec, hotcpu).list);
+		p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
+		if (IS_ERR(p)) {
 			printk("ksoftirqd for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
 		}
-
-		while (!per_cpu(ksoftirqd, hotcpu))
-			yield();
+		kthread_bind(p, hotcpu);
+  		per_cpu(ksoftirqd, hotcpu) = p;
+ 		break;
+	case CPU_ONLINE:
+		wake_up_process(per_cpu(ksoftirqd, hotcpu));
+		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind so it can run.  Fall thru. */
+		kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id());
+	case CPU_DEAD:
+		p = per_cpu(ksoftirqd, hotcpu);
+		per_cpu(ksoftirqd, hotcpu) = NULL;
+		kthread_stop(p);
+		takeover_tasklets(hotcpu);
+		break;
+#endif /* CONFIG_HOTPLUG_CPU */
  	}
 	return NOTIFY_OK;
 }
@@ -389,7 +451,9 @@
 
 __init int spawn_ksoftirqd(void)
 {
-	cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)(long)smp_processor_id());
+	void *cpu = (void *)(long)smp_processor_id();
+	cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+	cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
 	register_cpu_notifier(&cpu_nfb);
 	return 0;
 }
--- diff/kernel/sys.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/sys.c	2004-02-18 09:04:03.000000000 +0000
@@ -1089,10 +1089,178 @@
 /*
  * Supplementary group IDs
  */
-asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
+
+/* init to 2 - one for init_task, one to ensure it is never freed */
+struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
+
+struct group_info *groups_alloc(int gidsetsize)
 {
+	struct group_info *group_info;
+	int nblocks;
+	int i;
+
+	nblocks = (gidsetsize/NGROUPS_PER_BLOCK) +
+	    (gidsetsize%NGROUPS_PER_BLOCK?1:0);
+	group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *),
+	    GFP_USER);
+	if (!group_info)
+		return NULL;
+	group_info->ngroups = gidsetsize;
+	group_info->nblocks = nblocks;
+	atomic_set(&group_info->usage, 1);
+
+	if (gidsetsize <= NGROUPS_SMALL) {
+		group_info->blocks[0] = group_info->small_block;
+	} else {
+		for (i = 0; i < nblocks; i++) {
+			gid_t *b;
+			b = (void *)__get_free_page(GFP_USER);
+			if (!b)
+				goto out_undo_partial_alloc;
+			group_info->blocks[i] = b;
+		}
+	}
+	return group_info;
+
+out_undo_partial_alloc:
+	while (--i >= 0) {
+		free_page((unsigned long)group_info->blocks[i]);
+	}
+	kfree(group_info);
+	return NULL;
+}
+
+EXPORT_SYMBOL(groups_alloc);
+
+void groups_free(struct group_info *group_info)
+{
+	if (group_info->blocks[0] != group_info->small_block) {
+		int i;
+		for (i = 0; i < group_info->nblocks; i++)
+			free_page((unsigned long)group_info->blocks[i]);
+	}
+	kfree(group_info);
+}
+
+EXPORT_SYMBOL(groups_free);
+
+/* export the group_info to a user-space array */
+static int groups_to_user(gid_t __user *grouplist,
+    struct group_info *group_info)
+{
+	int i;
+	int count = group_info->ngroups;
+
+	for (i = 0; i < group_info->nblocks; i++) {
+		int cp_count = min(NGROUPS_PER_BLOCK, count);
+		int off = i * NGROUPS_PER_BLOCK;
+		int len = cp_count * sizeof(*grouplist);
+
+		if (copy_to_user(grouplist+off, group_info->blocks[i], len))
+			return -EFAULT;
+
+		count -= cp_count;
+	}
+	return 0;
+}
+
+/* fill a group_info from a user-space array - it must be allocated already */
+static int groups_from_user(struct group_info *group_info,
+    gid_t __user *grouplist)
+ {
 	int i;
-	
+	int count = group_info->ngroups;
+
+	for (i = 0; i < group_info->nblocks; i++) {
+		int cp_count = min(NGROUPS_PER_BLOCK, count);
+		int off = i * NGROUPS_PER_BLOCK;
+		int len = cp_count * sizeof(*grouplist);
+
+		if (copy_from_user(group_info->blocks[i], grouplist+off, len))
+			return -EFAULT;
+
+		count -= cp_count;
+	}
+	return 0;
+}
+
+/* a simple shell-metzner sort */
+static void groups_sort(struct group_info *group_info)
+{
+	int base, max, stride;
+	int gidsetsize = group_info->ngroups;
+
+	for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
+		; /* nothing */
+	stride /= 3;
+
+	while (stride) {
+		max = gidsetsize - stride;
+		for (base = 0; base < max; base++) {
+			int left = base;
+			int right = left + stride;
+			gid_t tmp = GROUP_AT(group_info, right);
+
+			while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
+				GROUP_AT(group_info, right) =
+				    GROUP_AT(group_info, left);
+				right = left;
+				left -= stride;
+			}
+			GROUP_AT(group_info, right) = tmp;
+		}
+		stride /= 3;
+	}
+}
+
+/* a simple bsearch */
+static int groups_search(struct group_info *group_info, gid_t grp)
+{
+	int left, right;
+
+	if (!group_info)
+		return 0;
+
+	left = 0;
+	right = group_info->ngroups;
+	while (left < right) {
+		int mid = (left+right)/2;
+		int cmp = grp - GROUP_AT(group_info, mid);
+		if (cmp > 0)
+			left = mid + 1;
+		else if (cmp < 0)
+			right = mid;
+		else
+			return 1;
+	}
+	return 0;
+}
+
+/* validate and set current->group_info */
+int set_current_groups(struct group_info *group_info)
+{
+	int retval;
+	struct group_info *old_info;
+
+	retval = security_task_setgroups(group_info);
+	if (retval)
+		return retval;
+
+	groups_sort(group_info);
+	get_group_info(group_info);
+	old_info = current->group_info;
+	current->group_info = group_info;
+	put_group_info(old_info);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(set_current_groups);
+
+asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
+{
+	int i = 0;
+
 	/*
 	 *	SMP: Nobody else can change our grouplist. Thus we are
 	 *	safe.
@@ -1100,54 +1268,52 @@
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+
+	get_group_info(current->group_info);
+	i = current->group_info->ngroups;
 	if (gidsetsize) {
-		if (i > gidsetsize)
-			return -EINVAL;
-		if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
-			return -EFAULT;
+		if (i > gidsetsize) {
+			i = -EINVAL;
+			goto out;
+		}
+		if (groups_to_user(grouplist, current->group_info)) {
+			i = -EFAULT;
+			goto out;
+		}
 	}
+out:
+	put_group_info(current->group_info);
 	return i;
 }
 
 /*
- *	SMP: Our groups are not shared. We can copy to/from them safely
+ *	SMP: Our groups are copy-on-write. We can set them safely
  *	without another task interfering.
  */
  
 asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
 {
-	gid_t groups[NGROUPS];
+	struct group_info *group_info;
 	int retval;
 
 	if (!capable(CAP_SETGID))
 		return -EPERM;
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned)gidsetsize > NGROUPS_MAX)
 		return -EINVAL;
-	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(gid_t)))
-		return -EFAULT;
-	retval = security_task_setgroups(gidsetsize, groups);
-	if (retval)
+
+	group_info = groups_alloc(gidsetsize);
+	if (!group_info)
+		return -ENOMEM;
+	retval = groups_from_user(group_info, grouplist);
+	if (retval) {
+		put_group_info(group_info);
 		return retval;
-	memcpy(current->groups, groups, gidsetsize * sizeof(gid_t));
-	current->ngroups = gidsetsize;
-	return 0;
-}
+	}
 
-static int supplemental_group_member(gid_t grp)
-{
-	int i = current->ngroups;
+	retval = set_current_groups(group_info);
+	put_group_info(group_info);
 
-	if (i) {
-		gid_t *groups = current->groups;
-		do {
-			if (*groups == grp)
-				return 1;
-			groups++;
-			i--;
-		} while (i);
-	}
-	return 0;
+	return retval;
 }
 
 /*
@@ -1156,8 +1322,11 @@
 int in_group_p(gid_t grp)
 {
 	int retval = 1;
-	if (grp != current->fsgid)
-		retval = supplemental_group_member(grp);
+	if (grp != current->fsgid) {
+		get_group_info(current->group_info);
+		retval = groups_search(current->group_info, grp);
+		put_group_info(current->group_info);
+	}
 	return retval;
 }
 
@@ -1166,8 +1335,11 @@
 int in_egroup_p(gid_t grp)
 {
 	int retval = 1;
-	if (grp != current->egid)
-		retval = supplemental_group_member(grp);
+	if (grp != current->egid) {
+		get_group_info(current->group_info);
+		retval = groups_search(current->group_info, grp);
+		put_group_info(current->group_info);
+	}
 	return retval;
 }
 
--- diff/kernel/sysctl.c	2004-02-18 08:54:13.000000000 +0000
+++ source/kernel/sysctl.c	2004-02-18 09:04:03.000000000 +0000
@@ -133,6 +133,9 @@
 static ctl_table debug_table[];
 static ctl_table dev_table[];
 extern ctl_table random_table[];
+#ifdef CONFIG_UNIX98_PTYS
+extern ctl_table pty_table[];
+#endif
 
 /* /proc declarations: */
 
@@ -518,6 +521,14 @@
 		.mode		= 0555,
 		.child		= random_table,
 	},
+#ifdef CONFIG_UNIX98_PTYS
+	{
+		.ctl_name	= KERN_PTY,
+		.procname	= "pty",
+		.mode		= 0555,
+		.child		= pty_table,
+	},
+#endif
 	{
 		.ctl_name	= KERN_OVERFLOWUID,
 		.procname	= "overflowuid",
@@ -714,6 +725,26 @@
 		.strategy	= &sysctl_intvec,
 		.extra1		= &zero,
 	},
+	{
+		.ctl_name	= VM_LAPTOP_MODE,
+		.procname	= "laptop_mode",
+		.data		= &laptop_mode,
+		.maxlen		= sizeof(laptop_mode),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+	},
+	{
+		.ctl_name	= VM_BLOCK_DUMP,
+		.procname	= "block_dump",
+		.data		= &block_dump,
+		.maxlen		= sizeof(block_dump),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+	},
 	{ .ctl_name = 0 }
 };
 
@@ -808,6 +839,22 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+	{
+		.ctl_name	= FS_AIO_NR,
+		.procname	= "aio-nr",
+		.data		= &aio_nr,
+		.maxlen		= sizeof(aio_nr),
+		.mode		= 0444,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= FS_AIO_MAX_NR,
+		.procname	= "aio-max-nr",
+		.data		= &aio_max_nr,
+		.maxlen		= sizeof(aio_max_nr),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 	{ .ctl_name = 0 }
 };
 
@@ -2008,7 +2055,7 @@
 #else /* CONFIG_SYSCTL */
 
 
-extern asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
+asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
 {
 	return -ENOSYS;
 }
--- diff/kernel/timer.c	2004-02-09 10:36:12.000000000 +0000
+++ source/kernel/timer.c	2004-02-18 09:04:03.000000000 +0000
@@ -971,6 +971,13 @@
 	wake_up_process((task_t *)__data);
 }
 
+static void futex_timeout(unsigned long __data)
+{
+	current->flags |= PF_FUTEX_DEBUG;
+	wake_up_process((task_t *)__data);
+	current->flags &= ~PF_FUTEX_DEBUG;
+}
+
 /**
  * schedule_timeout - sleep until timeout
  * @timeout: timeout value in jiffies
@@ -1037,7 +1044,10 @@
 	init_timer(&timer);
 	timer.expires = expire;
 	timer.data = (unsigned long) current;
-	timer.function = process_timeout;
+	if (current->flags & PF_FUTEX_DEBUG)
+		timer.function = futex_timeout;
+	else
+		timer.function = process_timeout;
 
 	add_timer(&timer);
 	schedule();
@@ -1223,7 +1233,73 @@
 
 	base->timer_jiffies = jiffies;
 }
-	
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
+{
+	struct timer_list *timer;
+
+	while (!list_empty(head)) {
+		timer = list_entry(head->next, struct timer_list, entry);
+		/* We're locking backwards from __mod_timer order here,
+		   beware deadlock. */
+		if (!spin_trylock(&timer->lock))
+			return 0;
+		list_del(&timer->entry);
+		internal_add_timer(new_base, timer);
+		timer->base = new_base;
+		spin_unlock(&timer->lock);
+	}
+	return 1;
+}
+
+static void __devinit migrate_timers(int cpu)
+{
+	tvec_base_t *old_base;
+	tvec_base_t *new_base;
+	int i;
+
+	BUG_ON(cpu_online(cpu));
+	old_base = &per_cpu(tvec_bases, cpu);
+	new_base = &get_cpu_var(tvec_bases);
+
+	local_irq_disable();
+again:
+	/* Prevent deadlocks via ordering by old_base < new_base. */
+	if (old_base < new_base) {
+		spin_lock(&new_base->lock);
+		spin_lock(&old_base->lock);
+	} else {
+		spin_lock(&old_base->lock);
+		spin_lock(&new_base->lock);
+	}
+
+	if (old_base->running_timer)
+		BUG();
+	for (i = 0; i < TVR_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv1.vec + i))
+			goto unlock_again;
+	for (i = 0; i < TVN_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv2.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv3.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv4.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv5.vec + i))
+			goto unlock_again;
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	local_irq_enable();
+	put_cpu_var(tvec_bases);
+	return;
+
+unlock_again:
+	/* Avoid deadlock with __mod_timer, by backing off. */
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	cpu_relax();
+	goto again;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit timer_cpu_notify(struct notifier_block *self, 
 				unsigned long action, void *hcpu)
 {
@@ -1232,6 +1308,11 @@
 	case CPU_UP_PREPARE:
 		init_timers_cpu(cpu);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		migrate_timers(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
--- diff/kernel/uid16.c	2003-10-09 09:47:17.000000000 +0100
+++ source/kernel/uid16.c	2004-02-18 09:04:03.000000000 +0000
@@ -13,21 +13,10 @@
 #include <linux/init.h>
 #include <linux/highuid.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
 
-extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
-extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
-extern asmlinkage long sys_setregid(gid_t, gid_t);
-extern asmlinkage long sys_setgid(gid_t);
-extern asmlinkage long sys_setreuid(uid_t, uid_t);
-extern asmlinkage long sys_setuid(uid_t);
-extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);
-extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);
-extern asmlinkage long sys_setfsuid(uid_t);
-extern asmlinkage long sys_setfsgid(gid_t);
- 
 asmlinkage long sys_chown16(const char * filename, old_uid_t user, old_gid_t group)
 {
 	return sys_chown(filename, low2highuid(user), low2highgid(group));
@@ -107,45 +96,83 @@
 	return sys_setfsgid((gid_t)gid);
 }
 
+static int groups16_to_user(old_gid_t __user *grouplist,
+    struct group_info *group_info)
+{
+	int i;
+	old_gid_t group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		group = (old_gid_t)GROUP_AT(group_info, i);
+		if (put_user(group, grouplist+i))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int groups16_from_user(struct group_info *group_info,
+    old_gid_t __user *grouplist)
+{
+	int i;
+	old_gid_t group;
+
+	for (i = 0; i < group_info->ngroups; i++) {
+		if (get_user(group, grouplist+i))
+			return  -EFAULT;
+		GROUP_AT(group_info, i) = (gid_t)group;
+	}
+
+	return 0;
+}
+
 asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist)
 {
-	old_gid_t groups[NGROUPS];
-	int i,j;
+	int i = 0;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+
+	get_group_info(current->group_info);
+	i = current->group_info->ngroups;
 	if (gidsetsize) {
-		if (i > gidsetsize)
-			return -EINVAL;
-		for(j=0;j<i;j++)
-			groups[j] = current->groups[j];
-		if (copy_to_user(grouplist, groups, sizeof(old_gid_t)*i))
-			return -EFAULT;
+		if (i > gidsetsize) {
+			i = -EINVAL;
+			goto out;
+		}
+		if (groups16_to_user(grouplist, current->group_info)) {
+			i = -EFAULT;
+			goto out;
+		}
 	}
+out:
+	put_group_info(current->group_info);
 	return i;
 }
 
 asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist)
 {
-	old_gid_t groups[NGROUPS];
-	gid_t new_groups[NGROUPS];
-	int i;
+	struct group_info *group_info;
+	int retval;
 
 	if (!capable(CAP_SETGID))
 		return -EPERM;
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned)gidsetsize > NGROUPS_MAX)
 		return -EINVAL;
-	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(old_gid_t)))
-		return -EFAULT;
-	for (i = 0 ; i < gidsetsize ; i++)
-		new_groups[i] = (gid_t)groups[i];
-	i = security_task_setgroups(gidsetsize, new_groups);
-	if (i)
-		return i;
-	memcpy(current->groups, new_groups, gidsetsize * sizeof(gid_t));
-	current->ngroups = gidsetsize;
-	return 0;
+
+	group_info = groups_alloc(gidsetsize);
+	if (!group_info)
+		return -ENOMEM;
+	retval = groups16_from_user(group_info, grouplist);
+	if (retval) {
+		put_group_info(group_info);
+		return retval;
+	}
+
+	retval = set_current_groups(group_info);
+	put_group_info(group_info);
+
+	return retval;
 }
 
 asmlinkage long sys_getuid16(void)
--- diff/kernel/workqueue.c	2004-02-09 10:36:12.000000000 +0000
+++ source/kernel/workqueue.c	2004-02-18 09:04:03.000000000 +0000
@@ -22,6 +22,9 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
 
 /*
  * The per-CPU workqueue.
@@ -45,7 +48,6 @@
 
 	struct workqueue_struct *wq;
 	task_t *thread;
-	struct completion exit;
 
 } ____cacheline_aligned;
 
@@ -55,8 +57,36 @@
  */
 struct workqueue_struct {
 	struct cpu_workqueue_struct cpu_wq[NR_CPUS];
+	const char *name;
+	struct list_head list;
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* All the workqueues on the system, for hotplug cpu to add/remove
+   threads to each one as cpus come/go.  Protected by cpucontrol
+   sem. */
+static LIST_HEAD(workqueues);
+#define add_workqueue(wq) list_add(&(wq)->list, &workqueues)
+#define del_workqueue(wq) list_del(&(wq)->list)
+#else
+#define add_workqueue(wq)
+#define del_workqueue(wq)
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/* Preempt must be disabled. */
+static void __queue_work(struct cpu_workqueue_struct *cwq,
+			 struct work_struct *work)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cwq->lock, flags);
+	work->wq_data = cwq;
+	list_add_tail(&work->entry, &cwq->worklist);
+	cwq->insert_sequence++;
+	wake_up(&cwq->more_work);
+	spin_unlock_irqrestore(&cwq->lock, flags);
+}
+
 /*
  * Queue work on a workqueue. Return non-zero if it was successfully
  * added.
@@ -66,19 +96,11 @@
  */
 int queue_work(struct workqueue_struct *wq, struct work_struct *work)
 {
-	unsigned long flags;
 	int ret = 0, cpu = get_cpu();
-	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
 
 	if (!test_and_set_bit(0, &work->pending)) {
 		BUG_ON(!list_empty(&work->entry));
-		work->wq_data = cwq;
-
-		spin_lock_irqsave(&cwq->lock, flags);
-		list_add_tail(&work->entry, &cwq->worklist);
-		cwq->insert_sequence++;
-		wake_up(&cwq->more_work);
-		spin_unlock_irqrestore(&cwq->lock, flags);
+		__queue_work(wq->cpu_wq + cpu, work);
 		ret = 1;
 	}
 	put_cpu();
@@ -88,39 +110,29 @@
 static void delayed_work_timer_fn(unsigned long __data)
 {
 	struct work_struct *work = (struct work_struct *)__data;
-	struct cpu_workqueue_struct *cwq = work->wq_data;
-	unsigned long flags;
+	struct workqueue_struct *wq = work->wq_data;
 
-	/*
-	 * Do the wakeup within the spinlock, so that flushing
-	 * can be done in a guaranteed way.
-	 */
-	spin_lock_irqsave(&cwq->lock, flags);
-	list_add_tail(&work->entry, &cwq->worklist);
-	cwq->insert_sequence++;
-	wake_up(&cwq->more_work);
-	spin_unlock_irqrestore(&cwq->lock, flags);
+	__queue_work(wq->cpu_wq + smp_processor_id(), work);
 }
 
 int queue_delayed_work(struct workqueue_struct *wq,
 			struct work_struct *work, unsigned long delay)
 {
-	int ret = 0, cpu = get_cpu();
+	int ret = 0;
 	struct timer_list *timer = &work->timer;
-	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
 
 	if (!test_and_set_bit(0, &work->pending)) {
 		BUG_ON(timer_pending(timer));
 		BUG_ON(!list_empty(&work->entry));
 
-		work->wq_data = cwq;
+		/* This stores wq for the moment, for the timer_fn */
+		work->wq_data = wq;
 		timer->expires = jiffies + delay;
 		timer->data = (unsigned long)work;
 		timer->function = delayed_work_timer_fn;
 		add_timer(timer);
 		ret = 1;
 	}
-	put_cpu();
 	return ret;
 }
 
@@ -153,28 +165,21 @@
 	spin_unlock_irqrestore(&cwq->lock, flags);
 }
 
-typedef struct startup_s {
-	struct cpu_workqueue_struct *cwq;
-	struct completion done;
-	const char *name;
-} startup_t;
-
-static int worker_thread(void *__startup)
+static int worker_thread(void *__cwq)
 {
-	startup_t *startup = __startup;
-	struct cpu_workqueue_struct *cwq = startup->cwq;
-	int cpu = cwq - cwq->wq->cpu_wq;
+	struct cpu_workqueue_struct *cwq = __cwq;
 	DECLARE_WAITQUEUE(wait, current);
 	struct k_sigaction sa;
+	sigset_t blocked;
 
-	daemonize("%s/%d", startup->name, cpu);
 	current->flags |= PF_IOTHREAD;
-	cwq->thread = current;
 
 	set_user_nice(current, -10);
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 
-	complete(&startup->done);
+	/* Block and flush all signals */
+	sigfillset(&blocked);
+	sigprocmask(SIG_BLOCK, &blocked, NULL);
+	flush_signals(current);
 
 	/* SIG_IGN makes children autoreap: see do_notify_parent(). */
 	sa.sa.sa_handler = SIG_IGN;
@@ -182,12 +187,10 @@
 	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
 	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
 
-	for (;;) {
+	while (!kthread_should_stop()) {
 		set_task_state(current, TASK_INTERRUPTIBLE);
 
 		add_wait_queue(&cwq->more_work, &wait);
-		if (!cwq->thread)
-			break;
 		if (list_empty(&cwq->worklist))
 			schedule();
 		else
@@ -197,9 +200,6 @@
 		if (!list_empty(&cwq->worklist))
 			run_workqueue(cwq);
 	}
-	remove_wait_queue(&cwq->more_work, &wait);
-	complete(&cwq->exit);
-
 	return 0;
 }
 
@@ -224,6 +224,7 @@
 
 	might_sleep();
 
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		DEFINE_WAIT(wait);
 		long sequence_needed;
@@ -245,15 +246,13 @@
 		finish_wait(&cwq->work_done, &wait);
 		spin_unlock_irq(&cwq->lock);
 	}
+	unlock_cpu_hotplug();
 }
 
-static int create_workqueue_thread(struct workqueue_struct *wq,
-				   const char *name,
-				   int cpu)
+static int create_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
-	startup_t startup;
 	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
-	int ret;
+	struct task_struct *p;
 
 	spin_lock_init(&cwq->lock);
 	cwq->wq = wq;
@@ -263,17 +262,13 @@
 	INIT_LIST_HEAD(&cwq->worklist);
 	init_waitqueue_head(&cwq->more_work);
 	init_waitqueue_head(&cwq->work_done);
-	init_completion(&cwq->exit);
 
-	init_completion(&startup.done);
-	startup.cwq = cwq;
-	startup.name = name;
-	ret = kernel_thread(worker_thread, &startup, CLONE_FS | CLONE_FILES);
-	if (ret >= 0) {
-		wait_for_completion(&startup.done);
-		BUG_ON(!cwq->thread);
-	}
-	return ret;
+	p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+	cwq->thread = p;
+	kthread_bind(p, cpu);
+	return 0;
 }
 
 struct workqueue_struct *create_workqueue(const char *name)
@@ -287,12 +282,19 @@
 	if (!wq)
 		return NULL;
 
+	wq->name = name;
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (!cpu_online(cpu))
 			continue;
-		if (create_workqueue_thread(wq, name, cpu) < 0)
+		if (create_workqueue_thread(wq, cpu) < 0)
 			destroy = 1;
+		else
+			wake_up_process(wq->cpu_wq[cpu].thread);
 	}
+	add_workqueue(wq);
+
 	/*
 	 * Was there any error during startup? If yes then clean up:
 	 */
@@ -300,21 +302,23 @@
 		destroy_workqueue(wq);
 		wq = NULL;
 	}
+	unlock_cpu_hotplug();
 	return wq;
 }
 
 static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq;
+	unsigned long flags;
+	struct task_struct *p;
 
 	cwq = wq->cpu_wq + cpu;
-	if (cwq->thread) {
-		/* Tell thread to exit and wait for it. */
-		cwq->thread = NULL;
-		wake_up(&cwq->more_work);
-
-		wait_for_completion(&cwq->exit);
-	}
+	spin_lock_irqsave(&cwq->lock, flags);
+	p = cwq->thread;
+	cwq->thread = NULL;
+	spin_unlock_irqrestore(&cwq->lock, flags);
+	if (p)
+		kthread_stop(p);
 }
 
 void destroy_workqueue(struct workqueue_struct *wq)
@@ -323,10 +327,14 @@
 
 	flush_workqueue(wq);
 
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (cpu_online(cpu))
 			cleanup_workqueue_thread(wq, cpu);
 	}
+	del_workqueue(wq);
+	unlock_cpu_hotplug();
 	kfree(wq);
 }
 
@@ -347,6 +355,11 @@
 	flush_workqueue(keventd_wq);
 }
 
+int keventd_up(void)
+{
+	return keventd_wq != NULL;
+}
+
 int current_is_keventd(void)
 {
 	struct cpu_workqueue_struct *cwq;
@@ -362,8 +375,75 @@
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* Take the work from this (downed) CPU. */
+static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+{
+	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
+	LIST_HEAD(list);
+	struct work_struct *work;
+
+	spin_lock_irq(&cwq->lock);
+	list_splice_init(&cwq->worklist, &list);
+
+	while (!list_empty(&list)) {
+		printk("Taking work for %s\n", wq->name);
+		work = list_entry(list.next,struct work_struct,entry);
+		list_del(&work->entry);
+		__queue_work(wq->cpu_wq + smp_processor_id(), work);
+	}
+	spin_unlock_irq(&cwq->lock);
+}
+
+/* We're holding the cpucontrol mutex here */
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	unsigned int hotcpu = (unsigned long)hcpu;
+	struct workqueue_struct *wq;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		/* Create a new workqueue thread for it. */
+		list_for_each_entry(wq, &workqueues, list) {
+			if (create_workqueue_thread(wq, hotcpu) < 0) {
+				printk("workqueue for %i failed\n", hotcpu);
+				return NOTIFY_BAD;
+			}
+		}
+		break;
+
+	case CPU_ONLINE:
+		/* Kick off worker threads. */
+		list_for_each_entry(wq, &workqueues, list)
+			wake_up_process(wq->cpu_wq[hotcpu].thread);
+		break;
+
+	case CPU_UP_CANCELED:
+		list_for_each_entry(wq, &workqueues, list) {
+			/* Unbind so it can run. */
+			kthread_bind(wq->cpu_wq[hotcpu].thread,
+				     smp_processor_id());
+			cleanup_workqueue_thread(wq, hotcpu);
+		}
+		break;
+
+	case CPU_DEAD:
+		list_for_each_entry(wq, &workqueues, list)
+			cleanup_workqueue_thread(wq, hotcpu);
+		list_for_each_entry(wq, &workqueues, list)
+			take_over_work(wq, hotcpu);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+#endif
+
 void init_workqueues(void)
 {
+	hotcpu_notifier(workqueue_cpu_callback, 0);
 	keventd_wq = create_workqueue("events");
 	BUG_ON(!keventd_wq);
 }
--- diff/lib/bitmap.c	2004-02-18 08:54:13.000000000 +0000
+++ source/lib/bitmap.c	2004-02-18 09:04:03.000000000 +0000
@@ -165,7 +165,7 @@
 #define unhex(c)			(isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
 
 /**
- * bitmap_snprintf - convert bitmap to an ASCII hex string.
+ * bitmap_scnprintf - convert bitmap to an ASCII hex string.
  * @buf: byte buffer into which string is placed
  * @buflen: reserved size of @buf, in bytes
  * @maskp: pointer to bitmap to convert
@@ -174,7 +174,7 @@
  * Exactly @nmaskbits bits are displayed.  Hex digits are grouped into
  * comma-separated sets of eight digits per set.
  */
-int bitmap_snprintf(char *buf, unsigned int buflen,
+int bitmap_scnprintf(char *buf, unsigned int buflen,
 	const unsigned long *maskp, int nmaskbits)
 {
 	int i, word, bit, len = 0;
@@ -193,14 +193,14 @@
 		word = i / BITS_PER_LONG;
 		bit = i % BITS_PER_LONG;
 		val = (maskp[word] >> bit) & chunkmask;
-		len += snprintf(buf+len, buflen-len, "%s%0*lx", sep,
+		len += scnprintf(buf+len, buflen-len, "%s%0*lx", sep,
 			(chunksz+3)/4, val);
 		chunksz = CHUNKSZ;
 		sep = ",";
 	}
 	return len;
 }
-EXPORT_SYMBOL(bitmap_snprintf);
+EXPORT_SYMBOL(bitmap_scnprintf);
 
 /**
  * bitmap_parse - convert an ASCII hex string into a bitmap.
--- diff/lib/crc32.c	2004-02-18 08:54:13.000000000 +0000
+++ source/lib/crc32.c	2004-02-18 09:04:03.000000000 +0000
@@ -397,7 +397,7 @@
  * the same way on decoding, it doesn't make a difference.
  */
 
-#if UNITTEST
+#ifdef UNITTEST
 
 #include <stdlib.h>
 #include <stdio.h>
--- diff/lib/idr.c	2003-05-21 11:50:01.000000000 +0100
+++ source/lib/idr.c	2004-02-18 09:04:03.000000000 +0000
@@ -62,13 +62,13 @@
  *   to the rest of the functions.  The structure is defined in the
  *   header.
 
- * int idr_pre_get(struct idr *idp)
+ * int idr_pre_get(struct idr *idp, unsigned gfp_mask)
 
  *   This function should be called prior to locking and calling the
  *   following function.  It pre allocates enough memory to satisfy the
- *   worst possible allocation.  It can sleep, so must not be called
- *   with any spinlocks held.  If the system is REALLY out of memory
- *   this function returns 0, other wise 1.
+ *   worst possible allocation.  Unless gfp_mask is GFP_ATOMIC, it can
+ *   sleep, so must not be called with any spinlocks held.  If the system is
+ *   REALLY out of memory this function returns 0, other wise 1.
 
  * int idr_get_new(struct idr *idp, void *ptr);
  
@@ -135,11 +135,11 @@
 	spin_unlock(&idp->lock);
 }
 
-int idr_pre_get(struct idr *idp)
+int idr_pre_get(struct idr *idp, unsigned gfp_mask)
 {
 	while (idp->id_free_cnt < idp->layers + 1) {
 		struct idr_layer *new;
-		new = kmem_cache_alloc(idr_layer_cache, GFP_KERNEL);
+		new = kmem_cache_alloc(idr_layer_cache, gfp_mask);
 		if(new == NULL)
 			return (0);
 		free_layer(idp, new);
--- diff/lib/vsprintf.c	2004-02-18 08:54:13.000000000 +0000
+++ source/lib/vsprintf.c	2004-02-18 09:04:03.000000000 +0000
@@ -12,6 +12,8 @@
 /* 
  * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
  * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
  */
 
 #include <stdarg.h>
@@ -228,19 +230,22 @@
 }
 
 /**
-* vsnprintf - Format a string and place it in a buffer
-* @buf: The buffer to place the result into
-* @size: The size of the buffer, including the trailing null space
-* @fmt: The format string to use
-* @args: Arguments for the format string
-*
-* The return value is the number of characters which would be
-* generated for the given input, excluding the trailing null,
-* as per ISO C99.  If the return is greater than or equal to
-* @size, the resulting string is truncated.
-*
-* Call this function if you are already dealing with a va_list.
-* You probably want snprintf instead.
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
  */
 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 {
@@ -482,6 +487,30 @@
 EXPORT_SYMBOL(vsnprintf);
 
 /**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int i;
+
+	i=vsnprintf(buf,size,fmt,args);
+	return (i >= size) ? (size - 1) : i;
+}
+
+EXPORT_SYMBOL(vscnprintf);
+
+/**
  * snprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @size: The size of the buffer, including the trailing null space
@@ -507,11 +536,39 @@
 EXPORT_SYMBOL(snprintf);
 
 /**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
+ * greater than or equal to @size, the resulting string is truncated.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vsnprintf(buf, size, fmt, args);
+	va_end(args);
+	return (i >= size) ? (size - 1) : i;
+}
+EXPORT_SYMBOL(scnprintf);
+
+/**
  * vsprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @fmt: The format string to use
  * @args: Arguments for the format string
  *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf or vscnprintf in order to avoid
+ * buffer overflows.
+ *
  * Call this function if you are already dealing with a va_list.
  * You probably want sprintf instead.
  */
@@ -527,6 +584,10 @@
  * @buf: The buffer to place the result into
  * @fmt: The format string to use
  * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf or scnprintf in order to avoid
+ * buffer overflows.
  */
 int sprintf(char * buf, const char *fmt, ...)
 {
--- diff/mm/Makefile	2003-10-09 09:47:17.000000000 +0100
+++ source/mm/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -12,3 +12,4 @@
 			   slab.o swap.o truncate.o vmscan.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+obj-$(CONFIG_X86_4G)	+= usercopy.o
--- diff/mm/bootmem.c	2003-11-25 15:24:59.000000000 +0000
+++ source/mm/bootmem.c	2004-02-18 09:04:03.000000000 +0000
@@ -91,8 +91,11 @@
 	if (end > bdata->node_low_pfn)
 		BUG();
 	for (i = sidx; i < eidx; i++)
-		if (test_and_set_bit(i, bdata->node_bootmem_map))
+		if (test_and_set_bit(i, bdata->node_bootmem_map)) {
+#ifdef CONFIG_DEBUG_BOOTMEM
 			printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
+#endif
+		}
 }
 
 static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
--- diff/mm/filemap.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/filemap.c	2004-02-18 09:04:03.000000000 +0000
@@ -73,6 +73,9 @@
  *  ->mmap_sem
  *    ->i_sem			(msync)
  *
+ *  ->i_sem
+ *    ->i_alloc_sem             (various)
+ *
  *  ->inode_lock
  *    ->sb_lock			(fs/fs-writeback.c)
  *    ->mapping->page_lock	(__sync_single_inode)
@@ -226,6 +229,18 @@
 
 EXPORT_SYMBOL(filemap_fdatawait);
 
+int filemap_write_and_wait(struct address_space *mapping)
+{
+	int retval = 0;
+
+	if (mapping->nrpages) {
+		retval = filemap_fdatawrite(mapping);
+		if (retval == 0)
+			retval = filemap_fdatawait(mapping);
+	}
+	return retval;
+}
+
 /*
  * This adds a page to the page cache, starting out as locked, unreferenced,
  * not uptodate and with no errors.
@@ -1713,6 +1728,7 @@
 
 /*
  * Write to a file through the page cache. 
+ * Called under i_sem for S_ISREG files.
  *
  * We put everything into the page cache prior to writing it. This is not a
  * problem when writing full pages. With partial pages, however, we first have
@@ -1801,12 +1817,21 @@
 		/*
 		 * Sync the fs metadata but not the minor inode changes and
 		 * of course not the data as we did direct DMA for the IO.
+		 * i_sem is held, which protects generic_osync_inode() from
+		 * livelocking.
 		 */
 		if (written >= 0 && file->f_flags & O_SYNC)
 			status = generic_osync_inode(inode, mapping, OSYNC_METADATA);
-		if (written >= 0 && !is_sync_kiocb(iocb))
+		if (written == count && !is_sync_kiocb(iocb))
 			written = -EIOCBQUEUED;
-		goto out_status;
+		if (written < 0 || written == count)
+			goto out_status;
+		/*
+		 * direct-io write to a hole: fall through to buffered I/O
+		 * for completing the rest of the request.
+		 */
+		pos += written;
+		count -= written;
 	}
 
 	buf = iov->iov_base;
@@ -1895,6 +1920,14 @@
 					OSYNC_METADATA|OSYNC_DATA);
 	}
 	
+	/*
+	 * If we get here for O_DIRECT writes then we must have fallen through
+	 * to buffered writes (block instantiation inside i_size).  So we sync
+	 * the file data here, to try to honour O_DIRECT expectations.
+	 */
+	if (unlikely(file->f_flags & O_DIRECT) && written)
+		status = filemap_write_and_wait(mapping);
+
 out_status:	
 	err = written ? written : status;
 out:
@@ -1986,6 +2019,9 @@
 
 EXPORT_SYMBOL(generic_file_writev);
 
+/*
+ * Called under i_sem for writes to S_ISREG files
+ */
 ssize_t
 generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
 	loff_t offset, unsigned long nr_segs)
@@ -1994,18 +2030,13 @@
 	struct address_space *mapping = file->f_mapping;
 	ssize_t retval;
 
-	if (mapping->nrpages) {
-		retval = filemap_fdatawrite(mapping);
-		if (retval == 0)
-			retval = filemap_fdatawait(mapping);
-		if (retval)
-			goto out;
+	retval = filemap_write_and_wait(mapping);
+	if (retval == 0) {
+		retval = mapping->a_ops->direct_IO(rw, iocb, iov,
+						offset, nr_segs);
+		if (rw == WRITE && mapping->nrpages)
+			invalidate_inode_pages2(mapping);
 	}
-
-	retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs);
-	if (rw == WRITE && mapping->nrpages)
-		invalidate_inode_pages2(mapping);
-out:
 	return retval;
 }
 
--- diff/mm/fremap.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/fremap.c	2004-02-18 09:04:03.000000000 +0000
@@ -38,7 +38,7 @@
 					set_page_dirty(page);
 				page_remove_rmap(page, ptep);
 				page_cache_release(page);
-				mm->rss--;
+				dec_rss(mm, page);
 			}
 		}
 	} else {
@@ -78,7 +78,7 @@
 
 	zap_pte(mm, vma, addr, pte);
 
-	mm->rss++;
+	inc_rss(mm, page);
 	flush_icache_page(vma, page);
 	set_pte(pte, mk_pte(page, prot));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
--- diff/mm/memory.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/memory.c	2004-02-18 09:04:03.000000000 +0000
@@ -109,7 +109,8 @@
 	pte_free_tlb(tlb, page);
 }
 
-static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir)
+static inline void free_one_pgd(struct mmu_gather *tlb, pgd_t * dir,
+							int pgd_idx)
 {
 	int j;
 	pmd_t * pmd;
@@ -123,8 +124,11 @@
 	}
 	pmd = pmd_offset(dir, 0);
 	pgd_clear(dir);
-	for (j = 0; j < PTRS_PER_PMD ; j++)
+	for (j = 0; j < PTRS_PER_PMD ; j++) {
+		if (pgd_idx * PGDIR_SIZE + j * PMD_SIZE >= TASK_SIZE)
+			break;
 		free_one_pmd(tlb, pmd+j);
+	}
 	pmd_free_tlb(tlb, pmd);
 }
 
@@ -137,11 +141,13 @@
 void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr)
 {
 	pgd_t * page_dir = tlb->mm->pgd;
+	int pgd_idx = first;
 
 	page_dir += first;
 	do {
-		free_one_pgd(tlb, page_dir);
+		free_one_pgd(tlb, page_dir, pgd_idx);
 		page_dir++;
+		pgd_idx++;
 	} while (--nr);
 }
 
@@ -328,7 +334,7 @@
 					pte = pte_mkclean(pte);
 				pte = pte_mkold(pte);
 				get_page(page);
-				dst->rss++;
+				inc_rss(dst, page);
 
 				set_pte(dst_pte, pte);
 				pte_chain = page_add_rmap(page, dst_pte,
@@ -420,7 +426,14 @@
 					if (page->mapping && pte_young(pte) &&
 							!PageSwapCache(page))
 						mark_page_accessed(page);
-					tlb->freed++;
+					/*
+					 * While we have the page that is being
+					 * freed handy, make sure we decrement
+					 * the mm's RSS accordingly.  This is
+					 * only important for NUMA per-node
+					 * RSS accounting.
+					 */
+					dec_rss(tlb->mm, page);
 					page_remove_rmap(page, ptep);
 					tlb_remove_page(tlb, page);
 				}
@@ -439,7 +452,7 @@
 		unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
-	unsigned long end;
+	unsigned long end, pgd_boundary;
 
 	if (pgd_none(*dir))
 		return;
@@ -450,8 +463,9 @@
 	}
 	pmd = pmd_offset(dir, address);
 	end = address + size;
-	if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
-		end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	pgd_boundary = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	if (pgd_boundary && (end > pgd_boundary))
+		end = pgd_boundary;
 	do {
 		zap_pte_range(tlb, pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
@@ -574,9 +588,10 @@
 			if ((long)zap_bytes > 0)
 				continue;
 			if (need_resched()) {
+				int fullmm = tlb_is_full_mm(*tlbp);
 				tlb_finish_mmu(*tlbp, tlb_start, start);
 				cond_resched_lock(&mm->page_table_lock);
-				*tlbp = tlb_gather_mmu(mm, 0);
+				*tlbp = tlb_gather_mmu(mm, fullmm);
 				tlb_start_valid = 0;
 			}
 			zap_bytes = ZAP_BLOCK_SIZE;
@@ -605,6 +620,11 @@
 	might_sleep();
 
 	if (is_vm_hugetlb_page(vma)) {
+		static int x;
+		if (x < 10) {
+			x++;
+			dump_stack();
+		}
 		zap_hugepage_range(vma, address, size);
 		return;
 	}
@@ -692,6 +712,7 @@
 		struct page **pages, struct vm_area_struct **vmas)
 {
 	int i;
+	int vm_io;
 	unsigned int flags;
 
 	/* 
@@ -735,8 +756,10 @@
 			continue;
 		}
 
-		if (!vma || (pages && (vma->vm_flags & VM_IO))
-				|| !(flags & vma->vm_flags))
+		if (!vma)
+			return i ? : -EFAULT;
+		vm_io = vma->vm_flags & VM_IO;
+		if ((pages && vm_io) || !(flags & vma->vm_flags))
 			return i ? : -EFAULT;
 
 		if (is_vm_hugetlb_page(vma)) {
@@ -746,8 +769,16 @@
 		}
 		spin_lock(&mm->page_table_lock);
 		do {
-			struct page *map;
-			while (!(map = follow_page(mm, start, write))) {
+			struct page *map = NULL;
+			int lookup_write = write;
+
+			/*
+			 * We don't follow pagetables for VM_IO regions - they
+			 * may have no pageframes.
+			 */
+			if (vm_io)
+				goto no_follow;
+			while (!(map = follow_page(mm, start, lookup_write))) {
 				spin_unlock(&mm->page_table_lock);
 				switch (handle_mm_fault(mm,vma,start,write)) {
 				case VM_FAULT_MINOR:
@@ -763,6 +794,14 @@
 				default:
 					BUG();
 				}
+				/*
+				 * Now that we have performed a write fault
+				 * and surely no longer have a shared page we
+				 * shouldn't write, we shouldn't ignore an
+				 * unwritable page in the page table if
+				 * we are forcing write access.
+				 */
+				lookup_write = write && !force;
 				spin_lock(&mm->page_table_lock);
 			}
 			if (pages) {
@@ -778,6 +817,7 @@
 				if (!PageReserved(pages[i]))
 					page_cache_get(pages[i]);
 			}
+no_follow:
 			if (vmas)
 				vmas[i] = vma;
 			i++;
@@ -952,6 +992,19 @@
 EXPORT_SYMBOL(remap_page_range);
 
 /*
+ * Do pte_mkwrite, but only if the vma says VM_WRITE.  We do this when
+ * servicing faults for write access.  In the normal case, do always want
+ * pte_mkwrite.  But get_user_pages can cause write faults for mappings
+ * that do not have writing enabled, when used by access_process_vm.
+ */
+static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
+{
+	if (likely(vma->vm_flags & VM_WRITE))
+		pte = pte_mkwrite(pte);
+	return pte;
+}
+
+/*
  * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
  */
 static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address, 
@@ -960,7 +1013,8 @@
 	pte_t entry;
 
 	flush_cache_page(vma, address);
-	entry = pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)));
+	entry = maybe_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)),
+			      vma);
 	ptep_establish(vma, address, page_table, entry);
 	update_mmu_cache(vma, address, entry);
 }
@@ -1012,7 +1066,8 @@
 		unlock_page(old_page);
 		if (reuse) {
 			flush_cache_page(vma, address);
-			entry = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)));
+			entry = maybe_mkwrite(pte_mkyoung(pte_mkdirty(pte)),
+					      vma);
 			ptep_establish(vma, address, page_table, entry);
 			update_mmu_cache(vma, address, entry);
 			pte_unmap(page_table);
@@ -1043,7 +1098,7 @@
 	page_table = pte_offset_map(pmd, address);
 	if (pte_same(*page_table, pte)) {
 		if (PageReserved(old_page))
-			++mm->rss;
+			inc_rss(mm, new_page);
 		page_remove_rmap(old_page, page_table);
 		break_cow(vma, new_page, address, page_table);
 		pte_chain = page_add_rmap(new_page, page_table, pte_chain);
@@ -1251,7 +1306,7 @@
 	mark_page_accessed(page);
 	pte_chain = pte_chain_alloc(GFP_KERNEL);
 	if (!pte_chain) {
-		ret = -ENOMEM;
+		ret = VM_FAULT_OOM;
 		goto out;
 	}
 	lock_page(page);
@@ -1277,10 +1332,10 @@
 	if (vm_swap_full())
 		remove_exclusive_swap_page(page);
 
-	mm->rss++;
+	inc_rss(mm, page);
 	pte = mk_pte(page, vma->vm_page_prot);
 	if (write_access && can_share_swap_page(page))
-		pte = pte_mkdirty(pte_mkwrite(pte));
+		pte = maybe_mkwrite(pte_mkdirty(pte), vma);
 	unlock_page(page);
 
 	flush_icache_page(vma, page);
@@ -1346,8 +1401,10 @@
 			ret = VM_FAULT_MINOR;
 			goto out;
 		}
-		mm->rss++;
-		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+		inc_rss(mm, page);
+		entry = maybe_mkwrite(pte_mkdirty(mk_pte(page,
+							 vma->vm_page_prot)),
+				      vma);
 		lru_cache_add_active(page);
 		mark_page_accessed(page);
 	}
@@ -1459,11 +1516,11 @@
 	/* Only go through if we didn't race with anybody else... */
 	if (pte_none(*page_table)) {
 		if (!PageReserved(new_page))
-			++mm->rss;
+			inc_rss(mm, new_page);
 		flush_icache_page(vma, new_page);
 		entry = mk_pte(new_page, vma->vm_page_prot);
 		if (write_access)
-			entry = pte_mkwrite(pte_mkdirty(entry));
+			entry = maybe_mkwrite(pte_mkdirty(entry), vma);
 		set_pte(page_table, entry);
 		pte_chain = page_add_rmap(new_page, page_table, pte_chain);
 		pte_unmap(page_table);
--- diff/mm/mmap.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/mmap.c	2004-02-18 09:04:03.000000000 +0000
@@ -11,6 +11,7 @@
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/syscalls.h>
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -1445,7 +1446,7 @@
 	vma = mm->mmap;
 	mm->mmap = mm->mmap_cache = NULL;
 	mm->mm_rb = RB_ROOT;
-	mm->rss = 0;
+	zero_rss(mm);
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
 
--- diff/mm/page-writeback.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/page-writeback.c	2004-02-18 09:04:03.000000000 +0000
@@ -28,6 +28,7 @@
 #include <linux/smp.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
+#include <linux/quotaops.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -81,6 +82,16 @@
  */
 int dirty_expire_centisecs = 30 * 100;
 
+/*
+ * Flag that makes the machine dump writes/reads and block dirtyings.
+ */
+int block_dump;
+
+/*
+ * Flag that puts the machine in "laptop mode".
+ */
+int laptop_mode;
+
 /* End of sysctl-exported parameters */
 
 
@@ -195,7 +206,7 @@
 	if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
 		dirty_exceeded = 0;
 
-	if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
+	if (!unlikely(laptop_mode) && !writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
 		pdflush_operation(background_writeout, 0);
 }
 
@@ -289,7 +300,17 @@
 	return pdflush_operation(background_writeout, nr_pages);
 }
 
-static struct timer_list wb_timer;
+
+static void wb_timer_fn(unsigned long unused);
+
+/*
+ * Both timers share the same handler
+ */
+static struct timer_list wb_timer =
+			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
+static struct timer_list laptop_mode_wb_timer =
+			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
+
 
 /*
  * Periodic writeback of "old" data.
@@ -328,6 +349,8 @@
 	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
 	start_jif = jiffies;
 	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
+	if (laptop_mode)
+		wbc.older_than_this = NULL;
 	nr_to_write = ps.nr_dirty + ps.nr_unstable +
 			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
 	while (nr_to_write > 0) {
@@ -346,8 +369,10 @@
 		next_jif = jiffies + HZ;
 	if (dirty_writeback_centisecs)
 		mod_timer(&wb_timer, next_jif);
+	del_timer(&laptop_mode_wb_timer); /* May have been set as a result of our writes. */
 }
 
+
 /*
  * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
  */
@@ -364,13 +389,31 @@
 	return 0;
 }
 
+/*
+ * We've spun up the disk and we're in laptop mode: schedule writeback
+ * of all dirty data in 5 seconds.
+ *
+ * Laptop mode writeback will be delayed if it has previously been
+ * scheduled to occur within 5 seconds. That way, the writeback will
+ * only be triggered if the system is truly quiet again.
+ */
+void disk_is_spun_up(int postpone_writeback)
+{
+	if (postpone_writeback || !timer_pending(&laptop_mode_wb_timer))
+		mod_timer(&laptop_mode_wb_timer, jiffies + 5 * HZ);
+}
+
+
+/*
+ * Handler for wb_timer and laptop_mode_wb_timer.
+ */
 static void wb_timer_fn(unsigned long unused)
 {
 	if (pdflush_operation(wb_kupdate, 0) < 0)
 		mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
-
 }
 
+
 /*
  * If ratelimit_pages is too high then we can get into dirty-data overload
  * if a large number of processes all perform writes at the same time.
@@ -430,20 +473,41 @@
 		vm_dirty_ratio /= 100;
 	}
 
-	init_timer(&wb_timer);
 	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
-	wb_timer.data = 0;
-	wb_timer.function = wb_timer_fn;
 	add_timer(&wb_timer);
+
 	set_ratelimit();
 	register_cpu_notifier(&ratelimit_nb);
 }
 
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
+	int ret;
+	if (wbc->sync_mode == WB_SYNC_NONE) {
+		if (!down_read_trylock(&mapping->wb_rwsema))
+			/*
+			 * SYNC writeback in progress
+			 */
+			return 0;
+	} else {
+		/*
+		 * Only allow 1 SYNC writeback at a time, to be able
+		 * to wait for all i/o without worrying about racing
+		 * WB_SYNC_NONE writers.
+		 */
+		down_write(&mapping->wb_rwsema);
+	}
+
 	if (mapping->a_ops->writepages)
-		return mapping->a_ops->writepages(mapping, wbc);
-	return generic_writepages(mapping, wbc);
+		ret = mapping->a_ops->writepages(mapping, wbc);
+	else
+		ret = generic_writepages(mapping, wbc);
+	if (wbc->sync_mode == WB_SYNC_NONE) {
+		up_read(&mapping->wb_rwsema);
+	} else {
+		up_write(&mapping->wb_rwsema);
+	}
+	return ret;
 }
 
 /**
@@ -526,6 +590,8 @@
 				__mark_inode_dirty(mapping->host,
 							I_DIRTY_PAGES);
 		}
+		if (unlikely(block_dump))
+			printk("%s(%d): dirtied page\n", current->comm, current->pid);
 	}
 	return ret;
 }
--- diff/mm/page_alloc.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/page_alloc.c	2004-02-18 09:04:03.000000000 +0000
@@ -390,6 +390,27 @@
 	return allocated;
 }
 
+#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
+static void __drain_pages(unsigned int cpu)
+{
+	struct zone *zone;
+	int i;
+
+	for_each_zone(zone) {
+		struct per_cpu_pageset *pset;
+
+		pset = &zone->pageset[cpu];
+		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+			struct per_cpu_pages *pcp;
+
+			pcp = &pset->pcp[i];
+			pcp->count -= free_pages_bulk(zone, pcp->count,
+						&pcp->list, 0);
+		}
+	}
+}
+#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
+
 #ifdef CONFIG_PM
 int is_head_of_free_region(struct page *page)
 {
@@ -419,22 +440,9 @@
 void drain_local_pages(void)
 {
 	unsigned long flags;
-	struct zone *zone;
-	int i;
 
 	local_irq_save(flags);	
-	for_each_zone(zone) {
-		struct per_cpu_pageset *pset;
-
-		pset = &zone->pageset[smp_processor_id()];
-		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-			struct per_cpu_pages *pcp;
-
-			pcp = &pset->pcp[i];
-			pcp->count -= free_pages_bulk(zone, pcp->count,
-						&pcp->list, 0);
-		}
-	}
+	__drain_pages(smp_processor_id());
 	local_irq_restore(flags);	
 }
 #endif /* CONFIG_PM */
@@ -971,7 +979,13 @@
 			printk("\n");
 
 		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
-			struct per_cpu_pageset *pageset = zone->pageset + cpu;
+			struct per_cpu_pageset *pageset;
+
+			if (!cpu_possible(cpu))
+				continue;
+
+			pageset = zone->pageset + cpu;
+
 			for (temperature = 0; temperature < 2; temperature++)
 				printk("cpu %d %s: low %d, high %d, batch %d\n",
 					cpu,
@@ -1212,6 +1226,15 @@
 #endif
 
 /*
+ * Dummy pages used to scan active lists. It would be cleaner if these
+ * could be part of struct zone directly, but include dependencies currently
+ * prevent that.
+ */
+static struct {
+	struct page zone[MAX_NR_ZONES];
+} ____cacheline_aligned scan_pages[MAX_NUMNODES];
+
+/*
  * Set up the zone data structures:
  *   - mark all pages reserved
  *   - mark all memory queues empty
@@ -1233,6 +1256,7 @@
 		struct zone *zone = pgdat->node_zones + j;
 		unsigned long size, realsize;
 		unsigned long batch;
+		struct page *scan_page;
 
 		zone_table[NODEZONE(nid, j)] = zone;
 		realsize = size = zones_size[j];
@@ -1287,6 +1311,22 @@
 		atomic_set(&zone->refill_counter, 0);
 		zone->nr_active = 0;
 		zone->nr_inactive = 0;
+
+		/* initialize dummy page used for scanning */
+		scan_page = &(scan_pages[nid].zone[j]);
+		zone->scan_page = scan_page;
+		memset(scan_page, 0, sizeof *scan_page);
+		scan_page->flags =
+			(1 << PG_locked) |
+			(1 << PG_error) |
+			(1 << PG_lru) |
+			(1 << PG_active) |
+			(1 << PG_reserved);
+		set_page_zone(scan_page, j);
+		page_cache_get(scan_page);
+		INIT_LIST_HEAD(&scan_page->list);
+		list_add(&scan_page->lru, &zone->active_list);
+
 		if (!size)
 			continue;
 
@@ -1536,34 +1576,27 @@
 
 #endif /* CONFIG_PROC_FS */
 
-static void __devinit init_page_alloc_cpu(int cpu)
-{
-	struct page_state *ps = &per_cpu(page_states, cpu);
-	memset(ps, 0, sizeof(*ps));
-}
-	
-static int __devinit page_alloc_cpu_notify(struct notifier_block *self, 
-				unsigned long action, void *hcpu)
+#ifdef CONFIG_HOTPLUG_CPU
+static int page_alloc_cpu_notify(struct notifier_block *self,
+				 unsigned long action, void *hcpu)
 {
 	int cpu = (unsigned long)hcpu;
-	switch(action) {
-	case CPU_UP_PREPARE:
-		init_page_alloc_cpu(cpu);
-		break;
-	default:
-		break;
+	long *count;
+
+	if (action == CPU_DEAD) {
+		/* Drain local pagecache count. */
+		count = &per_cpu(nr_pagecache_local, cpu);
+		atomic_add(*count, &nr_pagecache);
+		*count = 0;
+		__drain_pages(cpu);
 	}
 	return NOTIFY_OK;
 }
-
-static struct notifier_block __devinitdata page_alloc_nb = {
-	.notifier_call	= page_alloc_cpu_notify,
-};
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init page_alloc_init(void)
 {
-	init_page_alloc_cpu(smp_processor_id());
-	register_cpu_notifier(&page_alloc_nb);
+	hotcpu_notifier(page_alloc_cpu_notify, 0);
 }
 
 /*
--- diff/mm/pdflush.c	2003-10-09 09:47:17.000000000 +0100
+++ source/mm/pdflush.c	2004-02-18 09:04:03.000000000 +0000
@@ -84,6 +84,8 @@
 	unsigned long when_i_went_to_sleep;
 };
 
+static int wakeup_count = 100;
+
 static int __pdflush(struct pdflush_work *my_work)
 {
 	daemonize("pdflush");
@@ -112,7 +114,10 @@
 
 		spin_lock_irq(&pdflush_lock);
 		if (!list_empty(&my_work->list)) {
-			printk("pdflush: bogus wakeup!\n");
+			if (wakeup_count > 0) {
+				wakeup_count--;
+				printk("pdflush: bogus wakeup!\n");
+			}
 			my_work->fn = NULL;
 			continue;
 		}
@@ -182,6 +187,7 @@
 {
 	unsigned long flags;
 	int ret = 0;
+	static int poke_count = 0;
 
 	if (fn == NULL)
 		BUG();		/* Hard to diagnose if it's deferred */
@@ -190,9 +196,19 @@
 	if (list_empty(&pdflush_list)) {
 		spin_unlock_irqrestore(&pdflush_lock, flags);
 		ret = -1;
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: no threads\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 	} else {
 		struct pdflush_work *pdf;
 
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: found a thread\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 		pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
 		list_del_init(&pdf->list);
 		if (list_empty(&pdflush_list))
--- diff/mm/readahead.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/readahead.c	2004-02-18 09:04:03.000000000 +0000
@@ -30,6 +30,7 @@
 {
 	memset(ra, 0, sizeof(*ra));
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
+	ra->average = ra->ra_pages / 2;
 }
 
 EXPORT_SYMBOL(file_ra_state_init);
@@ -380,9 +381,18 @@
 		 */
 		first_access=1;
 		ra->next_size = max / 2;
+		ra->prev_page = offset;
+		ra->serial_cnt++;
 		goto do_io;
 	}
 
+	if (offset == ra->prev_page + 1) {
+		if (ra->serial_cnt <= (max * 2))
+			ra->serial_cnt++;
+	} else {
+		ra->average = (ra->average + ra->serial_cnt) / 2;
+		ra->serial_cnt = 1;
+	}
 	preoffset = ra->prev_page;
 	ra->prev_page = offset;
 
@@ -449,8 +459,12 @@
 			  * accessed in the current window, there
 			  * is a high probability that around 'n' pages
 			  * shall be used in the next current window.
+			  *
+			  * To minimize lazy-readahead triggered
+			  * in the next current window, read in
+			  * an extra page.
 			  */
-			ra->next_size = preoffset - ra->start + 1;
+			ra->next_size = preoffset - ra->start + 2;
 		}
 		ra->start = offset;
 		ra->size = ra->next_size;
@@ -468,17 +482,34 @@
 		}
 	} else {
 		/*
-		 * This read request is within the current window.  It is time
-		 * to submit I/O for the ahead window while the application is
-		 * crunching through the current window.
+		 * This read request is within the current window.  It may be
+		 * time to submit I/O for the ahead window while the
+		 * application is about to step into the ahead window.
 		 */
 		if (ra->ahead_start == 0) {
-			ra->ahead_start = ra->start + ra->size;
-			ra->ahead_size = ra->next_size;
-			actual = do_page_cache_readahead(mapping, filp,
+			/*
+			 * if the average io-size is less than maximum
+			 * readahead size of the file the io pattern is
+			 * sequential. Hence  bring in the readahead window
+			 * immediately.
+			 * Else the i/o pattern is random. Bring
+			 * in the readahead window only if the last page of
+			 * the current window is accessed (lazy readahead).
+			 */
+			unsigned long average = ra->average;
+
+			if (ra->serial_cnt > average)
+				average = (ra->serial_cnt + ra->average) / 2;
+
+			if ((average >= max) || (offset == (ra->start +
+							ra->size - 1))) {
+				ra->ahead_start = ra->start + ra->size;
+				ra->ahead_size = ra->next_size;
+				actual = do_page_cache_readahead(mapping, filp,
 					ra->ahead_start, ra->ahead_size);
-			check_ra_success(ra, ra->ahead_size,
-					actual, orig_next_size);
+				check_ra_success(ra, ra->ahead_size,
+						actual, orig_next_size);
+			}
 		}
 	}
 out:
--- diff/mm/rmap.c	2004-02-09 10:36:12.000000000 +0000
+++ source/mm/rmap.c	2004-02-18 09:04:03.000000000 +0000
@@ -171,7 +171,17 @@
 	pte_addr_t pte_paddr = ptep_to_paddr(ptep);
 	struct pte_chain *cur_pte_chain;
 
-	if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
+	if (!pfn_valid(page_to_pfn(page))) {
+		static int count;
+
+		if (count < 5) {
+			printk("%s: invalid pfn\n", __FUNCTION__);
+			count++;
+		}
+		return pte_chain;
+	}
+
+	if (PageReserved(page))
 		return pte_chain;
 
 	pte_chain_lock(page);
@@ -360,7 +370,7 @@
 	if (pte_dirty(pte))
 		set_page_dirty(page);
 
-	mm->rss--;
+	dec_rss(mm, page);
 	page_cache_release(page);
 	ret = SWAP_SUCCESS;
 
--- diff/mm/slab.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/slab.c	2004-02-18 09:04:03.000000000 +0000
@@ -357,8 +357,8 @@
 #define	RED_ACTIVE	0x170FC2A5UL	/* when obj is active */
 
 /* ...and for poisoning */
-#define	POISON_BEFORE	0x5a	/* for use-uninitialised poisoning */
-#define POISON_AFTER	0x6b	/* for use-after-free poisoning */
+#define	POISON_INUSE	0x5a	/* for use-uninitialised poisoning */
+#define POISON_FREE	0x6b	/* for use-after-free poisoning */
 #define	POISON_END	0xa5	/* end-byte of poisoning */
 
 /* memory layout of objects:
@@ -521,9 +521,19 @@
 static DEFINE_PER_CPU(struct timer_list, reap_timers);
 
 static void reap_timer_fnc(unsigned long data);
-
+static void free_block (kmem_cache_t* cachep, void** objpp, int len);
 static void enable_cpucache (kmem_cache_t *cachep);
 
+static inline void ** ac_entry(struct array_cache *ac)
+{
+	return (void**)(ac+1);
+}
+
+static inline struct array_cache *ac_data(kmem_cache_t *cachep)
+{
+	return cachep->array[smp_processor_id()];
+}
+
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
 static void cache_estimate (unsigned long gfporder, size_t size,
 		 int flags, size_t *left_over, unsigned int *num)
@@ -573,32 +583,39 @@
 	if (rt->function == NULL) {
 		init_timer(rt);
 		rt->expires = jiffies + HZ + 3*cpu;
+		rt->data = cpu;
 		rt->function = reap_timer_fnc;
 		add_timer_on(rt, cpu);
 	}
 }
 
-/*
- * Note: if someone calls kmem_cache_alloc() on the new
- * cpu before the cpuup callback had a chance to allocate
- * the head arrays, it will oops.
- * Is CPU_ONLINE early enough?
- */
+#ifdef CONFIG_HOTPLUG_CPU
+static void stop_cpu_timer(int cpu)
+{
+	struct timer_list *rt = &per_cpu(reap_timers, cpu);
+
+	if (rt->function) {
+		del_timer_sync(rt);
+		WARN_ON(timer_pending(rt));
+		rt->function = NULL;
+	}
+}
+#endif
+
 static int __devinit cpuup_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
 {
 	long cpu = (long)hcpu;
-	struct list_head *p;
+	kmem_cache_t* cachep;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
 		down(&cache_chain_sem);
-		list_for_each(p, &cache_chain) {
+		list_for_each_entry(cachep, &cache_chain, next) {
 			int memsize;
 			struct array_cache *nc;
 
-			kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next);
 			memsize = sizeof(void*)*cachep->limit+sizeof(struct array_cache);
 			nc = kmalloc(memsize, GFP_KERNEL);
 			if (!nc)
@@ -618,22 +635,30 @@
 		up(&cache_chain_sem);
 		break;
 	case CPU_ONLINE:
-		if (g_cpucache_up == FULL)
-			start_cpu_timer(cpu);
+		start_cpu_timer(cpu);
 		break;
+
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		stop_cpu_timer(cpu);
+		/* fall thru */
 	case CPU_UP_CANCELED:
 		down(&cache_chain_sem);
-
-		list_for_each(p, &cache_chain) {
+		list_for_each_entry(cachep, &cache_chain, next) {
 			struct array_cache *nc;
-			kmem_cache_t* cachep = list_entry(p, kmem_cache_t, next);
 
+			spin_lock_irq(&cachep->spinlock);
+			/* cpu is dead; no one can alloc from it. */
 			nc = cachep->array[cpu];
 			cachep->array[cpu] = NULL;
+			cachep->free_limit -= cachep->batchcount;
+			free_block(cachep, ac_entry(nc), nc->avail);
+			spin_unlock_irq(&cachep->spinlock);
 			kfree(nc);
 		}
 		up(&cache_chain_sem);
 		break;
+#endif /* CONFIG_HOTPLUG_CPU */
 	}
 	return NOTIFY_OK;
 bad:
@@ -643,16 +668,6 @@
 
 static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 };
 
-static inline void ** ac_entry(struct array_cache *ac)
-{
-	return (void**)(ac+1);
-}
-
-static inline struct array_cache *ac_data(kmem_cache_t *cachep)
-{
-	return cachep->array[smp_processor_id()];
-}
-
 /* Initialisation.
  * Called after the gfp() functions have been enabled, and before smp_init().
  */
@@ -887,60 +902,105 @@
 	*(unsigned char *)(addr+size-1) = POISON_END;
 }
 
-static void *scan_poisoned_obj(unsigned char* addr, unsigned int size)
+static void dump_line(char *data, int offset, int limit)
 {
-	unsigned char *end;
-	
-	end = addr + size - 1;
-
-	for (; addr < end; addr++) {
-		if (*addr != POISON_BEFORE && *addr != POISON_AFTER)
-			return addr;
+	int i;
+	printk(KERN_ERR "%03x:", offset);
+	for (i=0;i<limit;i++) {
+		printk(" %02x", (unsigned char)data[offset+i]);
 	}
-	if (*addr != POISON_END)
-		return addr;
-	return NULL;
+	printk("\n");
 }
+#endif
 
-static void check_poison_obj(kmem_cache_t *cachep, void *objp)
+static void print_objinfo(kmem_cache_t *cachep, void *objp, int lines)
 {
-	void *end;
-	void *realobj;
-	int size = obj_reallen(cachep);
+#if DEBUG
+	int i, size;
+	char *realobj;
 
-	realobj = objp+obj_dbghead(cachep);
+	if (cachep->flags & SLAB_RED_ZONE) {
+		printk(KERN_ERR "Redzone: 0x%lx/0x%lx.\n",
+			*dbg_redzone1(cachep, objp),
+			*dbg_redzone2(cachep, objp));
+	}
 
-	end = scan_poisoned_obj(realobj, size);
-	if (end) {
-		int s;
-		printk(KERN_ERR "Slab corruption: start=%p, expend=%p, "
-				"problemat=%p\n", realobj, realobj+size-1, end);
-		if (cachep->flags & SLAB_STORE_USER) {
-			printk(KERN_ERR "Last user: [<%p>]", *dbg_userword(cachep, objp));
-			print_symbol("(%s)", (unsigned long)*dbg_userword(cachep, objp));
-			printk("\n");
-		}
-		printk(KERN_ERR "Data: ");
-		for (s = 0; s < size; s++) {
-			if (((char*)realobj)[s] == POISON_BEFORE)
-				printk(".");
-			else if (((char*)realobj)[s] == POISON_AFTER)
-				printk("*");
-			else
-				printk("%02X ", ((unsigned char*)realobj)[s]);
-		}
+	if (cachep->flags & SLAB_STORE_USER) {
+		printk(KERN_ERR "Last user: [<%p>]", *dbg_userword(cachep, objp));
+		print_symbol("(%s)", (unsigned long)*dbg_userword(cachep, objp));
 		printk("\n");
-		printk(KERN_ERR "Next: ");
-		for (; s < size + 32; s++) {
-			if (((char*)realobj)[s] == POISON_BEFORE)
-				printk(".");
-			else if (((char*)realobj)[s] == POISON_AFTER)
-				printk("*");
-			else
-				printk("%02X ", ((unsigned char*)realobj)[s]);
+	}
+	realobj = (char*)objp+obj_dbghead(cachep);
+	size = cachep->objsize;
+	for (i=0; i<size && lines;i+=16, lines--) {
+		int limit;
+		limit = 16;
+		if (i+limit > size)
+			limit = size-i;
+		dump_line(realobj, i, limit);
+	}
+#endif
+}
+
+#if DEBUG
+
+static void check_poison_obj(kmem_cache_t *cachep, void *objp)
+{
+	char *realobj;
+	int size, i;
+	int lines = 0;
+
+	realobj = (char*)objp+obj_dbghead(cachep);
+	size = obj_reallen(cachep);
+
+	for (i=0;i<size;i++) {
+		char exp = POISON_FREE;
+		if (i == size-1)
+			exp = POISON_END;
+		if (realobj[i] != exp) {
+			int limit;
+			/* Mismatch ! */
+			/* Print header */
+			if (lines == 0) {
+				printk(KERN_ERR "Slab corruption: start=%p, len=%d\n",
+						realobj, size);
+				print_objinfo(cachep, objp, 0);
+			}
+			/* Hexdump the affected line */
+			i = (i/16)*16;
+			limit = 16;
+			if (i+limit > size)
+				limit = size-i;
+			dump_line(realobj, i, limit);
+			i += 16;
+			lines++;
+			/* Limit to 5 lines */
+			if (lines > 5)
+				break;
+		}
+	}
+	if (lines != 0) {
+		/* Print some data about the neighboring objects, if they
+		 * exist:
+		 */
+		struct slab *slabp = GET_PAGE_SLAB(virt_to_page(objp));
+		int objnr;
+
+		objnr = (objp-slabp->s_mem)/cachep->objsize;
+		if (objnr) {
+			objp = slabp->s_mem+(objnr-1)*cachep->objsize;
+			realobj = (char*)objp+obj_dbghead(cachep);
+			printk(KERN_ERR "Prev obj: start=%p, len=%d\n",
+						realobj, size);
+			print_objinfo(cachep, objp, 2);
+		}
+		if (objnr+1 < cachep->num) {
+			objp = slabp->s_mem+(objnr+1)*cachep->objsize;
+			realobj = (char*)objp+obj_dbghead(cachep);
+			printk(KERN_ERR "Next obj: start=%p, len=%d\n",
+						realobj, size);
+			print_objinfo(cachep, objp, 2);
 		}
-		printk("\n");
-		slab_error(cachep, "object was modified after freeing");
 	}
 }
 #endif
@@ -1042,8 +1102,10 @@
 		(size < BYTES_PER_WORD) ||
 		(size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
 		(dtor && !ctor) ||
-		(offset < 0 || offset > size))
+		(offset < 0 || offset > size)) {
+			printk("%sEarly error in slab %s\n", func_nm, name);
 			BUG();
+		}
 
 #if DEBUG
 	WARN_ON(strchr(name, ' '));	/* It confuses parsers */
@@ -1094,7 +1156,6 @@
 	if (size & (BYTES_PER_WORD-1)) {
 		size += (BYTES_PER_WORD-1);
 		size &= ~(BYTES_PER_WORD-1);
-		printk("%sForcing size word alignment - %s\n", func_nm, name);
 	}
 	
 #if DEBUG
@@ -1181,7 +1242,8 @@
 		cachep = NULL;
 		goto opps;
 	}
-	slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab));
+	slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t) +
+			sizeof(struct slab));
 
 	/*
 	 * If the slab has been placed off-slab, and we have enough space then
@@ -1225,10 +1287,13 @@
 			 * the cache that's used by kmalloc(24), otherwise
 			 * the creation of further caches will BUG().
 			 */
-			cachep->array[smp_processor_id()] = &initarray_generic.cache;
+			cachep->array[smp_processor_id()] =
+					&initarray_generic.cache;
 			g_cpucache_up = PARTIAL;
 		} else {
-			cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL);
+			cachep->array[smp_processor_id()] =
+				kmalloc(sizeof(struct arraycache_init),
+					GFP_KERNEL);
 		}
 		BUG_ON(!ac_data(cachep));
 		ac_data(cachep)->avail = 0;
@@ -1242,7 +1307,7 @@
 	} 
 
 	cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 +
-					((unsigned long)cachep)%REAPTIMEOUT_LIST3;
+				((unsigned long)cachep)%REAPTIMEOUT_LIST3;
 
 	/* Need the semaphore to access the chain. */
 	down(&cache_chain_sem);
@@ -1255,16 +1320,24 @@
 		list_for_each(p, &cache_chain) {
 			kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
 			char tmp;
-			/* This happens when the module gets unloaded and doesn't
-			   destroy its slab cache and noone else reuses the vmalloc
-			   area of the module. Print a warning. */
-			if (__get_user(tmp,pc->name)) { 
-				printk("SLAB: cache with size %d has lost its name\n", 
-					pc->objsize); 
+
+			/*
+			 * This happens when the module gets unloaded and
+			 * doesn't destroy its slab cache and noone else reuses
+			 * the vmalloc area of the module. Print a warning.
+			 */
+#ifdef CONFIG_X86_UACCESS_INDIRECT
+			if (__direct_get_user(tmp,pc->name)) {
+#else
+			if (__get_user(tmp,pc->name)) {
+#endif
+				printk("SLAB: cache with size %d has lost its "
+						"name\n", pc->objsize);
 				continue; 
 			} 	
 			if (!strcmp(pc->name,name)) { 
-				printk("kmem_cache_create: duplicate cache %s\n",name); 
+				printk("kmem_cache_create: duplicate "
+						"cache %s\n",name);
 				up(&cache_chain_sem); 
 				BUG(); 
 			}	
@@ -1321,7 +1394,6 @@
 	preempt_enable();
 }
 
-static void free_block (kmem_cache_t* cachep, void** objpp, int len);
 static void drain_array_locked(kmem_cache_t* cachep,
 				struct array_cache *ac, int force);
 
@@ -1442,6 +1514,9 @@
 		return 1;
 	}
 
+	/* no cpu_online check required here since we clear the percpu
+	 * array on cpu offline and set this to NULL.
+	 */
 	for (i = 0; i < NR_CPUS; i++)
 		kfree(cachep->array[i]);
 
@@ -1493,7 +1568,7 @@
 #if DEBUG
 		/* need to poison the objs? */
 		if (cachep->flags & SLAB_POISON)
-			poison_obj(cachep, objp, POISON_BEFORE);
+			poison_obj(cachep, objp, POISON_FREE);
 		if (cachep->flags & SLAB_STORE_USER)
 			*dbg_userword(cachep, objp) = NULL;
 
@@ -1712,13 +1787,13 @@
 	if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
 		if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) {
-			store_stackinfo(cachep, objp, POISON_AFTER);
+			store_stackinfo(cachep, objp, (unsigned long)caller);
 	       		kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0);
 		} else {
-			poison_obj(cachep, objp, POISON_AFTER);
+			poison_obj(cachep, objp, POISON_FREE);
 		}
 #else
-		poison_obj(cachep, objp, POISON_AFTER);
+		poison_obj(cachep, objp, POISON_FREE);
 #endif
 	}
 #endif
@@ -1875,7 +1950,7 @@
 #else
 		check_poison_obj(cachep, objp);
 #endif
-		poison_obj(cachep, objp, POISON_BEFORE);
+		poison_obj(cachep, objp, POISON_INUSE);
 	}
 	if (cachep->flags & SLAB_STORE_USER)
 		*dbg_userword(cachep, objp) = caller;
@@ -1890,6 +1965,15 @@
 		*dbg_redzone1(cachep, objp) = RED_ACTIVE;
 		*dbg_redzone2(cachep, objp) = RED_ACTIVE;
 	}
+	{
+		int objnr;
+		struct slab *slabp;
+
+		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+
+		objnr = (objp - slabp->s_mem) / cachep->objsize;
+		slab_bufctl(slabp)[objnr] = (int)caller;
+	}
 	objp += obj_dbghead(cachep);
 	if (cachep->ctor && cachep->flags & SLAB_POISON) {
 		unsigned long	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -1951,12 +2035,14 @@
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
 		check_slabp(cachep, slabp);
 #if DEBUG
+#if 0
 		if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
 			printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n",
 						cachep->name, objp);
 			BUG();
 		}
 #endif
+#endif
 		slab_bufctl(slabp)[objnr] = slabp->free;
 		slabp->free = objnr;
 		STATS_DEC_ACTIVE(cachep);
@@ -2554,17 +2640,19 @@
 }
 
 /*
- * This is a timer handler.  There is on per CPU.  It is called periodially
+ * This is a timer handler.  There is one per CPU.  It is called periodially
  * to shrink this CPU's caches.  Otherwise there could be memory tied up
  * for long periods (or for ever) due to load changes.
  */
-static void reap_timer_fnc(unsigned long data)
+static void reap_timer_fnc(unsigned long cpu)
 {
-	int cpu = smp_processor_id();
 	struct timer_list *rt = &__get_cpu_var(reap_timers);
 
-	cache_reap();
-	mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu);
+	/* CPU hotplug can drag us off cpu: don't run on wrong CPU */
+	if (!cpu_is_offline(cpu)) {
+		cache_reap();
+		mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu);
+	}
 }
 
 #ifdef CONFIG_PROC_FS
@@ -2735,6 +2823,29 @@
 	.show	= s_show,
 };
 
+static void do_dump_slabp(kmem_cache_t *cachep)
+{
+#if DEBUG
+	struct list_head *q;
+
+	check_irq_on();
+	spin_lock_irq(&cachep->spinlock);
+	list_for_each(q,&cachep->lists.slabs_full) {
+		struct slab *slabp;
+		int i;
+		slabp = list_entry(q, struct slab, list);
+		for (i = 0; i < cachep->num; i++) {
+			unsigned long sym = slab_bufctl(slabp)[i];
+
+			printk("obj %p/%d: %p", slabp, i, (void *)sym);
+			print_symbol(" <%s>", sym);
+			printk("\n");
+		}
+	}
+	spin_unlock_irq(&cachep->spinlock);
+#endif
+}
+
 #define MAX_SLABINFO_WRITE 128
 /**
  * slabinfo_write - Tuning for the slab allocator
@@ -2775,9 +2886,11 @@
 			    batchcount < 1 ||
 			    batchcount > limit ||
 			    shared < 0) {
-				res = -EINVAL;
+				do_dump_slabp(cachep);
+				res = 0;
 			} else {
-				res = do_tune_cpucache(cachep, limit, batchcount, shared);
+				res = do_tune_cpucache(cachep, limit,
+							batchcount, shared);
 			}
 			break;
 		}
@@ -2866,14 +2979,7 @@
 			kernel_map_pages(virt_to_page(objp),
 					c->objsize/PAGE_SIZE, 1);
 
-			if (c->flags & SLAB_RED_ZONE)
-				printk("redzone: 0x%lx/0x%lx.\n",
-					*dbg_redzone1(c, objp),
-					*dbg_redzone2(c, objp));
-
-			if (c->flags & SLAB_STORE_USER)
-				printk("Last user: %p.\n",
-					*dbg_userword(c, objp));
+			print_objinfo(c, objp, 2);
 		}
 		spin_unlock_irqrestore(&c->spinlock, flags);
 
--- diff/mm/swap.c	2004-01-19 10:22:59.000000000 +0000
+++ source/mm/swap.c	2004-02-18 09:04:03.000000000 +0000
@@ -27,6 +27,9 @@
 #include <linux/module.h>
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
 
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
@@ -381,7 +384,37 @@
 	preempt_enable();
 }
 EXPORT_SYMBOL(vm_acct_memory);
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void lru_drain_cache(unsigned int cpu)
+{
+	struct pagevec *pvec = &per_cpu(lru_add_pvecs, cpu);
+
+	/* CPU is dead, so no locking needed. */
+	if (pagevec_count(pvec))
+		__pagevec_lru_add(pvec);
+	pvec = &per_cpu(lru_add_active_pvecs, cpu);
+	if (pagevec_count(pvec))
+		__pagevec_lru_add_active(pvec);
+}
+
+/* Drop the CPU's cached committed space back into the central pool. */
+static int cpu_swap_callback(struct notifier_block *nfb,
+			     unsigned long action,
+			     void *hcpu)
+{
+	long *committed;
+
+	committed = &per_cpu(committed_space, (long)hcpu);
+	if (action == CPU_DEAD) {
+		atomic_add(*committed, &vm_committed_space);
+		*committed = 0;
+		lru_drain_cache((long)hcpu);
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_SMP
 void percpu_counter_mod(struct percpu_counter *fbc, long amount)
@@ -420,4 +453,5 @@
 	 * Right now other parts of the system means that we
 	 * _really_ don't want to cluster much more
 	 */
+	hotcpu_notifier(cpu_swap_callback, 0);
 }
--- diff/mm/swap_state.c	2003-08-20 14:16:34.000000000 +0100
+++ source/mm/swap_state.c	2004-02-18 09:04:03.000000000 +0000
@@ -38,6 +38,7 @@
 	.truncate_count  = ATOMIC_INIT(0),
 	.private_lock	= SPIN_LOCK_UNLOCKED,
 	.private_list	= LIST_HEAD_INIT(swapper_space.private_list),
+	.wb_rwsema	= __RWSEM_INITIALIZER(swapper_space.wb_rwsema)
 };
 
 #define INC_CACHE_INFO(x)	do { swap_cache_info.x++; } while (0)
--- diff/mm/swapfile.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/swapfile.c	2004-02-18 09:04:03.000000000 +0000
@@ -387,7 +387,7 @@
 unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir,
 	swp_entry_t entry, struct page *page, struct pte_chain **pte_chainp)
 {
-	vma->vm_mm->rss++;
+	inc_rss(vma->vm_mm, page);
 	get_page(page);
 	set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
 	*pte_chainp = page_add_rmap(page, dir, *pte_chainp);
--- diff/mm/truncate.c	2003-10-09 09:47:34.000000000 +0100
+++ source/mm/truncate.c	2004-02-18 09:04:03.000000000 +0000
@@ -174,6 +174,14 @@
 		}
 		pagevec_release(&pvec);
 	}
+
+	if (lstart == 0) {
+		WARN_ON(mapping->nrpages);
+		WARN_ON(!list_empty(&mapping->clean_pages));
+		WARN_ON(!list_empty(&mapping->dirty_pages));
+		WARN_ON(!list_empty(&mapping->locked_pages));
+		WARN_ON(!list_empty(&mapping->io_pages));
+	}
 }
 
 EXPORT_SYMBOL(truncate_inode_pages);
--- diff/mm/vmscan.c	2004-02-18 08:54:13.000000000 +0000
+++ source/mm/vmscan.c	2004-02-18 09:04:03.000000000 +0000
@@ -30,6 +30,8 @@
 #include <linux/backing-dev.h>
 #include <linux/rmap-locking.h>
 #include <linux/topology.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -43,14 +45,15 @@
 int vm_swappiness = 60;
 static long total_memory;
 
+#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
+
 #ifdef ARCH_HAS_PREFETCH
 #define prefetch_prev_lru_page(_page, _base, _field)			\
 	do {								\
 		if ((_page)->lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page->lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&(_page)->lru);		\
 			prefetch(&prev->_field);			\
 		}							\
 	} while (0)
@@ -64,8 +67,7 @@
 		if ((_page)->lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page->lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&(_page)->lru);		\
 			prefetchw(&prev->_field);			\
 		}							\
 	} while (0)
@@ -135,7 +137,7 @@
  *
  * We do weird things to avoid (scanned*seeks*entries) overflowing 32 bits.
  */
-static int shrink_slab(long scanned, unsigned int gfp_mask)
+static int shrink_slab(unsigned long scanned, unsigned int gfp_mask)
 {
 	struct shrinker *shrinker;
 	long pages;
@@ -147,7 +149,7 @@
 	list_for_each_entry(shrinker, &shrinker_list, list) {
 		unsigned long long delta;
 
-		delta = 4 * (scanned / shrinker->seeks);
+		delta = 4 * scanned / shrinker->seeks;
 		delta *= (*shrinker->shrinker)(0, gfp_mask);
 		do_div(delta, pages + 1);
 		shrinker->nr += delta;
@@ -243,8 +245,7 @@
  * shrink_list returns the number of reclaimed pages
  */
 static int
-shrink_list(struct list_head *page_list, unsigned int gfp_mask,
-		int *max_scan, int *nr_mapped)
+shrink_list(struct list_head *page_list, unsigned int gfp_mask, int *nr_mapped)
 {
 	struct address_space *mapping;
 	LIST_HEAD(ret_pages);
@@ -260,7 +261,7 @@
 		int may_enter_fs;
 		int referenced;
 
-		page = list_entry(page_list->prev, struct page, lru);
+		page = lru_to_page(page_list);
 		list_del(&page->lru);
 
 		if (TestSetPageLocked(page))
@@ -479,13 +480,15 @@
  */
 static int
 shrink_cache(const int nr_pages, struct zone *zone,
-		unsigned int gfp_mask, int max_scan, int *nr_mapped)
+		unsigned int gfp_mask, int max_scan, int *nr_scanned)
 {
 	LIST_HEAD(page_list);
 	struct pagevec pvec;
 	int nr_to_process;
 	int ret = 0;
 
+	*nr_scanned = 0;
+
 	/*
 	 * Try to ensure that we free `nr_pages' pages in one pass of the loop.
 	 */
@@ -496,8 +499,9 @@
 	pagevec_init(&pvec, 1);
 
 	lru_add_drain();
+again:
 	spin_lock_irq(&zone->lru_lock);
-	while (max_scan > 0 && ret < nr_pages) {
+	while (*nr_scanned < max_scan && ret < nr_pages) {
 		struct page *page;
 		int nr_taken = 0;
 		int nr_scan = 0;
@@ -505,8 +509,7 @@
 
 		while (nr_scan++ < nr_to_process &&
 				!list_empty(&zone->inactive_list)) {
-			page = list_entry(zone->inactive_list.prev,
-						struct page, lru);
+			page = lru_to_page(&zone->inactive_list);
 
 			prefetchw_prev_lru_page(page,
 						&zone->inactive_list, flags);
@@ -528,23 +531,24 @@
 		zone->pages_scanned += nr_taken;
 		spin_unlock_irq(&zone->lru_lock);
 
+		*nr_scanned += nr_scan;
 		if (nr_taken == 0)
-			goto done;
+			goto again;
 
-		max_scan -= nr_scan;
 		mod_page_state(pgscan, nr_scan);
-		nr_freed = shrink_list(&page_list, gfp_mask,
-					&max_scan, nr_mapped);
+		nr_freed = shrink_list(&page_list, gfp_mask, nr_scanned);
 		ret += nr_freed;
+
 		if (nr_freed <= 0 && list_empty(&page_list))
-			goto done;
+			goto again;
 
 		spin_lock_irq(&zone->lru_lock);
+
 		/*
 		 * Put back any unfreeable pages.
 		 */
 		while (!list_empty(&page_list)) {
-			page = list_entry(page_list.prev, struct page, lru);
+			page = lru_to_page(&page_list);
 			if (TestSetPageLRU(page))
 				BUG();
 			list_del(&page->lru);
@@ -560,11 +564,42 @@
 		}
   	}
 	spin_unlock_irq(&zone->lru_lock);
-done:
 	pagevec_release(&pvec);
 	return ret;
 }
 
+
+/* move pages from @page_list to the @spot, that should be somewhere on the
+ * @zone->active_list */
+static int
+spill_on_spot(struct zone *zone, struct list_head *page_list,
+		struct list_head *spot, struct pagevec *pvec)
+{
+	struct page *page;
+	int          moved;
+
+	moved = 0;
+	while (!list_empty(page_list)) {
+		page = lru_to_page(page_list);
+		prefetchw_prev_lru_page(page, page_list, flags);
+		if (TestSetPageLRU(page))
+			BUG();
+		BUG_ON(!PageActive(page));
+		list_move(&page->lru, spot);
+		moved++;
+		if (!pagevec_add(pvec, page)) {
+			zone->nr_active += moved;
+			moved = 0;
+			spin_unlock_irq(&zone->lru_lock);
+			__pagevec_release(pvec);
+			spin_lock_irq(&zone->lru_lock);
+		}
+	}
+	return moved;
+}
+
+
+
 /*
  * This moves pages from the active list to the inactive list.
  *
@@ -584,44 +619,25 @@
  */
 static void
 refill_inactive_zone(struct zone *zone, const int nr_pages_in,
-			struct page_state *ps, int priority)
+			struct page_state *ps)
 {
 	int pgmoved;
 	int pgdeactivate = 0;
 	int nr_pages = nr_pages_in;
 	LIST_HEAD(l_hold);	/* The pages which were snipped off */
 	LIST_HEAD(l_inactive);	/* Pages to go onto the inactive_list */
-	LIST_HEAD(l_active);	/* Pages to go onto the active_list */
+	LIST_HEAD(l_ignore);	/* Pages to be returned to the active_list */
+	LIST_HEAD(l_active);	/* Pages to go onto the head of the
+				 * active_list */
+
 	struct page *page;
+	struct page *scan;
 	struct pagevec pvec;
 	int reclaim_mapped = 0;
 	long mapped_ratio;
 	long distress;
 	long swap_tendency;
 
-	lru_add_drain();
-	pgmoved = 0;
-	spin_lock_irq(&zone->lru_lock);
-	while (nr_pages && !list_empty(&zone->active_list)) {
-		page = list_entry(zone->active_list.prev, struct page, lru);
-		prefetchw_prev_lru_page(page, &zone->active_list, flags);
-		if (!TestClearPageLRU(page))
-			BUG();
-		list_del(&page->lru);
-		if (page_count(page) == 0) {
-			/* It is currently in pagevec_release() */
-			SetPageLRU(page);
-			list_add(&page->lru, &zone->active_list);
-		} else {
-			page_cache_get(page);
-			list_add(&page->lru, &l_hold);
-			pgmoved++;
-		}
-		nr_pages--;
-	}
-	zone->nr_active -= pgmoved;
-	spin_unlock_irq(&zone->lru_lock);
-
 	/*
 	 * `distress' is a measure of how much trouble we're having reclaiming
 	 * pages.  0 -> no problems.  100 -> great trouble.
@@ -653,10 +669,63 @@
 	if (swap_tendency >= 100)
 		reclaim_mapped = 1;
 
+	scan = zone->scan_page;
+	lru_add_drain();
+	pgmoved = 0;
+	spin_lock_irq(&zone->lru_lock);
+	if (reclaim_mapped) {
+		/*
+		 * When scanning active_list with !reclaim_mapped mapped
+		 * inactive pages are left behind zone->scan_page. If zone is
+		 * switched to reclaim_mapped mode reset zone->scan_page to
+		 * the end of inactive list so that inactive mapped pages are
+		 * re-scanned.
+		 */
+		list_move_tail(&scan->lru, &zone->active_list);
+	}
+	while (nr_pages && zone->active_list.prev != zone->active_list.next) {
+		/*
+		 * if head of active list reached---wrap to the tail
+		 */
+		if (scan->lru.prev == &zone->active_list)
+			list_move_tail(&scan->lru, &zone->active_list);
+		page = lru_to_page(&scan->lru);
+		prefetchw_prev_lru_page(page, &zone->active_list, flags);
+		if (!TestClearPageLRU(page))
+			BUG();
+		list_del(&page->lru);
+		if (page_count(page) == 0) {
+			/* It is currently in pagevec_release() */
+			SetPageLRU(page);
+			list_add(&page->lru, &zone->active_list);
+		} else {
+			page_cache_get(page);
+			list_add(&page->lru, &l_hold);
+			pgmoved++;
+		}
+		nr_pages--;
+	}
+	zone->nr_active -= pgmoved;
+	spin_unlock_irq(&zone->lru_lock);
+
 	while (!list_empty(&l_hold)) {
-		page = list_entry(l_hold.prev, struct page, lru);
+		page = lru_to_page(&l_hold);
 		list_del(&page->lru);
 		if (page_mapped(page)) {
+
+			/*
+			 * Don't clear page referenced if we're not going
+			 * to use it.
+			 */
+			if (!reclaim_mapped) {
+				list_add(&page->lru, &l_ignore);
+				continue;
+			}
+
+			/*
+			 * probably it would be useful to transfer dirty bit
+			 * from pte to the @page here.
+			 */
 			pte_chain_lock(page);
 			if (page_mapped(page) && page_referenced(page)) {
 				pte_chain_unlock(page);
@@ -664,10 +733,6 @@
 				continue;
 			}
 			pte_chain_unlock(page);
-			if (!reclaim_mapped) {
-				list_add(&page->lru, &l_active);
-				continue;
-			}
 		}
 		/*
 		 * FIXME: need to consider page_count(page) here if/when we
@@ -685,7 +750,7 @@
 	pgmoved = 0;
 	spin_lock_irq(&zone->lru_lock);
 	while (!list_empty(&l_inactive)) {
-		page = list_entry(l_inactive.prev, struct page, lru);
+		page = lru_to_page(&l_inactive);
 		prefetchw_prev_lru_page(page, &l_inactive, flags);
 		if (TestSetPageLRU(page))
 			BUG();
@@ -712,23 +777,9 @@
 		spin_lock_irq(&zone->lru_lock);
 	}
 
-	pgmoved = 0;
-	while (!list_empty(&l_active)) {
-		page = list_entry(l_active.prev, struct page, lru);
-		prefetchw_prev_lru_page(page, &l_active, flags);
-		if (TestSetPageLRU(page))
-			BUG();
-		BUG_ON(!PageActive(page));
-		list_move(&page->lru, &zone->active_list);
-		pgmoved++;
-		if (!pagevec_add(&pvec, page)) {
+	pgmoved = spill_on_spot(zone, &l_active, &zone->active_list, &pvec);
 			zone->nr_active += pgmoved;
-			pgmoved = 0;
-			spin_unlock_irq(&zone->lru_lock);
-			__pagevec_release(&pvec);
-			spin_lock_irq(&zone->lru_lock);
-		}
-	}
+	pgmoved = spill_on_spot(zone, &l_ignore, &scan->lru, &pvec);
 	zone->nr_active += pgmoved;
 	spin_unlock_irq(&zone->lru_lock);
 	pagevec_release(&pvec);
@@ -743,41 +794,49 @@
  * direct reclaim.
  */
 static int
-shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask,
-	const int nr_pages, int *nr_mapped, struct page_state *ps, int priority)
+shrink_zone(struct zone *zone, unsigned int gfp_mask,
+	int nr_pages, int *nr_scanned, struct page_state *ps, int priority)
 {
-	unsigned long ratio;
+	unsigned long imbalance;
+	unsigned long nr_refill_inact;
+	unsigned long max_scan;
 
 	/*
 	 * Try to keep the active list 2/3 of the size of the cache.  And
 	 * make sure that refill_inactive is given a decent number of pages.
 	 *
-	 * The "ratio+1" here is important.  With pagecache-intensive workloads
-	 * the inactive list is huge, and `ratio' evaluates to zero all the
-	 * time.  Which pins the active list memory.  So we add one to `ratio'
-	 * just to make sure that the kernel will slowly sift through the
-	 * active list.
+	 * Keeping imbalance > 0 is important.  With pagecache-intensive loads
+	 * the inactive list is huge, and imbalance evaluates to zero all the
+	 * time which would pin the active list memory.
 	 */
-	ratio = (unsigned long)nr_pages * zone->nr_active /
-				((zone->nr_inactive | 1) * 2);
-	atomic_add(ratio+1, &zone->refill_counter);
-	if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) {
-		int count;
+	if (zone->nr_active >= zone->nr_inactive * 4) {
+		/* ratio will be >= 2 */
+		imbalance = 8*nr_pages;
+	} else if (zone->nr_active >= zone->nr_inactive * 2) {
+		/* 1 < ratio < 2 */
+		imbalance = 4 * nr_pages*zone->nr_active /
+				(zone->nr_inactive * 2 + 1);
+	} else {
+		imbalance = nr_pages / 2;
+	}
 
-		/*
-		 * Don't try to bring down too many pages in one attempt.
-		 * If this fails, the caller will increase `priority' and
-		 * we'll try again, with an increased chance of reclaiming
-		 * mapped memory.
-		 */
-		count = atomic_read(&zone->refill_counter);
-		if (count > SWAP_CLUSTER_MAX * 4)
-			count = SWAP_CLUSTER_MAX * 4;
-		atomic_set(&zone->refill_counter, 0);
-		refill_inactive_zone(zone, count, ps, priority);
+	imbalance++;
+
+	nr_refill_inact = atomic_read(&zone->refill_counter) + imbalance;
+	if (nr_refill_inact > SWAP_CLUSTER_MAX) {
+		refill_inactive_zone(zone, nr_refill_inact, ps);
+		nr_refill_inact = 0;
 	}
-	return shrink_cache(nr_pages, zone, gfp_mask,
-				max_scan, nr_mapped);
+	atomic_set(&zone->refill_counter, nr_refill_inact);
+
+	/*
+	 * Now pull pages from the inactive list
+	 */
+	max_scan = zone->nr_inactive >> priority;
+	if (max_scan < nr_pages * 2)
+		max_scan = nr_pages * 2;
+
+	return shrink_cache(nr_pages, zone, gfp_mask, max_scan, nr_scanned);
 }
 
 /*
@@ -806,8 +865,7 @@
 	for (i = 0; zones[i] != NULL; i++) {
 		int to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX);
 		struct zone *zone = zones[i];
-		int nr_mapped = 0;
-		int max_scan;
+		int nr_scanned;
 
 		if (zone->free_pages < zone->pages_high)
 			zone->temp_priority = priority;
@@ -815,16 +873,9 @@
 		if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 			continue;	/* Let kswapd poll it */
 
-		/*
-		 * If we cannot reclaim `nr_pages' pages by scanning twice
-		 * that many pages then fall back to the next zone.
-		 */
-		max_scan = zone->nr_inactive >> priority;
-		if (max_scan < to_reclaim * 2)
-			max_scan = to_reclaim * 2;
-		ret += shrink_zone(zone, max_scan, gfp_mask,
-				to_reclaim, &nr_mapped, ps, priority);
-		*total_scanned += max_scan + nr_mapped;
+		ret += shrink_zone(zone, gfp_mask,
+				to_reclaim, &nr_scanned, ps, priority);
+		*total_scanned += nr_scanned;
 		if (ret >= nr_pages)
 			break;
 	}
@@ -870,31 +921,44 @@
 		get_page_state(&ps);
 		nr_reclaimed += shrink_caches(zones, priority, &total_scanned,
 						gfp_mask, nr_pages, &ps);
+
+		if (zones[0] - zones[0]->zone_pgdat->node_zones < ZONE_HIGHMEM) {
+			shrink_slab(total_scanned, gfp_mask);
+			if (reclaim_state) {
+				nr_reclaimed += reclaim_state->reclaimed_slab;
+				reclaim_state->reclaimed_slab = 0;
+			}
+		}
+
 		if (nr_reclaimed >= nr_pages) {
 			ret = 1;
+			if (gfp_mask & __GFP_FS)
+				wakeup_bdflush(total_scanned);
 			goto out;
 		}
+
+		/* Don't stall on the first run - it might be bad luck */
+		if (likely(priority == DEF_PRIORITY))
+			continue;
+
+		/* Let the caller handle it */
 		if (!(gfp_mask & __GFP_FS))
-			break;		/* Let the caller handle it */
+			goto out;
+
 		/*
-		 * Try to write back as many pages as we just scanned.  Not
-		 * sure if that makes sense, but it's an attempt to avoid
-		 * creating IO storms unnecessarily
+		 * Try to write back as many pages as we just scanned.
+		 * Not sure if that makes sense, but it's an attempt
+		 * to avoid creating IO storms unnecessarily
 		 */
 		wakeup_bdflush(total_scanned);
 
 		/* Take a nap, wait for some writeback to complete */
 		blk_congestion_wait(WRITE, HZ/10);
-		if (zones[0] - zones[0]->zone_pgdat->node_zones < ZONE_HIGHMEM) {
-			shrink_slab(total_scanned, gfp_mask);
-			if (reclaim_state) {
-				nr_reclaimed += reclaim_state->reclaimed_slab;
-				reclaim_state->reclaimed_slab = 0;
-			}
-		}
 	}
-	if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY))
+
+	if (!(gfp_mask & __GFP_NORETRY))
 		out_of_memory();
+
 out:
 	for (i = 0; zones[i] != 0; i++)
 		zones[i]->prev_priority = zones[i]->temp_priority;
@@ -939,42 +1003,45 @@
 
 		for (i = 0; i < pgdat->nr_zones; i++) {
 			struct zone *zone = pgdat->node_zones + i;
-			int nr_mapped = 0;
-			int max_scan;
+			int nr_scanned;
 			int to_reclaim;
+			int reclaimed;
 
 			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 				continue;
 
-			if (nr_pages && to_free > 0) {	/* Software suspend */
+			if (nr_pages) {		/* Software suspend */
 				to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8);
-			} else {			/* Zone balancing */
+			} else {		/* Zone balancing */
 				to_reclaim = zone->pages_high-zone->free_pages;
 				if (to_reclaim <= 0)
 					continue;
 			}
-			zone->temp_priority = priority;
 			all_zones_ok = 0;
-			max_scan = zone->nr_inactive >> priority;
-			if (max_scan < to_reclaim * 2)
-				max_scan = to_reclaim * 2;
-			if (max_scan < SWAP_CLUSTER_MAX)
-				max_scan = SWAP_CLUSTER_MAX;
-			to_free -= shrink_zone(zone, max_scan, GFP_KERNEL,
-					to_reclaim, &nr_mapped, ps, priority);
+			zone->temp_priority = priority;
+			reclaimed = shrink_zone(zone, GFP_KERNEL,
+					to_reclaim, &nr_scanned, ps, priority);
 			if (i < ZONE_HIGHMEM) {
 				reclaim_state->reclaimed_slab = 0;
-				shrink_slab(max_scan + nr_mapped, GFP_KERNEL);
-				to_free -= reclaim_state->reclaimed_slab;
+				shrink_slab(nr_scanned, GFP_KERNEL);
+				reclaimed += reclaim_state->reclaimed_slab;
 			}
+			to_free -= reclaimed;
 			if (zone->all_unreclaimable)
 				continue;
 			if (zone->pages_scanned > zone->present_pages * 2)
 				zone->all_unreclaimable = 1;
 		}
+		if (nr_pages && to_free > 0)
+			continue;	/* swsusp: need to do more work */
 		if (all_zones_ok)
-			break;
-		if (to_free > 0)
+			break;		/* kswapd: all done */
+		/*
+		 * OK, kswapd is getting into trouble.  Take a nap, then take
+		 * another pass across the zones. Don't stall on the first
+		 * pass.
+		 */
+		if (priority < DEF_PRIORITY)
 			blk_congestion_wait(WRITE, HZ/10);
 	}
 
@@ -1085,13 +1152,39 @@
 }
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* It's optimal to keep kswapds on the same CPUs as their memory, but
+   not required for correctness.  So if the last cpu in a node goes
+   away, we get changed to run anywhere: as the first one comes back,
+   restore their cpu bindings. */
+static int __devinit cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	pg_data_t *pgdat;
+	cpumask_t mask;
+
+	if (action == CPU_ONLINE) {
+		for_each_pgdat(pgdat) {
+			mask = node_to_cpumask(pgdat->node_id);
+			if (any_online_cpu(mask) != NR_CPUS)
+				/* One of our CPUs online: restore mask */
+				set_cpus_allowed(pgdat->kswapd, mask);
+		}
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
 	swap_setup();
 	for_each_pgdat(pgdat)
-		kernel_thread(kswapd, pgdat, CLONE_KERNEL);
+		pgdat->kswapd
+		= find_task_by_pid(kernel_thread(kswapd, pgdat, CLONE_KERNEL));
 	total_memory = nr_free_pagecache_pages();
+	hotcpu_notifier(cpu_callback, 0);
 	return 0;
 }
 
--- diff/net/8021q/vlan.c	2003-10-09 09:47:34.000000000 +0100
+++ source/net/8021q/vlan.c	2004-02-18 09:04:03.000000000 +0000
@@ -566,7 +566,7 @@
 	goto out_put_dev;
 
 out_free_newdev:
-	kfree(new_dev);
+	free_netdev(new_dev);
 
 out_unlock:
 	rtnl_unlock();
--- diff/net/Kconfig	2004-02-18 08:54:13.000000000 +0000
+++ source/net/Kconfig	2004-02-18 09:04:03.000000000 +0000
@@ -32,8 +32,7 @@
 	  to work, choose Y.
 
 	  To compile this driver as a module, choose M here: the module will
-	  be called af_packet. If you use modprobe or kmod, you may also
-	  want to add "alias net-pf-17 af_packet" to /etc/modules.conf.
+	  be called af_packet.
 
 	  If unsure, say Y.
 
@@ -67,11 +66,8 @@
 	  want to say Y here.
 
 	  To compile this driver as a module, choose M here: the module will be
-	  called unix.  If you try building this as a module and you have
-	  said Y to "Kernel module loader support" above, be sure to add
-	  'alias net-pf-1 unix' to your /etc/modules.conf file. Note that
-	  several important services won't work correctly if you say M here
-	  and then neglect to load the module.
+	  called unix.  Note that several important services won't work
+	  correctly if you say M here and then neglect to load the module.
 
 	  Say Y unless you know what you are doing.
 
@@ -127,9 +123,7 @@
 	  in the kernel source.
 
 	  To compile this protocol support as a module, choose M here: the 
-	  module will be called ipv6.  If you try building this as a module 
-	  and you have said Y to "Kernel module loader support" above, 
-	  be sure to add 'alias net-pf-10 ipv6' to your /etc/modules.conf file.
+	  module will be called ipv6.
 
 	  It is safe to say N here for now.
 
@@ -664,4 +658,19 @@
 
 source "net/bluetooth/Kconfig"
 
+config KGDBOE
+	def_bool X86 && KGDB
+
+config NETPOLL
+	def_bool NETCONSOLE || KGDBOE
+
+config NETPOLL_RX
+	def_bool KGDBOE
+
+config NETPOLL_TRAP
+	def_bool KGDBOE
+
+config NET_POLL_CONTROLLER
+	def_bool NETPOLL
+
 endmenu
--- diff/net/atm/clip.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/atm/clip.c	2004-02-18 09:04:03.000000000 +0000
@@ -829,7 +829,7 @@
 	    !clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
 	    (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/HZ);
 
-	off = snprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", NIPQUAD(entry->ip));
+	off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", NIPQUAD(entry->ip));
 	while (off < 16)
 		buf[off++] = ' ';
 	buf[off] = '\0';
--- diff/net/atm/lec.c	2003-09-30 15:46:21.000000000 +0100
+++ source/net/atm/lec.c	2004-02-18 09:04:03.000000000 +0000
@@ -798,7 +798,7 @@
                         return -ENOMEM;
                 snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
                 if (register_netdev(dev_lec[i])) {
-                        kfree(dev_lec[i]);
+                        free_netdev(dev_lec[i]);
                         return -EINVAL;
                 }
 
--- diff/net/bluetooth/bnep/core.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/bluetooth/bnep/core.c	2004-02-18 09:04:03.000000000 +0000
@@ -501,7 +501,7 @@
 	__bnep_unlink_session(s);
 
 	up_write(&bnep_session_sem);
-	kfree(dev);
+	free_netdev(dev);
 	return 0;
 }
 
@@ -588,7 +588,7 @@
 
 failed:
 	up_write(&bnep_session_sem);
-	kfree(dev);
+	free_netdev(dev);
 	return err;
 }
 
--- diff/net/compat.c	2004-01-19 10:22:59.000000000 +0000
+++ source/net/compat.c	2004-02-18 09:04:03.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/file.h>
 #include <linux/icmpv6.h>
 #include <linux/socket.h>
+#include <linux/syscalls.h>
 #include <linux/filter.h>
 #include <linux/compat.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -304,9 +305,6 @@
 	__scm_destroy(scm);
 }
 
-extern asmlinkage long sys_setsockopt(int fd, int level, int optname,
-				     char *optval, int optlen);
-
 /*
  * For now, we assume that the compatibility and native version
  * of struct ipt_entry are the same - sfr.  FIXME
@@ -471,9 +469,6 @@
 	return sys_setsockopt(fd, level, optname, optval, optlen);
 }
 
-extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
-				       void * optval, int *optlen);
-
 static int do_get_sock_timeout(int fd, int level, int optname, char *optval,
 		int *optlen)
 {
@@ -517,22 +512,6 @@
 				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
 #undef AL
 
-extern asmlinkage long sys_bind(int, struct sockaddr *, int);
-extern asmlinkage long sys_connect(int, struct sockaddr *, int);
-extern asmlinkage long sys_accept(int, struct sockaddr *, int *); 
-extern asmlinkage long sys_getsockname(int, struct sockaddr *, int *);
-extern asmlinkage long sys_getpeername(int, struct sockaddr *, int *);
-extern asmlinkage long sys_send(int, void *, size_t, unsigned);
-extern asmlinkage long sys_sendto(int, void *, size_t, unsigned,
-		struct sockaddr *, int);
-extern asmlinkage long sys_recv(int, void *, size_t, unsigned);
-extern asmlinkage long sys_recvfrom(int, void *, size_t, unsigned,
-		struct sockaddr *, int *);
-extern asmlinkage long sys_socket(int, int, int);
-extern asmlinkage long sys_socketpair(int, int, int, int [2]);
-extern asmlinkage long sys_shutdown(int, int);
-extern asmlinkage long sys_listen(int, int);
-
 asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags)
 {
 	return sys_sendmsg(fd, (struct msghdr *)msg, flags | MSG_CMSG_COMPAT);
--- diff/net/core/Makefile	2003-09-17 12:28:12.000000000 +0100
+++ source/net/core/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -13,3 +13,4 @@
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NET_RADIO) += wireless.o
+obj-$(CONFIG_NETPOLL) += netpoll.o
--- diff/net/core/dev.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/core/dev.c	2004-02-18 09:04:03.000000000 +0000
@@ -105,6 +105,8 @@
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/cpu.h>
+#include <linux/netpoll.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
 #include <net/iw_handler.h>
@@ -1547,7 +1549,6 @@
 }
 #endif
 
-
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1572,6 +1573,13 @@
 	struct softnet_data *queue;
 	unsigned long flags;
 
+#ifdef CONFIG_NETPOLL_RX
+	if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+#endif
+
 	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
@@ -1727,6 +1735,13 @@
 	int ret = NET_RX_DROP;
 	unsigned short type = skb->protocol;
 
+#ifdef CONFIG_NETPOLL_RX
+	if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+#endif
+
 	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
@@ -1851,7 +1866,6 @@
 	unsigned long start_time = jiffies;
 	int budget = netdev_max_backlog;
 
-	
 	preempt_disable();
 	local_irq_disable();
 
@@ -1878,6 +1892,10 @@
 			dev_put(dev);
 			local_irq_disable();
 		}
+
+#ifdef CONFIG_KGDBOE
+		kgdb_process_breakpoint();
+#endif
 	}
 out:
 	local_irq_enable();
@@ -3150,6 +3168,52 @@
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int dev_cpu_callback(struct notifier_block *nfb,
+			    unsigned long action,
+			    void *ocpu)
+{
+	struct sk_buff **list_skb;
+	struct net_device **list_net;
+	struct sk_buff *skb;
+	unsigned int cpu, oldcpu = (unsigned long)ocpu;
+	struct softnet_data *sd, *oldsd;
+
+	if (action != CPU_DEAD)
+		return NOTIFY_OK;
+
+	local_irq_disable();
+	cpu = smp_processor_id();
+	sd = &per_cpu(softnet_data, cpu);
+	oldsd = &per_cpu(softnet_data, oldcpu);
+
+	/* Find end of our completion_queue. */
+	list_skb = &sd->completion_queue;
+	while (*list_skb)
+		list_skb = &(*list_skb)->next;
+	/* Append completion queue from offline CPU. */
+	*list_skb = oldsd->completion_queue;
+	oldsd->completion_queue = NULL;
+
+	/* Find end of our output_queue. */
+	list_net = &sd->output_queue;
+	while (*list_net)
+		list_net = &(*list_net)->next_sched;
+	/* Append output queue from offline CPU. */
+	*list_net = oldsd->output_queue;
+	oldsd->output_queue = NULL;
+
+	raise_softirq_irqoff(NET_TX_SOFTIRQ);
+	local_irq_enable();
+
+	/* Process offline CPU's input_pkt_queue */
+	while ((skb = __skb_dequeue(&oldsd->input_pkt_queue)))
+		netif_rx(skb);
+
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 
 /*
  *	Initialize the DEV module. At boot time this walks the device list and
@@ -3220,6 +3284,7 @@
 #ifdef CONFIG_NET_SCHED
 	pktsched_init();
 #endif
+	hotcpu_notifier(dev_cpu_callback, 0);
 	rc = 0;
 out:
 	return rc;
--- diff/net/core/filter.c	2003-10-09 09:47:34.000000000 +0100
+++ source/net/core/filter.c	2004-02-18 09:04:03.000000000 +0000
@@ -332,7 +332,7 @@
 	struct sock_filter *ftest;
 	int pc;
 
-	if ((unsigned int)flen >= (~0U / sizeof(struct sock_filter)))
+	if (((unsigned int)flen >= (~0U / sizeof(struct sock_filter))) || flen == 0)
 		return -EINVAL;
 
 	/* check the filter code now */
--- diff/net/core/flow.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/core/flow.c	2004-02-18 09:04:03.000000000 +0000
@@ -326,6 +326,17 @@
 	tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int flow_cache_cpu(struct notifier_block *nfb,
+			  unsigned long action,
+			  void *hcpu)
+{
+	if (action == CPU_DEAD)
+		__flow_cache_shrink((unsigned long)hcpu, 0);
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init flow_cache_init(void)
 {
 	int i;
@@ -350,6 +361,7 @@
 	for_each_cpu(i)
 		flow_cache_cpu_prepare(i);
 
+	hotcpu_notifier(flow_cache_cpu, 0);
 	return 0;
 }
 
--- diff/net/ipv4/ip_gre.c	2003-11-25 15:24:59.000000000 +0000
+++ source/net/ipv4/ip_gre.c	2004-02-18 09:04:03.000000000 +0000
@@ -280,7 +280,7 @@
 	nt->parms = *parms;
 
 	if (register_netdevice(dev) < 0) {
-		kfree(dev);
+		free_netdev(dev);
 		goto failed;
 	}
 
@@ -1276,7 +1276,7 @@
 	return err;
 fail:
 	inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
-	kfree(ipgre_fb_tunnel_dev);
+	free_netdev(ipgre_fb_tunnel_dev);
 	goto out;
 }
 
--- diff/net/ipv4/ipconfig.c	2003-10-09 09:47:34.000000000 +0100
+++ source/net/ipv4/ipconfig.c	2004-02-18 09:04:03.000000000 +0000
@@ -1189,12 +1189,47 @@
 #endif /* CONFIG_PROC_FS */
 
 /*
+ *  Extract IP address from the parameter string if needed. Note that we
+ *  need to have root_server_addr set _before_ IPConfig gets called as it
+ *  can override it.
+ */
+u32 __init root_nfs_parse_addr(char *name)
+{
+	u32 addr;
+	int octets = 0;
+	char *cp, *cq;
+
+	cp = cq = name;
+	while (octets < 4) {
+		while (*cp >= '0' && *cp <= '9')
+			cp++;
+		if (cp == cq || cp - cq > 3)
+			break;
+		if (*cp == '.' || octets == 3)
+			octets++;
+		if (octets < 4)
+			cp++;
+		cq = cp;
+	}
+	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
+		if (*cp == ':')
+			*cp++ = '\0';
+		addr = in_aton(name);
+		strcpy(name, cp);
+	} else
+		addr = INADDR_NONE;
+
+	return addr;
+}
+
+/*
  *	IP Autoconfig dispatcher.
  */
 
 static int __init ip_auto_config(void)
 {
 	unsigned long jiff;
+	u32 addr;
 
 #ifdef CONFIG_PROC_FS
 	proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops);
@@ -1283,6 +1318,10 @@
 		ic_dev = ic_first_dev->dev;
 	}
 
+	addr = root_nfs_parse_addr(root_server_path);
+	if (root_server_addr == INADDR_NONE)
+		root_server_addr = addr;
+
 	/*
 	 * Use defaults whereever applicable.
 	 */
--- diff/net/ipv4/ipip.c	2003-10-27 09:20:44.000000000 +0000
+++ source/net/ipv4/ipip.c	2004-02-18 09:04:03.000000000 +0000
@@ -250,7 +250,7 @@
 	nt->parms = *parms;
 
 	if (register_netdevice(dev) < 0) {
-		kfree(dev);
+		free_netdev(dev);
 		goto failed;
 	}
 
@@ -899,7 +899,7 @@
 	return err;
  fail:
 	xfrm4_tunnel_deregister(&ipip_handler);
-	kfree(ipip_fb_tunnel_dev);
+	free_netdev(ipip_fb_tunnel_dev);
 	goto out;
 }
 
--- diff/net/ipv4/ipmr.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/ipv4/ipmr.c	2004-02-18 09:04:03.000000000 +0000
@@ -209,7 +209,7 @@
 		return NULL;
 
 	if (register_netdevice(dev)) {
-		kfree(dev);
+		free_netdev(dev);
 		return NULL;
 	}
 	dev->iflink = 0;
--- diff/net/ipv4/route.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/ipv4/route.c	2004-02-18 09:04:03.000000000 +0000
@@ -2717,6 +2717,16 @@
 #endif /* CONFIG_PROC_FS */
 #endif /* CONFIG_NET_CLS_ROUTE */
 
+static __initdata unsigned long rhash_entries;
+static int __init set_rhash_entries(char *str)
+{
+	if (!str)
+		return 0;
+	rhash_entries = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("rhash_entries=", set_rhash_entries);
+
 int __init ip_rt_init(void)
 {
 	int i, order, goal, rc = 0;
@@ -2743,7 +2753,10 @@
 		panic("IP: failed to allocate ip_dst_cache\n");
 
 	goal = num_physpages >> (26 - PAGE_SHIFT);
-
+	if (!rhash_entries)
+		goal = min(10, goal);
+	else
+		goal = (rhash_entries * sizeof(struct rt_hash_bucket)) >> PAGE_SHIFT;
 	for (order = 0; (1UL << order) < goal; order++)
 		/* NOTHING */;
 
--- diff/net/ipv4/tcp.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv4/tcp.c	2004-02-18 09:04:03.000000000 +0000
@@ -2570,6 +2570,16 @@
 extern void __skb_cb_too_small_for_tcp(int, int);
 extern void tcpdiag_init(void);
 
+static __initdata unsigned long thash_entries;
+static int __init set_thash_entries(char *str)
+{
+	if (!str)
+		return 0;
+	thash_entries = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("thash_entries=", set_thash_entries);
+
 void __init tcp_init(void)
 {
 	struct sk_buff *skb = NULL;
@@ -2611,6 +2621,10 @@
 	else
 		goal = num_physpages >> (23 - PAGE_SHIFT);
 
+	if (!thash_entries)
+		goal = min(10UL, goal);
+	else
+		goal = (thash_entries * sizeof(struct tcp_ehash_bucket)) >> PAGE_SHIFT;
 	for (order = 0; (1UL << order) < goal; order++)
 		;
 	do {
--- diff/net/ipv6/af_inet6.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/ipv6/af_inet6.c	2004-02-18 09:04:03.000000000 +0000
@@ -56,7 +56,7 @@
 #include <net/transp_v6.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
-#if CONFIG_IPV6_TUNNEL
+#ifdef CONFIG_IPV6_TUNNEL
 #include <net/ip6_tunnel.h>
 #endif
 
--- diff/net/ipv6/ip6_tunnel.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/ipv6/ip6_tunnel.c	2004-02-18 09:04:03.000000000 +0000
@@ -245,7 +245,7 @@
 	t->parms = *p;
 
 	if ((err = register_netdevice(dev)) < 0) {
-		kfree(dev);
+		free_netdev(dev);
 		return err;
 	}
 	dev_hold(dev);
@@ -1118,7 +1118,7 @@
 	ip6ip6_fb_tnl_dev->init = ip6ip6_fb_tnl_dev_init;
 
 	if ((err = register_netdev(ip6ip6_fb_tnl_dev))) {
-		kfree(ip6ip6_fb_tnl_dev);
+		free_netdev(ip6ip6_fb_tnl_dev);
 		goto fail;
 	}
 	return 0;
--- diff/net/ipv6/sit.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/ipv6/sit.c	2004-02-18 09:04:03.000000000 +0000
@@ -187,7 +187,7 @@
 	nt->parms = *parms;
 
 	if (register_netdevice(dev) < 0) {
-		kfree(dev);
+		free_netdev(dev);
 		goto failed;
 	}
 
@@ -840,6 +840,6 @@
 	return err;
  fail:
 	inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
-	kfree(ipip6_fb_tunnel_dev);
+	free_netdev(ipip6_fb_tunnel_dev);
 	goto out;
 }
--- diff/net/irda/irlan/irlan_common.c	2003-09-30 15:46:21.000000000 +0100
+++ source/net/irda/irlan/irlan_common.c	2004-02-18 09:04:03.000000000 +0000
@@ -224,7 +224,7 @@
 		IRDA_DEBUG(2, "%s(), register_netdev() failed!\n", 
 			   __FUNCTION__ );
 		self = NULL;
-		kfree(dev);
+		free_netdev(dev);
 	} else {
 		rtnl_lock();
 		list_add_rcu(&self->dev_list, &irlans);
--- diff/net/irda/irlan/irlan_eth.c	2003-08-26 10:00:54.000000000 +0100
+++ source/net/irda/irlan/irlan_eth.c	2004-02-18 09:04:03.000000000 +0000
@@ -60,7 +60,7 @@
 	dev->hard_start_xmit    = irlan_eth_xmit; 
 	dev->get_stats	        = irlan_eth_get_stats;
 	dev->set_multicast_list = irlan_eth_set_multicast_list;
-	dev->destructor		= (void (*)(struct net_device *)) kfree;
+	dev->destructor		= free_netdev;
 
 	SET_MODULE_OWNER(dev);
 
--- diff/net/lapb/lapb_iface.c	2003-09-17 12:28:12.000000000 +0100
+++ source/net/lapb/lapb_iface.c	2004-02-18 09:04:03.000000000 +0000
@@ -81,18 +81,14 @@
 	lapb_hold(lapb);
 }
 
-/*
- *	Convert the integer token used by the device driver into a pointer
- *	to a LAPB control structure.
- */
-static struct lapb_cb *__lapb_tokentostruct(void *token)
+static struct lapb_cb *__lapb_devtostruct(struct net_device *dev)
 {
 	struct list_head *entry;
 	struct lapb_cb *lapb, *use = NULL;
 
 	list_for_each(entry, &lapb_list) {
 		lapb = list_entry(entry, struct lapb_cb, node);
-		if (lapb->token == token) {
+		if (lapb->dev == dev) {
 			use = lapb;
 			break;
 		}
@@ -104,12 +100,12 @@
 	return use;
 }
 
-static struct lapb_cb *lapb_tokentostruct(void *token)
+static struct lapb_cb *lapb_devtostruct(struct net_device *dev)
 {
 	struct lapb_cb *rc;
 
 	read_lock_bh(&lapb_list_lock);
-	rc = __lapb_tokentostruct(token);
+	rc = __lapb_devtostruct(dev);
 	read_unlock_bh(&lapb_list_lock);
 
 	return rc;
@@ -144,14 +140,14 @@
 	return lapb;
 }
 
-int lapb_register(void *token, struct lapb_register_struct *callbacks)
+int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks)
 {
 	struct lapb_cb *lapb;
 	int rc = LAPB_BADTOKEN;
 
 	write_lock_bh(&lapb_list_lock);
 
-	lapb = __lapb_tokentostruct(token);
+	lapb = __lapb_devtostruct(dev);
 	if (lapb) {
 		lapb_put(lapb);
 		goto out;
@@ -162,7 +158,7 @@
 	if (!lapb)
 		goto out;
 
-	lapb->token     = token;
+	lapb->dev       = dev;
 	lapb->callbacks = *callbacks;
 
 	__lapb_insert_cb(lapb);
@@ -175,13 +171,13 @@
 	return rc;
 }
 
-int lapb_unregister(void *token)
+int lapb_unregister(struct net_device *dev)
 {
 	struct lapb_cb *lapb;
 	int rc = LAPB_BADTOKEN;
 
 	write_unlock_bh(&lapb_list_lock);
-	lapb = __lapb_tokentostruct(token);
+	lapb = __lapb_devtostruct(dev);
 	if (!lapb)
 		goto out;
 
@@ -199,10 +195,10 @@
 	return rc;
 }
 
-int lapb_getparms(void *token, struct lapb_parms_struct *parms)
+int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
 {
 	int rc = LAPB_BADTOKEN;
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 
 	if (!lapb)
 		goto out;
@@ -231,10 +227,10 @@
 	return rc;
 }
 
-int lapb_setparms(void *token, struct lapb_parms_struct *parms)
+int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
 {
 	int rc = LAPB_BADTOKEN;
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 
 	if (!lapb)
 		goto out;
@@ -264,9 +260,9 @@
 	return rc;
 }
 
-int lapb_connect_request(void *token)
+int lapb_connect_request(struct net_device *dev)
 {
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 	int rc = LAPB_BADTOKEN;
 
 	if (!lapb)
@@ -283,7 +279,7 @@
 	lapb_establish_data_link(lapb);
 
 #if LAPB_DEBUG > 0
-	printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
+	printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->dev);
 #endif
 	lapb->state = LAPB_STATE_1;
 
@@ -294,9 +290,9 @@
 	return rc;
 }
 
-int lapb_disconnect_request(void *token)
+int lapb_disconnect_request(struct net_device *dev)
 {
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 	int rc = LAPB_BADTOKEN;
 
 	if (!lapb)
@@ -309,10 +305,10 @@
 
 		case LAPB_STATE_1:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->dev);
 #endif
 #if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev);
 #endif
 			lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 			lapb->state = LAPB_STATE_0;
@@ -333,10 +329,10 @@
 	lapb->state = LAPB_STATE_2;
 
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
+	printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->dev);
 #endif
 #if LAPB_DEBUG > 0
-	printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
+	printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->dev);
 #endif
 
 	rc = LAPB_OK;
@@ -346,9 +342,9 @@
 	return rc;
 }
 
-int lapb_data_request(void *token, struct sk_buff *skb)
+int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
 {
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 	int rc = LAPB_BADTOKEN;
 
 	if (!lapb)
@@ -367,9 +363,9 @@
 	return rc;
 }
 
-int lapb_data_received(void *token, struct sk_buff *skb)
+int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
 {
-	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	struct lapb_cb *lapb = lapb_devtostruct(dev);
 	int rc = LAPB_BADTOKEN;
 
 	if (lapb) {
@@ -384,31 +380,31 @@
 void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
 {
 	if (lapb->callbacks.connect_confirmation)
-		lapb->callbacks.connect_confirmation(lapb->token, reason);
+		lapb->callbacks.connect_confirmation(lapb->dev, reason);
 }
 
 void lapb_connect_indication(struct lapb_cb *lapb, int reason)
 {
 	if (lapb->callbacks.connect_indication)
-		lapb->callbacks.connect_indication(lapb->token, reason);
+		lapb->callbacks.connect_indication(lapb->dev, reason);
 }
 
 void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
 {
 	if (lapb->callbacks.disconnect_confirmation)
-		lapb->callbacks.disconnect_confirmation(lapb->token, reason);
+		lapb->callbacks.disconnect_confirmation(lapb->dev, reason);
 }
 
 void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
 {
 	if (lapb->callbacks.disconnect_indication)
-		lapb->callbacks.disconnect_indication(lapb->token, reason);
+		lapb->callbacks.disconnect_indication(lapb->dev, reason);
 }
 
 int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
 {
 	if (lapb->callbacks.data_indication)
-		return lapb->callbacks.data_indication(lapb->token, skb);
+		return lapb->callbacks.data_indication(lapb->dev, skb);
 
 	kfree_skb(skb);
 	return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ 
@@ -419,7 +415,7 @@
 	int used = 0;
 
 	if (lapb->callbacks.data_transmit) {
-		lapb->callbacks.data_transmit(lapb->token, skb);
+		lapb->callbacks.data_transmit(lapb->dev, skb);
 		used = 1;
 	}
 
--- diff/net/lapb/lapb_in.c	2003-10-09 09:47:34.000000000 +0100
+++ source/net/lapb/lapb_in.c	2004-02-18 09:04:03.000000000 +0000
@@ -47,23 +47,23 @@
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -82,16 +82,16 @@
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -107,7 +107,7 @@
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
@@ -117,9 +117,9 @@
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 			printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			lapb_send_control(lapb, LAPB_UA, frame->pf,
 					  LAPB_RESPONSE);
@@ -143,19 +143,19 @@
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -165,19 +165,19 @@
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
@@ -187,9 +187,9 @@
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 			printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			lapb_send_control(lapb, LAPB_DM, frame->pf,
 					  LAPB_RESPONSE);
@@ -198,12 +198,12 @@
 		case LAPB_UA:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -220,12 +220,12 @@
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_clear_queues(lapb);
 				lapb->state = LAPB_STATE_0;
@@ -251,9 +251,9 @@
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 			printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			lapb_send_control(lapb, LAPB_DM, frame->pf,
 					  LAPB_RESPONSE);
@@ -262,9 +262,9 @@
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 			printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			lapb_send_control(lapb, LAPB_UA, frame->pf,
 					  LAPB_RESPONSE);
@@ -273,12 +273,12 @@
 		case LAPB_UA:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb->state = LAPB_STATE_0;
 				lapb_start_t1timer(lapb);
@@ -290,12 +290,12 @@
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb->state = LAPB_STATE_0;
 				lapb_start_t1timer(lapb);
@@ -311,9 +311,9 @@
 		case LAPB_RR:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}"
-			       "(%d)\n", lapb->token, frame->pf);
+			       "(%d)\n", lapb->dev, frame->pf);
 			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (frame->pf)
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
@@ -339,19 +339,19 @@
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -369,12 +369,12 @@
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -389,7 +389,7 @@
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
@@ -399,11 +399,11 @@
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
-			       lapb->token);
+			       lapb->dev);
 #endif
 			lapb_clear_queues(lapb);
 			lapb_send_control(lapb, LAPB_UA, frame->pf,
@@ -417,11 +417,11 @@
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
-			       lapb->token);
+			       lapb->dev);
 #endif
 			lapb_clear_queues(lapb);
 			lapb->state = LAPB_STATE_0;
@@ -433,7 +433,7 @@
 		case LAPB_RNR:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n",
-			       lapb->token, frame->pf, frame->nr);
+			       lapb->dev, frame->pf, frame->nr);
 #endif
 			lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -445,7 +445,7 @@
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -457,7 +457,7 @@
 		case LAPB_RR:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n",
-			       lapb->token, frame->pf, frame->nr);
+			       lapb->dev, frame->pf, frame->nr);
 #endif
 			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -469,7 +469,7 @@
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -481,7 +481,7 @@
 		case LAPB_REJ:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n",
-			       lapb->token, frame->pf, frame->nr);
+			       lapb->dev, frame->pf, frame->nr);
 #endif
 			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -496,7 +496,7 @@
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -508,7 +508,7 @@
 		case LAPB_I:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n",
-			       lapb->token, frame->pf, frame->ns, frame->nr);
+			       lapb->dev, frame->pf, frame->ns, frame->nr);
 #endif
 			if (!lapb_validate_nr(lapb, frame->nr)) {
 				lapb->frmr_data = *frame;
@@ -516,7 +516,7 @@
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -564,7 +564,7 @@
 #if LAPB_DEBUG > 1
 					printk(KERN_DEBUG
 					       "lapb: (%p) S3 TX REJ(%d) R%d\n",
-					       lapb->token, frame->pf, lapb->vr);
+					       lapb->dev, frame->pf, lapb->vr);
 #endif
 					lapb->condition |= LAPB_REJECT_CONDITION;
 					lapb_send_control(lapb, LAPB_REJ,
@@ -578,14 +578,14 @@
 		case LAPB_FRMR:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X "
-			       "%02X %02X %02X %02X\n", lapb->token, frame->pf,
+			       "%02X %02X %02X %02X\n", lapb->dev, frame->pf,
 			       skb->data[0], skb->data[1], skb->data[2],
 			       skb->data[3], skb->data[4]);
 #endif
 			lapb_establish_data_link(lapb);
 #if LAPB_DEBUG > 0
 			printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n",
-			       lapb->token);
+			       lapb->dev);
 #endif
 			lapb_requeue_frames(lapb);
 			lapb->state = LAPB_STATE_1;
@@ -594,13 +594,13 @@
 		case LAPB_ILLEGAL:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			lapb->frmr_data = *frame;
 			lapb->frmr_type = LAPB_FRMR_W;
 			lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->dev);
 #endif
 			lapb_start_t1timer(lapb);
 			lapb_stop_t2timer(lapb);
@@ -624,23 +624,23 @@
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -659,16 +659,16 @@
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n",
-			       lapb->token, frame->pf);
+			       lapb->dev, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
-				       lapb->token);
+				       lapb->dev);
 #endif
 				lapb_send_control(lapb, LAPB_UA, frame->pf,
 						  LAPB_RESPONSE);
@@ -684,7 +684,7 @@
 			} else {
 #if LAPB_DEBUG > 1
 				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
-				       lapb->token, frame->pf);
+				       lapb->dev, frame->pf);
 #endif
 				lapb_send_control(lapb, LAPB_DM, frame->pf,
 						  LAPB_RESPONSE);
--- diff/net/lapb/lapb_out.c	2002-10-16 04:28:27.000000000 +0100
+++ source/net/lapb/lapb_out.c	2004-02-18 09:04:03.000000000 +0000
@@ -63,7 +63,7 @@
 
 #if LAPB_DEBUG > 1
 	printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n",
-	       lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr);
+	       lapb->dev, lapb->state, poll_bit, lapb->vs, lapb->vr);
 #endif
 
 	lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);	
@@ -151,7 +151,7 @@
 
 #if LAPB_DEBUG > 2
 	printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n",
-	       lapb->token, lapb->state,
+	       lapb->dev, lapb->state,
 	       skb->data[0], skb->data[1], skb->data[2]);
 #endif
 
@@ -167,13 +167,13 @@
 	if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
 		printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n",
-		       lapb->token, lapb->state);
+		       lapb->dev, lapb->state);
 #endif
 		lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
 	} else {
 #if LAPB_DEBUG > 1
 		printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n",
-		       lapb->token, lapb->state);
+		       lapb->dev, lapb->state);
 #endif
 		lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
 	}
@@ -186,7 +186,7 @@
 {
 #if LAPB_DEBUG > 1
 	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n",
-	       lapb->token, lapb->state, lapb->vr);
+	       lapb->dev, lapb->state, lapb->vr);
 #endif
 
 	lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
@@ -198,7 +198,7 @@
 {
 #if LAPB_DEBUG > 1
 	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n",
-	       lapb->token, lapb->state, lapb->vr);
+	       lapb->dev, lapb->state, lapb->vr);
 #endif
 	lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
 
--- diff/net/lapb/lapb_subr.c	2003-10-09 09:47:34.000000000 +0100
+++ source/net/lapb/lapb_subr.c	2004-02-18 09:04:03.000000000 +0000
@@ -114,7 +114,7 @@
 
 #if LAPB_DEBUG > 2
 	printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n",
-	       lapb->token, lapb->state,
+	       lapb->dev, lapb->state,
 	       skb->data[0], skb->data[1], skb->data[2]);
 #endif
 
@@ -287,7 +287,7 @@
 
 #if LAPB_DEBUG > 1
 	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n",
-	       lapb->token, lapb->state,
+	       lapb->dev, lapb->state,
 	       skb->data[1], skb->data[2], skb->data[3],
 	       skb->data[4], skb->data[5]);
 #endif
@@ -304,7 +304,7 @@
 
 #if LAPB_DEBUG > 1
 	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n",
-	       lapb->token, lapb->state, skb->data[1],
+	       lapb->dev, lapb->state, skb->data[1],
 	       skb->data[2], skb->data[3]);
 #endif
 	}
--- diff/net/lapb/lapb_timer.c	2002-10-16 04:27:21.000000000 +0100
+++ source/net/lapb/lapb_timer.c	2004-02-18 09:04:03.000000000 +0000
@@ -107,19 +107,19 @@
 				lapb->state = LAPB_STATE_0;
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev);
 #endif
 				return;
 			} else {
 				lapb->n2count++;
 				if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-					printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->token);
+					printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->dev);
 #endif
 					lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
 				} else {
 #if LAPB_DEBUG > 1
-					printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->token);
+					printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->dev);
 #endif
 					lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
 				}
@@ -135,13 +135,13 @@
 				lapb->state = LAPB_STATE_0;
 				lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->dev);
 #endif
 				return;
 			} else {
 				lapb->n2count++;
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->dev);
 #endif
 				lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 			}
@@ -157,7 +157,7 @@
 				lapb_stop_t2timer(lapb);
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->dev);
 #endif
 				return;
 			} else {
@@ -175,7 +175,7 @@
 				lapb->state = LAPB_STATE_0;
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->dev);
 #endif
 				return;
 			} else {
--- diff/net/socket.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/socket.c	2004-02-18 09:04:03.000000000 +0000
@@ -78,6 +78,7 @@
 #include <linux/divert.h>
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/kmod.h>
 
--- diff/net/sunrpc/auth.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/sunrpc/auth.c	2004-02-18 09:04:03.000000000 +0000
@@ -255,34 +255,41 @@
 struct rpc_cred *
 rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
 {
-	struct auth_cred acred = {
-		.uid = current->fsuid,
-		.gid = current->fsgid,
-		.ngroups = current->ngroups,
-		.groups = current->groups,
-	};
+	struct auth_cred acred;
+	struct rpc_cred *ret;
+
+	get_group_info(current->group_info);
+	acred.uid = current->fsuid;
+	acred.gid = current->fsgid;
+	acred.group_info = current->group_info;
+
 	dprintk("RPC:     looking up %s cred\n",
 		auth->au_ops->au_name);
-	return rpcauth_lookup_credcache(auth, &acred, taskflags);
+	ret = rpcauth_lookup_credcache(auth, &acred, taskflags);
+	put_group_info(current->group_info);
+	return ret;
 }
 
 struct rpc_cred *
 rpcauth_bindcred(struct rpc_task *task)
 {
 	struct rpc_auth *auth = task->tk_auth;
-	struct auth_cred acred = {
-		.uid = current->fsuid,
-		.gid = current->fsgid,
-		.ngroups = current->ngroups,
-		.groups = current->groups,
-	};
+	struct auth_cred acred;
+	struct rpc_cred *ret;
+
+	get_group_info(current->group_info);
+	acred.uid = current->fsuid;
+	acred.gid = current->fsgid;
+	acred.group_info = current->group_info;
 
 	dprintk("RPC: %4d looking up %s cred\n",
 		task->tk_pid, task->tk_auth->au_ops->au_name);
 	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags);
 	if (task->tk_msg.rpc_cred == 0)
 		task->tk_status = -ENOMEM;
-	return task->tk_msg.rpc_cred;
+	ret = task->tk_msg.rpc_cred;
+	put_group_info(current->group_info);
+	return ret;
 }
 
 void
--- diff/net/sunrpc/auth_unix.c	2003-10-09 09:47:17.000000000 +0100
+++ source/net/sunrpc/auth_unix.c	2004-02-18 09:04:03.000000000 +0000
@@ -82,7 +82,7 @@
 		cred->uc_gid = cred->uc_pgid = 0;
 		cred->uc_gids[0] = NOGROUP;
 	} else {
-		int groups = acred->ngroups;
+		int groups = acred->group_info->ngroups;
 		if (groups > NFS_NGROUPS)
 			groups = NFS_NGROUPS;
 
@@ -91,7 +91,7 @@
 		cred->uc_puid = current->uid;
 		cred->uc_pgid = current->gid;
 		for (i = 0; i < groups; i++)
-			cred->uc_gids[i] = (gid_t) acred->groups[i];
+			cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
 		if (i < NFS_NGROUPS)
 		  cred->uc_gids[i] = NOGROUP;
 	}
@@ -126,11 +126,11 @@
 		 || cred->uc_pgid != current->gid)
 			return 0;
 
-		groups = acred->ngroups;
+		groups = acred->group_info->ngroups;
 		if (groups > NFS_NGROUPS)
 			groups = NFS_NGROUPS;
 		for (i = 0; i < groups ; i++)
-			if (cred->uc_gids[i] != (gid_t) acred->groups[i])
+			if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
 				return 0;
 		return 1;
 	}
--- diff/net/sunrpc/cache.c	2004-02-09 10:36:12.000000000 +0000
+++ source/net/sunrpc/cache.c	2004-02-18 09:04:03.000000000 +0000
@@ -325,6 +325,7 @@
 	
 	if (current_detail && current_index < current_detail->hash_size) {
 		struct cache_head *ch, **cp;
+		struct cache_detail *d;
 		
 		write_lock(&current_detail->hash_lock);
 
@@ -354,12 +355,14 @@
 			rv = 1;
 		}
 		write_unlock(&current_detail->hash_lock);
-		if (ch)
-			current_detail->cache_put(ch, current_detail);
-		else
+		d = current_detail;
+		if (!ch)
 			current_index ++;
-	}
-	spin_unlock(&cache_list_lock);
+		spin_unlock(&cache_list_lock);
+		if (ch)
+			d->cache_put(ch, d);
+	} else
+		spin_unlock(&cache_list_lock);
 
 	return rv;
 }
--- diff/net/sunrpc/stats.c	2003-09-17 12:28:13.000000000 +0100
+++ source/net/sunrpc/stats.c	2004-02-18 09:04:03.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcsock.h>
 
@@ -28,70 +29,66 @@
 /*
  * Get RPC client stats
  */
-int
-rpc_proc_read(char *buffer, char **start, off_t offset, int count,
-				int *eof, void *data)
-{
-	struct rpc_stat	*statp = (struct rpc_stat *) data;
-	struct rpc_program *prog = statp->program;
-	struct rpc_version *vers;
-	int		len, i, j;
+static int rpc_proc_show(struct seq_file *seq, void *v) {
+	const struct rpc_stat	*statp = seq->private;
+	const struct rpc_program *prog = statp->program;
+	int		i, j;
 
-	len = sprintf(buffer,
+	seq_printf(seq,
 		"net %d %d %d %d\n",
 			statp->netcnt,
 			statp->netudpcnt,
 			statp->nettcpcnt,
 			statp->nettcpconn);
-	len += sprintf(buffer + len,
+	seq_printf(seq,
 		"rpc %d %d %d\n",
 			statp->rpccnt,
 			statp->rpcretrans,
 			statp->rpcauthrefresh);
 
 	for (i = 0; i < prog->nrvers; i++) {
-		if (!(vers = prog->version[i]))
+		const struct rpc_version *vers = prog->version[i];
+		if (!vers)
 			continue;
-		len += sprintf(buffer + len, "proc%d %d",
+		seq_printf(seq, "proc%d %d",
 					vers->number, vers->nrprocs);
 		for (j = 0; j < vers->nrprocs; j++)
-			len += sprintf(buffer + len, " %d",
+			seq_printf(seq, " %d",
 					vers->procs[j].p_count);
-		buffer[len++] = '\n';
+		seq_putc(seq, '\n');
 	}
+	return 0;
+}
 
-	if (offset >= len) {
-		*start = buffer;
-		*eof = 1;
-		return 0;
-	}
-	*start = buffer + offset;
-	if ((len -= offset) > count)
-		return count;
-	*eof = 1;
-	return len;
+static int rpc_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rpc_proc_show, PDE(inode)->data);
 }
 
+static struct file_operations rpc_proc_fops = {
+	.owner = THIS_MODULE,
+	.open = rpc_proc_open,
+	.read  = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 /*
  * Get RPC server stats
  */
-int
-svc_proc_read(char *buffer, char **start, off_t offset, int count,
-				int *eof, void *data)
-{
-	struct svc_stat *statp	= (struct svc_stat *) data;
-	struct svc_program *prog = statp->program;
-	struct svc_procedure *proc;
-	struct svc_version *vers;
-	int		len, i, j;
+void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
+	const struct svc_program *prog = statp->program;
+	const struct svc_procedure *proc;
+	const struct svc_version *vers;
+	int		i, j;
 
-	len = sprintf(buffer,
+	seq_printf(seq,
 		"net %d %d %d %d\n",
 			statp->netcnt,
 			statp->netudpcnt,
 			statp->nettcpcnt,
 			statp->nettcpconn);
-	len += sprintf(buffer + len,
+	seq_printf(seq,
 		"rpc %d %d %d %d %d\n",
 			statp->rpccnt,
 			statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
@@ -102,41 +99,36 @@
 	for (i = 0; i < prog->pg_nvers; i++) {
 		if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
 			continue;
-		len += sprintf(buffer + len, "proc%d %d", i, vers->vs_nproc);
+		seq_printf(seq, "proc%d %d", i, vers->vs_nproc);
 		for (j = 0; j < vers->vs_nproc; j++, proc++)
-			len += sprintf(buffer + len, " %d", proc->pc_count);
-		buffer[len++] = '\n';
+			seq_printf(seq, " %d", proc->pc_count);
+		seq_putc(seq, '\n');
 	}
-
-	if (offset >= len) {
-		*start = buffer;
-		*eof = 1;
-		return 0;
-	}
-	*start = buffer + offset;
-	if ((len -= offset) > count)
-		return count;
-	*eof = 1;
-	return len;
 }
 
 /*
  * Register/unregister RPC proc files
  */
 static inline struct proc_dir_entry *
-do_register(const char *name, void *data, int issvc)
+do_register(const char *name, void *data, struct file_operations *fops)
 {
+	struct proc_dir_entry *ent;
+
 	rpc_proc_init();
 	dprintk("RPC: registering /proc/net/rpc/%s\n", name);
-	return create_proc_read_entry(name, 0, proc_net_rpc, 
-				      issvc? svc_proc_read : rpc_proc_read,
-				      data);
+
+	ent = create_proc_entry(name, 0, proc_net_rpc);
+	if (ent) {
+		ent->proc_fops = fops;
+		ent->data = data;
+	}
+	return ent;
 }
 
 struct proc_dir_entry *
 rpc_proc_register(struct rpc_stat *statp)
 {
-	return do_register(statp->program->name, statp, 0);
+	return do_register(statp->program->name, statp, &rpc_proc_fops);
 }
 
 void
@@ -146,9 +138,9 @@
 }
 
 struct proc_dir_entry *
-svc_proc_register(struct svc_stat *statp)
+svc_proc_register(struct svc_stat *statp, struct file_operations *fops)
 {
-	return do_register(statp->program->pg_name, statp, 1);
+	return do_register(statp->program->pg_name, statp, fops);
 }
 
 void
@@ -163,7 +155,7 @@
 	dprintk("RPC: registering /proc/net/rpc\n");
 	if (!proc_net_rpc) {
 		struct proc_dir_entry *ent;
-		ent = proc_mkdir("net/rpc", 0);
+		ent = proc_mkdir("rpc", proc_net);
 		if (ent) {
 			ent->owner = THIS_MODULE;
 			proc_net_rpc = ent;
--- diff/net/sunrpc/sunrpc_syms.c	2004-02-18 08:54:13.000000000 +0000
+++ source/net/sunrpc/sunrpc_syms.c	2004-02-18 09:04:03.000000000 +0000
@@ -90,10 +90,9 @@
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(rpc_proc_register);
 EXPORT_SYMBOL(rpc_proc_unregister);
-EXPORT_SYMBOL(rpc_proc_read);
 EXPORT_SYMBOL(svc_proc_register);
 EXPORT_SYMBOL(svc_proc_unregister);
-EXPORT_SYMBOL(svc_proc_read);
+EXPORT_SYMBOL(svc_seq_show);
 #endif
 
 /* caching... */
--- diff/net/sunrpc/svcauth.c	2003-07-08 09:55:20.000000000 +0100
+++ source/net/sunrpc/svcauth.c	2004-02-18 09:04:03.000000000 +0000
@@ -150,7 +150,13 @@
 		  &auth_domain_cache,
 		  auth_domain_hash(item),
 		  auth_domain_match(tmp, item),
-		  kfree(new); if(!set) return NULL;
+		  kfree(new); if(!set) {
+			if (new)
+				write_unlock(&auth_domain_cache.hash_lock);
+			else
+				read_unlock(&auth_domain_cache.hash_lock);
+			return NULL;
+		  }
 		  new=item; atomic_inc(&new->h.refcnt),
 		  /* no update */,
 		  0 /* no inplace updates */
--- diff/net/sunrpc/svcauth_unix.c	2003-07-08 09:55:20.000000000 +0100
+++ source/net/sunrpc/svcauth_unix.c	2004-02-18 09:04:03.000000000 +0000
@@ -119,7 +119,8 @@
 }
 static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
 {
-	new->m_class = strdup(item->m_class);
+	new->m_class = item->m_class;
+	item->m_class = NULL;
 	new->m_addr.s_addr = item->m_addr.s_addr;
 }
 static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
@@ -191,7 +192,9 @@
 	} else
 		dom = NULL;
 
-	ipm.m_class = class;
+	ipm.m_class = strdup(class);
+	if (ipm.m_class == NULL)
+		return -ENOMEM;
 	ipm.m_addr.s_addr =
 		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
 	ipm.h.flags = 0;
@@ -207,6 +210,7 @@
 		ip_map_put(&ipmp->h, &ip_map_cache);
 	if (dom)
 		auth_domain_put(dom);
+	if (ipm.m_class) kfree(ipm.m_class);
 	if (!ipmp)
 		return -ENOMEM;
 	cache_flush();
@@ -266,7 +270,9 @@
 	if (dom->flavour != RPC_AUTH_UNIX)
 		return -EINVAL;
 	udom = container_of(dom, struct unix_domain, h);
-	ip.m_class = "nfsd";
+	ip.m_class = strdup("nfsd");
+	if (!ip.m_class)
+		return -ENOMEM;
 	ip.m_addr = addr;
 	ip.m_client = udom;
 	ip.m_add_change = udom->addr_changes+1;
@@ -274,6 +280,7 @@
 	ip.h.expiry_time = NEVER;
 	
 	ipmp = ip_map_lookup(&ip, 1);
+	if (ip.m_class) kfree(ip.m_class);
 	if (ipmp) {
 		ip_map_put(&ipmp->h, &ip_map_cache);
 		return 0;
@@ -434,11 +441,11 @@
 	if (slen > 16 || (len -= (slen + 2)*4) < 0)
 		goto badcred;
 	for (i = 0; i < slen; i++)
-		if (i < NGROUPS)
+		if (i < SVC_CRED_NGROUPS)
 			cred->cr_groups[i] = ntohl(svc_getu32(argv));
 		else
 			svc_getu32(argv);
-	if (i < NGROUPS)
+	if (i < SVC_CRED_NGROUPS)
 		cred->cr_groups[i] = NOGROUP;
 
 	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
--- diff/scripts/kconfig/Makefile	2003-09-30 15:46:21.000000000 +0100
+++ source/scripts/kconfig/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -95,7 +95,7 @@
 HOSTCFLAGS_lex.zconf.o	:= -I$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(src)
 
-HOSTLOADLIBES_qconf	= -L$(QTDIR)/lib -Wl,-rpath,$(QTDIR)/lib -l$(QTLIB) -ldl
+HOSTLOADLIBES_qconf	= -L$(QTDIR)/lib -L$(QTDIR)/lib64 -Wl,-rpath,$(QTDIR)/lib -l$(QTLIB) -ldl
 HOSTCXXFLAGS_qconf.o	= -I$(QTDIR)/include 
 
 HOSTLOADLIBES_gconf	= `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --libs`
--- diff/scripts/lxdialog/Makefile	2003-05-21 11:49:51.000000000 +0100
+++ source/scripts/lxdialog/Makefile	2004-02-18 09:04:03.000000000 +0000
@@ -16,15 +16,13 @@
 endif
 
 host-progs	:= lxdialog
-always		:= $(host-progs)
+always		:= ncurses $(host-progs)
 
 lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \
 		 util.o lxdialog.o msgbox.o
 
-first_rule: ncurses
-
-.PHONY: ncurses
-ncurses:
+.PHONY: $(obj)/ncurses
+$(obj)/ncurses:
 	@echo "main() {}" > lxtemp.c
 	@if $(HOSTCC) lxtemp.c  $(HOST_LOADLIBES); then \
 		rm -f lxtemp.c a.out; \
@@ -33,7 +31,7 @@
 		echo -e "\007" ;\
 		echo ">> Unable to find the Ncurses libraries." ;\
 		echo ">>" ;\
-		echo ">> You must have Ncurses installed in order" ;\
+		echo ">> You must install ncurses-devel in order" ;\
 		echo ">> to use 'make menuconfig'" ;\
 		echo ;\
 		exit 1 ;\
--- diff/scripts/mkspec	2004-01-19 10:22:59.000000000 +0000
+++ source/scripts/mkspec	2004-02-18 09:04:03.000000000 +0000
@@ -37,6 +37,7 @@
 echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
 echo "Provides: $PROVIDES"
 echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
+echo "%define debug_package %{nil}"
 echo ""
 echo "%description"
 echo "The Linux Kernel, the operating system core itself"
--- diff/security/dummy.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/dummy.c	2004-02-18 09:04:03.000000000 +0000
@@ -544,7 +544,7 @@
 	return 0;
 }
 
-static int dummy_task_setgroups (int gidsetsize, gid_t * grouplist)
+static int dummy_task_setgroups (struct group_info *group_info)
 {
 	return 0;
 }
--- diff/security/selinux/hooks.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/hooks.c	2004-02-18 09:04:03.000000000 +0000
@@ -34,6 +34,7 @@
 #include <linux/swap.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
+#include <linux/syscalls.h>
 #include <linux/file.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
@@ -2539,7 +2540,7 @@
 	return task_has_perm(current, p, PROCESS__GETSESSION);
 }
 
-static int selinux_task_setgroups(int gidsetsize, gid_t *grouplist)
+static int selinux_task_setgroups(struct group_info *group_info)
 {
 	/* See the comment for setuid above. */
 	return 0;
--- diff/security/selinux/selinuxfs.c	2004-02-18 08:54:13.000000000 +0000
+++ source/security/selinux/selinuxfs.c	2004-02-18 09:04:03.000000000 +0000
@@ -54,7 +54,7 @@
 		return -ENOMEM;
 	memset(page, 0, PAGE_SIZE);
 
-	length = snprintf(page, PAGE_SIZE, "%d", selinux_enforcing);
+	length = scnprintf(page, PAGE_SIZE, "%d", selinux_enforcing);
 	if (length < 0) {
 		free_page((unsigned long)page);
 		return length;
@@ -139,7 +139,7 @@
 		return -ENOMEM;
 	memset(page, 0, PAGE_SIZE);
 
-	length = snprintf(page, PAGE_SIZE, "%u", POLICYDB_VERSION);
+	length = scnprintf(page, PAGE_SIZE, "%u", POLICYDB_VERSION);
 	if (length < 0) {
 		free_page((unsigned long)page);
 		return length;
@@ -404,7 +404,7 @@
 	if (length < 0)
 		goto out2;
 
-	length = snprintf(buf, PAYLOAD_SIZE, "%x %x %x %x %u",
+	length = scnprintf(buf, PAYLOAD_SIZE, "%x %x %x %x %u",
 			  avd.allowed, avd.decided,
 			  avd.auditallow, avd.auditdeny,
 			  avd.seqno);
--- diff/sound/core/info.c	2003-09-30 15:46:21.000000000 +0100
+++ source/sound/core/info.c	2004-02-18 09:04:03.000000000 +0000
@@ -99,7 +99,7 @@
 	if (buffer->stop || buffer->error)
 		return 0;
 	va_start(args, fmt);
-	res = vsnprintf(sbuffer, sizeof(sbuffer), fmt, args);
+	res = vscnprintf(sbuffer, sizeof(sbuffer), fmt, args);
 	va_end(args);
 	if (buffer->size + res >= buffer->len) {
 		buffer->stop = 1;
--- diff/sound/core/seq/seq_dummy.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/core/seq/seq_dummy.c	2004-02-18 09:04:03.000000000 +0000
@@ -46,7 +46,7 @@
 
   The number of ports to be created can be specified via the module
   parameter "ports".  For example, to create four ports, add the
-  following option in /etc/modules.conf:
+  following option in /etc/modprobe.conf:
 
 	option snd-seq-dummy ports=4
 
--- diff/sound/drivers/vx/vx_core.c	2004-02-18 08:54:13.000000000 +0000
+++ source/sound/drivers/vx/vx_core.c	2004-02-18 09:04:03.000000000 +0000
@@ -355,11 +355,12 @@
  */
 int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh)
 {
+	unsigned long flags;
 	int err;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_msg_nolock(chip, rmh);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
@@ -415,10 +416,11 @@
 int vx_send_rih(vx_core_t *chip, int cmd)
 {
 	int err;
+	unsigned long flags;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_rih_nolock(chip, cmd);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
--- diff/sound/oss/msnd.c	2002-10-16 04:27:50.000000000 +0100
+++ source/sound/oss/msnd.c	2004-02-18 09:04:03.000000000 +0000
@@ -25,9 +25,6 @@
  ********************************************************************/
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < 0x020101
-#  define LINUX20
-#endif
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -35,18 +32,10 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
-#ifdef LINUX20
-#  include <linux/major.h>
-#  include <linux/fs.h>
-#  include <linux/sound.h>
-#  include <asm/segment.h>
-#  include "sound_config.h"
-#else
-#  include <linux/init.h>
-#  include <asm/io.h>
-#  include <asm/uaccess.h>
-#  include <linux/spinlock.h>
-#endif
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/spinlock.h>
 #include <asm/irq.h>
 #include "msnd.h"
 
--- diff/sound/oss/os.h	2003-05-21 11:50:17.000000000 +0100
+++ source/sound/oss/os.h	2004-02-18 09:04:03.000000000 +0000
@@ -7,10 +7,6 @@
 #include <linux/module.h>
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE > 131328
-#define LINUX21X
-#endif
-
 #ifdef __KERNEL__
 #include <linux/utsname.h>
 #include <linux/string.h>
--- diff/usr/gen_init_cpio.c	2004-01-19 10:22:59.000000000 +0000
+++ source/usr/gen_init_cpio.c	2004-02-18 09:04:03.000000000 +0000
@@ -56,7 +56,7 @@
 	const char name[] = "TRAILER!!!";
 
 	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
-	       "%08X%08X%08X%08X%08X%08ZX%08X",
+	       "%08X%08X%08X%08X%08X%08X%08X",
 		"070701",		/* magic */
 		0,			/* ino */
 		0,			/* mode */
@@ -69,7 +69,7 @@
 		0,			/* minor */
 		0,			/* rmajor */
 		0,			/* rminor */
-		strlen(name) + 1,	/* namesize */
+		(unsigned)strlen(name) + 1, /* namesize */
 		0);			/* chksum */
 	push_hdr(s);
 	push_rest(name);
@@ -87,7 +87,7 @@
 	time_t mtime = time(NULL);
 
 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
-	       "%08X%08X%08X%08X%08X%08ZX%08X",
+	       "%08X%08X%08X%08X%08X%08X%08X",
 		"070701",		/* magic */
 		ino++,			/* ino */
 		S_IFDIR | mode,		/* mode */
@@ -100,7 +100,7 @@
 		1,			/* minor */
 		0,			/* rmajor */
 		0,			/* rminor */
-		strlen(name) + 1,	/* namesize */
+		(unsigned)strlen(name) + 1,/* namesize */
 		0);			/* chksum */
 	push_hdr(s);
 	push_rest(name);
@@ -119,7 +119,7 @@
 		mode |= S_IFCHR;
 
 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
-	       "%08X%08X%08X%08X%08X%08ZX%08X",
+	       "%08X%08X%08X%08X%08X%08X%08X",
 		"070701",		/* magic */
 		ino++,			/* ino */
 		mode,			/* mode */
@@ -132,7 +132,7 @@
 		1,			/* minor */
 		maj,			/* rmajor */
 		min,			/* rminor */
-		strlen(name) + 1,	/* namesize */
+		(unsigned)strlen(name) + 1,/* namesize */
 		0);			/* chksum */
 	push_hdr(s);
 	push_rest(name);
@@ -176,7 +176,7 @@
 	}
 
 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
-	       "%08X%08X%08X%08X%08X%08ZX%08X",
+	       "%08X%08X%08X%08X%08X%08X%08X",
 		"070701",		/* magic */
 		ino++,			/* ino */
 		mode,			/* mode */
@@ -189,7 +189,7 @@
 		1,			/* minor */
 		0,			/* rmajor */
 		0,			/* rminor */
-		strlen(location) + 1,	/* namesize */
+		(unsigned)strlen(location) + 1,/* namesize */
 		0);			/* chksum */
 	push_hdr(s);
 	push_string(location);
--- diff/Documentation/debugging-modules.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/debugging-modules.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,18 @@
+Debugging Modules after 2.6.3
+-----------------------------
+
+In almost all distributions, the kernel asks for modules which don't
+exist, such as "net-pf-10" or whatever.  Changing "modprobe -q" to
+"succeed" in this case is hacky and breaks some setups, and also we
+want to know if it failed for the fallback code for old aliases in
+fs/char_dev.c, for example.
+
+In the past a debugging message which would fill people's logs was
+emitted.  This debugging message has been removed.  The correct way
+of debugging module problems is something like this:
+
+echo '#! /bin/sh' > /tmp/modprobe
+echo 'echo "$@" >> /tmp/modprobe.log' >> /tmp/modprobe
+echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
+chmod a+x /tmp/modprobe
+echo /tmp/modprobe > /proc/sys/kernel/modprobe
--- diff/Documentation/i386/kgdb/andthen	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/andthen	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,100 @@
+
+define	set_andthen
+	set var $thp=0
+	set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
+	set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
+	set var $at_oc=kgdb_and_then_count
+	set var $at_cc=$at_oc
+end
+
+define andthen_next
+	set var $at_cc=$arg0
+end
+
+define andthen
+	andthen_set_edge
+	if ($at_cc >= $at_oc)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc
+		output *($thp+($at_cc++ % $at_size ))
+		printf "\n"
+	end
+end
+define andthen_set_edge
+	set var $at_oc=kgdb_and_then_count
+	set var $at_low = $at_oc - $at_size
+	if ($at_low < 0 )
+		set var $at_low = 0
+	end
+	if (( $at_cc > $at_oc) || ($at_cc < $at_low))
+		printf "Count outside of window, setting count to "
+		if ($at_cc >= $at_oc)
+			set var $at_cc = $at_oc
+		else
+			set var $at_cc = $at_low
+		end
+		printf "%d\n",$at_cc
+	end
+end
+
+define beforethat
+	andthen_set_edge
+	if ($at_cc <= $at_low)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc-1
+		output *($thp+(--$at_cc % $at_size ))
+		printf "\n"
+	end
+end
+
+document andthen_next
+	andthen_next <count>
+	.	sets the number of the event to display next. If this event
+	.	is not in the event pool, either andthen or beforethat will
+	.	correct it to the nearest event pool edge.  The event pool
+	.	ends at the last event recorded and begins <number of events>
+	.	prior to that.  If beforethat is used next, it will display
+	.	event <count> -1.
+.
+	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+
+document andthen
+	andthen
+.	displays the next event in the list.  <set_andthen> sets up to display
+.	the oldest saved event first.
+.	<count> (optional) count of the event to display.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to andthen the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document set_andthen
+	set_andthen
+.	sets up to use the <andthen> and <beforethat> commands.
+.		if you have defined your own struct, use the above and
+.		then enter the following:
+.		p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
+.		where <kgdb_and_then_structX> is the name of your structure.
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document beforethat
+	beforethat
+.	displays the next prior event in the list. <set_andthen> sets up to
+.	display the last occuring event first.
+.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to beforethat the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
--- diff/Documentation/i386/kgdb/debug-nmi.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/debug-nmi.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,37 @@
+Subject: Debugging with NMI
+Date: Mon, 12 Jul 1999 11:28:31 -0500
+From: David Grothe <dave@gcom.com>
+Organization: Gcom, Inc
+To: David Grothe <dave@gcom.com>
+
+Kernel hackers:
+
+Maybe this is old hat, but it is new to me --
+
+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
+slot you will generate an NMI to the CPU.  This interrupts even a
+machine that is hung in a loop with interrupts disabled.  Used in
+conjunction with kgdb <
+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
+gain debugger control of a machine that is hung in the kernel!  Even
+without kgdb the kernel will print a stack trace so you can find out
+where it was hung.
+
+The A1/B1 pins are directly opposite one another and the farthest pins
+towards the bracket end of the ISA bus socket.  You can stick a paper
+clip or multi-meter probe between them to short them out.
+
+I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
+board consists of two rows of wire wrap pins.  So I wired a push button
+between the A1/B1 pins and now have an ISA board that I can stick into
+any ISA bus slot for debugger entry.
+
+Microsoft has a circuit diagram of a PCI card at
+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
+build one you will have to mail them and ask for the PAL equations.
+Nobody makes one comercially.
+
+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
+your machine catches fire, it is your problem, not mine.]
+
+-- Dave (the kgdb guy)
--- diff/Documentation/i386/kgdb/gdb-globals.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdb-globals.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,71 @@
+Sender: akale@veritas.com
+Date: Fri, 23 Jun 2000 19:26:35 +0530
+From: "Amit S. Kale" <akale@veritas.com>
+Organization: Veritas Software (India)
+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
+CC: David Milburn <dmilburn@wirespeed.com>,
+        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
+        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
+Subject: Re: Module debugging using kgdb
+
+Dave Grothe wrote:
+>
+> Amit:
+>
+> There is a 2.4.0 version of kgdb on our ftp site:
+> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
+> and loadmodule.sh there.
+>
+> Have a look at the README file and see if I go it right.  If not, send
+> me some corrections and I will update it.
+>
+> Does your version of gdb solve the global variable problem?
+
+Yes.
+Thanks to Elena Zanoni, gdb (developement version) can now calculate
+correctly addresses  of dynamically loaded object files. I have not been
+following gdb developement for sometime and am not sure when symbol
+address calculation fix is going to appear in a gdb stable version.
+
+Elena, any idea when the fix will make it to a prebuilt gdb from a
+redhat release?
+
+For the time being I have built a gdb developement version. It can be
+used for module debugging with loadmodule.sh script.
+
+The problem with calculating of module addresses with previous versions
+of gdb was as follows:
+gdb did not use base address of a section while calculating address of
+a symbol in the section in an object file loaded via 'add-symbol-file'.
+It used address of .text segment instead. Due to this addresses of
+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
+
+Above mentioned fix allow gdb to use base address of a segment while
+calculating address of a symbol in it. It adds a parameter '-s' to
+'add-symbol-file' command for specifying base address of a segment.
+
+loadmodule.sh script works as follows.
+
+1. Copy a module file to target machine.
+2. Load the module on the target machine using insmod with -m parameter.
+insmod produces a module load map which contains base addresses of all
+sections in the module and addresses of symbols in the module file.
+3. Find all sections and their base addresses in the module from
+the module map.
+4. Generate a script that loads the module file. The script uses
+'add-symbol-file' and specifies address of text segment followed by
+addresses of all segments in the module.
+
+Here is an example gdb script produced by loadmodule.sh script.
+
+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
+
+With this command gdb can calculate addresses of symbols in ANY segment
+in a module file.
+
+Regards.
+--
+Amit Kale
+Veritas Software ( http://www.veritas.com )
--- diff/Documentation/i386/kgdb/gdbinit	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,14 @@
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400
+target remote /dev/ttyS0
+define si
+stepi
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
+end
+define ni
+nexti
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
--- diff/Documentation/i386/kgdb/gdbinit-modules	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit-modules	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,146 @@
+#
+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
+#
+# This don't work for Linux-2.0 or older.
+#
+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
+#
+#
+# Fri Apr 30 20:33:29 CEST 1999
+#   First public release.
+#
+#   Major cleanup after experiment Linux-2.0 kernel without success.
+#   Symbols of a module are not in the correct order, I can't explain
+#   why :(
+#
+# Fri Mar 19 15:41:40 CET 1999
+#   Initial version.
+#
+# Thu Jan  6 16:29:03 CST 2000
+#   A little fixing by Dave Grothe <dave@gcom.com>
+#
+# Mon Jun 19 09:33:13 CDT 2000
+#   Alignment changes from Edouard Parmelan
+#
+# The basic idea is to find where insmod load the module and inform
+# GDB to load the symbol table of the module with the GDB command
+# ``add-symbol-file <object> <address>''.
+#
+# The Linux kernel holds the list of all loaded modules in module_list,
+# this list end with &kernel_module (exactly with module->next == NULL,
+# but the last module is not a real module).
+#
+# Insmod allocates the struct module before the object file.  Since
+# Linux-2.1, this structure contain his size.  The real address of
+# the object file is then (char*)module + module->size_of_struct.
+#
+# You can use three user functions ``mod-list'', ``mod-print-symbols''
+# and ``add-module-symbols''.
+#
+# mod-list list all loaded modules with the format:
+#    <module-address> <module-name>
+#
+# As soon as you have found the address of your module, you can
+# print its exported symbols (mod-print-symbols) or inform GDB to add
+# symbols from your module file (mod-add-symbols).
+#
+# The argument that you give to mod-print-symbols or mod-add-symbols
+# is the <module-address> from the mod-list command.
+#
+# When using the mod-add-symbols command you must also give the full
+# pathname of the modules object code file.
+#
+# The command mod-add-lis is an example of how to make this easier.
+# You can edit this macro to contain the path name of your own
+# favorite module and then use it as a shorthand to load it.  You
+# still need the module-address, however.
+#
+# The internal function ``mod-validate'' set the GDB variable $mod
+# as a ``struct module*'' if the kernel known the module otherwise
+# $mod is set to NULL.  This ensure to not add symbols for a wrong
+# address.
+#
+# Have a nice hacking day !
+#
+#
+define mod-list
+    set $mod = (struct module*)module_list
+    # the last module is the kernel, ignore it
+    while $mod != &kernel_module
+    	printf "%p\t%s\n", (long)$mod, ($mod)->name
+	set $mod = $mod->next
+    end
+end
+document mod-list
+List all modules in the form: <module-address> <module-name>
+Use the <module-address> as the argument for the other
+mod-commands: mod-print-symbols, mod-add-symbols.
+end
+
+define mod-validate
+    set $mod = (struct module*)module_list
+    while ($mod != $arg0) && ($mod != &kernel_module)
+    	set $mod = $mod->next
+    end
+    if $mod == &kernel_module
+	set $mod = 0
+    	printf "%p is not a module\n", $arg0
+    end
+end
+document mod-validate
+mod-validate <module-address>
+Internal user-command used to validate the module parameter.
+If <module> is a real loaded module, set $mod to it otherwise set $mod to 0.
+end
+
+
+define mod-print-symbols
+    mod-validate $arg0
+    if $mod != 0
+	set $i = 0
+	while $i < $mod->nsyms
+	    set $sym = $mod->syms[$i]
+	    printf "%p\t%s\n", $sym->value, $sym->name
+	    set $i = $i + 1
+	end
+    end
+end
+document mod-print-symbols
+mod-print-symbols <module-address>
+Print all exported symbols of the module.  see mod-list
+end
+
+
+define mod-add-symbols-align
+    mod-validate $arg0
+    if $mod != 0
+	set $mod_base = ($mod->size_of_struct + (long)$mod)
+	if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0)
+	    set $mod_base = ($mod_base | ($arg2 - 1)) + 1
+	end
+	add-symbol-file $arg1 $mod_base
+    end
+end
+document mod-add-symbols-align
+mod-add-symbols-align <module-address> <object file path name> <align>
+Load the symbols table of the module from the object file where
+first section aligment is <align>.
+To retreive alignment, use `objdump -h <object file path name>'.
+end
+
+define mod-add-symbols
+    mod-add-symbols-align $arg0 $arg1 sizeof(long)
+end
+document mod-add-symbols
+mod-add-symbols <module-address> <object file path name>
+Load the symbols table of the module from the object file.
+Default alignment is 4.  See mod-add-symbols-align.
+end
+
+define mod-add-lis
+    mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16
+end
+document mod-add-lis
+mod-add-lis <module-address>
+Does mod-add-symbols <module-address> /usr/src/LiS/streams.o
+end
--- diff/Documentation/i386/kgdb/gdbinit.hw	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit.hw	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,117 @@
+
+#Using ia-32 hardware breakpoints.
+#
+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
+#do not need code modification. They are set using debug registers.
+#
+#Each hardware breakpoint can be of one of the
+#three types: execution, write, access.
+#1. An Execution breakpoint is triggered when code at the breakpoint address is
+#executed.
+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
+#at the breakpoint address is written.
+#3. An access breakpoint is triggered when memory location at the breakpoint
+#address is either read or written.
+#
+#As hardware breakpoints are available in limited number, use software
+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
+#
+#Length of an access or a write breakpoint defines length of the datatype to
+#be watched. Length is 1 for char, 2 short , 3 int.
+#
+#For placing execution, write and access breakpoints, use commands
+#hwebrk, hwwbrk, hwabrk
+#To remove a breakpoint use hwrmbrk command.
+#
+#These commands take following types of arguments. For arguments associated
+#with each command, use help command.
+#1. breakpointno: 0 to 3
+#2. length: 1 to 3
+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
+#
+#Use the command exinfo to find which hardware breakpoint occured.
+
+#hwebrk breakpointno address
+define hwebrk
+	maintenance packet Y$arg0,0,0,$arg1
+end
+document hwebrk
+	hwebrk <breakpointno> <address>
+	Places a hardware execution breakpoint
+	<breakpointno> = 0 - 3
+	<address> = Hex digits without leading "0x".
+end
+
+#hwwbrk breakpointno length address
+define hwwbrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwwbrk
+	hwwbrk <breakpointno> <length> <address>
+	Places a hardware write breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwabrk breakpointno length address
+define hwabrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwabrk
+	hwabrk <breakpointno> <length> <address>
+	Places a hardware access breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwrmbrk breakpointno
+define hwrmbrk
+	maintenance packet y$arg0
+end
+document hwrmbrk
+	hwrmbrk <breakpointno>
+	<breakpointno> = 0 - 3
+	Removes a hardware breakpoint
+end
+
+define reboot
+        maintenance packet r
+end
+#exinfo
+define exinfo
+	maintenance packet qE
+end
+document exinfo
+	exinfo
+	Gives information about a breakpoint.
+end
+define get_th
+	p $th=(struct thread_info *)((int)$esp & ~8191)
+end
+document get_th
+	get_tu
+	Gets and prints the current thread_info pointer, Defines th to be it.
+end
+define get_cu
+	p $cu=((struct thread_info *)((int)$esp & ~8191))->task
+end
+document get_cu
+	get_cu
+	Gets and print the "current" value.  Defines $cu to be it.
+end
+define int_off
+	set var $flags=$eflags
+	set $eflags=$eflags&~0x200
+	end
+define int_on
+	set var $eflags|=$flags&0x200
+	end
+document int_off
+	saves the current interrupt state and clears the processor interrupt
+	flag.  Use int_on to restore the saved flag.
+end
+document int_on
+	Restores the interrupt flag saved by int_off.
+end
--- diff/Documentation/i386/kgdb/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdb.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,775 @@
+Last edit: <20030806.1637.12>
+This file has information specific to the i386 kgdb option.  Other
+platforms with the kgdb option may behave in a similar fashion.
+
+New features:
+============
+20030806.1557.37
+This version was made against the 2.6.0-test2 kernel. We have made the
+following changes:
+
+- The getthread() code in the stub calls find_task_by_pid().  It fails
+  if we are early in the bring up such that the pid arrays have yet to
+  be allocated.  We have added a line to kernel/pid.c to make
+  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
+  getthread() code knows not to call.  This is only used by the thread
+  debugging stuff and threads will not yet exist at this point in the
+  boot.
+
+- For some reason, gdb was not asking for a new thread list when the
+  "info thread" command was given.  We changed to the newer version of
+  the thread info command and gdb now seems to ask when needed.  Result,
+  we now get all threads in the thread list.
+
+- We now respond to the ThreadExtraInfo request from gdb with the thread
+  name from task_struct .comm.  This then appears in the thread list.
+  Thoughts on additional options for this are welcome.  Things such as
+  "has BKL" and "Preempted" come to mind.  I think we could have a flag
+  word that could enable different bits of info here.
+
+- We now honor, sort of, the C and S commands.  These are continue and
+  single set after delivering a signal.  We ignore the signal and do the
+  requested action.  This only happens when we told gdb that a signal
+  was the reason for entry, which is only done on memory faults.  The
+  result is that you can now continue into the Oops.
+
+- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
+  but it is more exact on what language to use.
+
+- We added two dwarf2 include files and a bit of code at the end of
+  entry.S.  This does not yet work, so it is disabled.  Still we want to
+  keep track of the code and "maybe" someone out there can fix it.
+
+- Randy Dunlap sent some fix ups for this file which are now merged.
+
+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
+  compiler warning if CONFIG_KGDB is off (now who would do that :).
+
+- Andrew Morton sent a fix for the serial driver which is now merged.
+
+- Andrew also sent a change to the stub around the cpu managment code
+  which is also merged.
+
+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
+  commands to enter kgdb, merged.
+
+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
+  "who" field to the spinlock data struct.  This is filled with
+  "current" when ever the spinlock suceeds.  Useful if you want to know
+  who has the lock.
+
+_ And last, but not least, we fixed the "get_cu" macro to properly get
+  the current value of "current".
+
+New features:
+============
+20030505.1827.27
+We are starting to align with the sourceforge version, at least in
+commands.  To this end, the boot command string to start kgdb at
+boot time has been changed from "kgdb" to "gdb".
+
+Andrew Morton sent a couple of patches which are now included as follows:
+1.) We now return a flag to the interrupt handler.
+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
+    sure high-mem is set up before we attempt to register our interrupt
+    handler.
+We now include asm/kgdb.h from config.h so you will most likely never
+have to include it.  It also 'NULLS' the kgdb macros you might have in
+your code when CONFIG_KGDB is not defined.  This allows you to just
+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
+This include is conditioned on the machine being an x86 so as to not
+mess with other archs.
+
+20020801.1129.03
+This is currently the version for the 2.4.18 (and beyond?) kernel.
+
+We have several new "features" beginning with this version:
+
+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
+    waiting and it will pull that guy out of an IRQ off spin lock :)
+
+2.) We doctored up the code that tells where a task is waiting and
+    included it so that the "info thread" command will show a bit more
+    than "schedule()".  Try it...
+
+3.) Added the ability to call a function from gdb.  All the standard gdb
+    issues apply, i.e. if you hit a breakpoint in the function, you are
+    not allowed to call another (gdb limitation, not kgdb).  To help
+    this capability we added a memory allocation function.  Gdb does not
+    return this memory (it is used for strings that you pass to that function
+    you are calling from gdb) so we fixed up a way to allow you to
+    manually return the memory (see below).
+
+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
+    interrupt flag to now also include the preemption count and the
+    "in_interrupt" info.  The flag is now called "with_pif" to indicate
+    the order, preempt_count, in_interrupt, flag.  The preempt_count is
+    shifted left by 4 bits so you can read the count in hex by dropping
+    the low order digit.  In_interrupt is in bit 1, and the flag is in
+    bit 0.
+
+5.) The command: "p kgdb_info" is now expanded and prints something
+    like:
+(gdb) p kgdb_info
+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
+  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
+  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
+      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
+
+    Things to note here: a.) used_malloc is the amount of memory that
+    has been malloc'ed to do calls from gdb.  You can reclaim this
+    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
+    cpus_waiting is now "sized" by the number of CPUs you enter at
+    configure time in the kgdb configure section.  This is NOT used
+    anywhere else in the system, but it is "nice" here.  c.)  The task's
+    "pid" is now in the structure.  This is the pid you will need to use
+    to decode to the thread id to get gdb to look at that thread.
+    Remember that the "info thread" command prints a list of threads
+    wherein it numbers each thread with its reference number followed
+    by the thread's pid.  Note that the per-CPU idle threads actually
+    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
+    To avoid confusion, kgdb numbers these threads with numbers beyond
+    the MAX_PID.  That is why you see 32768 and above.
+
+6.) A subtle change, we now provide the complete register set for tasks
+    that are active on the other CPUs.  This allows better trace back on
+    those tasks.
+
+    And, let's mention what we could not fix.  Back-trace from all but the
+    thread that we trapped will, most likely, have a bogus entry in it.
+    The problem is that gdb does not recognize the entry code for
+    functions that use "current" near (at all?) the entry.  The compiler
+    is putting the "current" decode as the first two instructions of the
+    function where gdb expects to find %ebp changing code.  Back trace
+    also has trouble with interrupt frames.  I am talking with Daniel
+    Jacobowitz about some way to fix this, but don't hold your breath.
+
+20011220.0050.35
+Major enhancement with this version is the ability to hold one or more
+CPUs in an SMP system while allowing the others to continue.  Also, by
+default only the current CPU is enabled on single-step commands (please
+note that gdb issues single-step commands at times other than when you
+use the si command).
+
+Another change is to collect some useful information in
+a global structure called "kgdb_info".  You should be able to just:
+
+p kgdb_info
+
+although I have seen cases where the first time this is done gdb just
+prints the first member but prints the whole structure if you then enter
+CR (carriage return or enter).  This also works:
+
+p *&kgdb_info
+
+Here is a sample:
+(gdb) p kgdb_info
+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
+  vector = 3, print_debug_info = 0}
+
+"Called_from" is the return address from the current entry into kgdb.
+Sometimes it is useful to know why you are in kgdb, for example, was
+it an NMI or a real breakpoint?  The simple way to interrogate this
+return address is:
+
+l *0xc010732c
+
+which will print the surrounding few lines of source code.
+
+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
+kgdb_ts entries).
+
+"errcode" and "vector" are other entry parameters which may be helpful on
+some traps.
+
+"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
+you can modify it.
+
+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
+"hold_on_step":
+
+(gdb) p kgdb_info
+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
+  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
+      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
+      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}}}
+
+"Cpus_waiting" has an entry for each CPU other than the current one that
+has been stopped.  Each entry contains the task_struct address for that
+CPU, the address of the regs for that task and a hold flag.  All these
+have the proper typing so that, for example:
+
+p *kgdb_info.cpus_waiting[1].regs
+
+will print the registers for CPU 1.
+
+"Hold_on_sstep" is a new feature with this version and comes up set or
+true.  What this means is that whenever kgdb is asked to single-step all
+other CPUs are held (i.e. not allowed to execute).  The flag applies to
+all but the current CPU and, again, can be changed:
+
+p kgdb_info.hold_on_sstep=0
+
+restores the old behavior of letting all CPUs run during single-stepping.
+
+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
+of execution.  Note that this has some risk in cases where the CPUs need
+to communicate with each other.  If kgdb finds no CPU available on exit,
+it will push a message thru gdb and stay in kgdb.  Note that it is legal
+to hold the current CPU as long as at least one CPU can execute.
+
+20010621.1117.09
+This version implements an event queue.  Events are signaled by calling
+a function in the kgdb stub and may be examined from gdb.  See EVENTS
+below for details.  This version also tightens up the interrupt and SMP
+handling to not allow interrupts on the way to kgdb from a breakpoint
+trap.  It is fine to allow these interrupts for user code, but not
+system debugging.
+
+Version
+=======
+
+This version of the kgdb package was developed and tested on
+kernel version 2.4.16.  It will not install on any earlier kernels.
+It is possible that it will continue to work on later versions
+of 2.4 and then versions of 2.5 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need the
+appropriate modem eliminator (null modem) cable(s) for this.
+
+Decide on which tty port you want the machines to communicate, then
+connect them up back-to-back using the null modem cable.  COM1 is
+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
+with the two machines prior to trying to debug a kernel.  Once you
+have it working, on the TARGET machine, enter:
+
+setserial /dev/ttyS0 (or what ever tty you are using)
+
+and record the port address and the IRQ number.
+
+On the DEVELOPMENT machine you need to apply the patch for the kgdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and do
+"make Xconfig" where X is one of "x", "menu", or "".  If you are
+configuring in the standard serial driver, it must not be a module.
+Either yes or no is ok, but making the serial driver a module means it
+will initialize after kgdb has set up the UART interrupt code and may
+cause a failure of the control-C option discussed below.  The configure
+question for the serial driver is under the "Character devices" heading
+and is:
+
+"Standard/generic (8250/16550 and compatible UARTs) serial support"
+
+Go down to the kernel debugging menu item and open it up.  Enable the
+kernel kgdb stub code by selecting that item.  You can also choose to
+turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
+to put more debug info (like local symbols) in the object file.  On the
+i386 -g and -ggdb are the same so this option just reduces to "O1".  The
+-O1 reduces the optimization level.  This may be helpful in some cases,
+be aware, however, that this may also mask the problem you are looking
+for.
+
+The baud rate.  Default is 115200.  What ever you choose be sure that
+the host machine is set to the same speed.  I recommend the default.
+
+The port.  This is the I/O address of the serial UART that you should
+have gotten using setserial as described above.  The standard COM1 port
+(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
+3.
+
+The port IRQ (see above).
+
+Stack overflow test.  This option makes a minor change in the trap,
+system call and interrupt code to detect stack overflow and transfer
+control to kgdb if it happens.  (Some platforms have this in the
+baseline code, but the i386 does not.)
+
+You can also configure the system to recognize the boot option
+"console=kgdb" which if given will cause all console output during
+booting to be put thru gdb as well as other consoles.  This option
+requires that gdb and kgdb be connected prior to sending console output
+so, if they are not, a breakpoint is executed to force the connection.
+This will happen before any kernel output (it is going thru gdb, right),
+and will stall the boot until the connection is made.
+
+You can also configure in a patch to SysRq to enable the kGdb SysRq.
+This request generates a breakpoint.  Since the serial port IRQ line is
+set up after any serial drivers, it is possible that this command will
+work when the control-C will not.
+
+Save and exit the Xconfig program.  Then do "make clean" , "make dep"
+and "make bzImage" (or whatever target you want to make).  This gets the
+kernel compiled with the "-g" option set -- necessary for debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on your TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.  I
+usually arrange to copy development:
+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
+via a LAN based NFS access.  That is, I run the cp command on the target
+and copy from the development machine via the LAN.  Run Lilo (see "man
+lilo" for details on how to set this up) on the new kernel on the target
+machine so that it will boot!  Then boot the kernel on the target
+machine.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400 (or what ever speed you have chosen)
+target remote /dev/ttyS0
+
+
+Change the "echo" and "target" definition so that it specifies the tty
+port that you intend to use.  Change the "remotebaud" definition to
+match the data rate that you are going to use for the com line.
+
+You are now ready to try it out.
+
+Boot your target machine with "kgdb" in the boot command i.e. something
+like:
+
+lilo> test kgdb
+
+or if you also want console output thru gdb:
+
+lilo> test kgdb console=kgdb
+
+You should see the lilo message saying it has loaded the kernel and then
+all output stops.  The kgdb stub is trying to connect with gdb.  Start
+gdb something like this:
+
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded it will read your .gdbinit file and, if
+everything is working correctly, you should see gdb print out a few
+lines indicating that a breakpoint has been taken.  It will actually
+show a line of code in the target kernel inside the kgdb activation
+code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux),
+    Copyright 1995 Free Software Foundation, Inc...
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb)
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+If you have the kgdb console enabled when you continue, gdb will print
+out all the console messages.
+
+The above example caused a breakpoint relatively early in the boot
+process.  For the i386 kgdb it is possible to code a break instruction
+as the first C-language point in init/main.c, i.e. as the first instruction
+in start_kernel().  This could be done as follows:
+
+#include <asm/kgdb.h>
+	 breakpoint();
+
+This breakpoint() is really a function that sets up the breakpoint and
+single-step hardware trap cells and then executes a breakpoint.  Any
+early hard coded breakpoint will need to use this function.  Once the
+trap cells are set up they need not be set again, but doing it again
+does not hurt anything, so you don't need to be concerned about which
+breakpoint is hit first.  Once the trap cells are set up (and the kernel
+sets them up in due course even if breakpoint() is never called) the
+macro:
+
+BREAKPOINT;
+
+will generate an inline breakpoint.  This may be more useful as it stops
+the processor at the instruction instead of in a function a step removed
+from the location of interest.  In either case <asm/kgdb.h> must be
+included to define both breakpoint() and BREAKPOINT.
+
+Triggering kgdbstub at other times
+==================================
+
+Often you don't need to enter the debugger until much later in the boot
+or even after the machine has been running for some time.  Once the
+kernel is booted and interrupts are on, you can force the system to
+enter the debugger by sending a control-C to the debug port. This is
+what the first line of the recommended .gdbinit file does.  This allows
+you to start gdb any time after the system is up as well as when the
+system is already at a breakpoint.  (In the case where the system is
+already at a breakpoint the control-C is not needed, however, it will
+be ignored by the target so no harm is done.  Also note the the echo
+command assumes that the port speed is already set.  This will be true
+once gdb has connected, but it is best to set the port speed before you
+run gdb.)
+
+Another simple way to do this is to put the following file in you ~/bin
+directory:
+
+#!/bin/bash
+echo  -e "\003"  > /dev/ttyS0
+
+Here, the ttyS0 should be replaced with what ever port you are using.
+The "\003" is control-C.  Once you are connected with gdb, you can enter
+control-C at the command prompt.
+
+An alternative way to get control to the debugger is to enable the kGdb
+SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
+same time, but push them down in the order given).  To refresh your
+memory of the available SysRq commands try Alt-SysRq-=.  Actually any
+undefined command could replace the "=", but I like to KNOW that what I
+am pushing will never be defined.
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C (see above paragraph).  If the target machine has
+interrupts enabled this will stop it in the kernel and enter the
+debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.  The exploratory breakpoints can be
+entered either thru gdb or hard coded into the source.  This is very
+handy if you do something like:
+
+if (<it hurts>) BREAKPOINT;
+
+
+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
+(debug-nmi.txt) which describes how to create an NMI on an ISA bus
+machine using a paper clip.  I have a sophisticated version of this made
+by wiring a push button switch into a PC104/ISA bus adapter card.  The
+adapter card nicely furnishes wire wrap pins for all the ISA bus
+signals.
+
+When you are done debugging the kernel on the target machine it is a
+good idea to leave it in a running state.  This makes reboots faster,
+bypassing the fsck.  So do a gdb "continue" as the last gdb command if
+this is possible.  To terminate gdb itself on the development machine
+and leave the target machine running, first clear all breakpoints and
+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
+something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy
+things first like double checking your cabling and data rates.  You
+might try some non-kernel based programs to see if the back-to-back
+connection works properly.  Just something simple like cat /etc/hosts
+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
+if you can send data from one machine to the other.  Make sure it works
+in both directions.  There is no point in tearing out your hair in the
+kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
+the code that talks to the serial port on the target side.  There might
+be a problem there.  In particular there is a section of this code that
+tests the UART which will tell you what UART you have if you define
+"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
+report you will need to boot the system without any beakpoints.  This
+allows the kernel to run to the point where it calls kgdb to set up
+interrupts.  At this time kgdb will test the UART and print out the type
+it finds.  (You need to wait so that the printks are actually being
+printed.  Early in the boot they are cached, waiting for the console to
+be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
+to cause a dead lock by calling printk when the console is locked.  The
+stub thus avoids doing printks from breakpoints, especially in the
+serial code.)  At this time, if the UART fails to do the expected thing,
+kgdb will print out (using printk) information on what failed.  (These
+messages will be buried in all the other boot up messages.  Look for
+lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
+once the system is up to view the log.  If this fails or if you still
+don't connect, review your answers for the port address.  Use:
+
+setserial /dev/ttyS0
+
+to get the current port and IRQ information.  This command will also
+tell you what the system found for the UART type. The stub recognizes
+the following UART types:
+
+16450, 16550, and 16550A
+
+If you are really desperate you can use printk debugging in the
+kgdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.  Likewise there are debug printks in the kgdb_serial.c
+code that can be turned on with simple changes in the macro defines.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory when kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread
+related commands (info threads, thread n) can be used.
+
+ia-32 hardware breakpoints
+==========================
+
+kgdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+
+1. Execution breakpoint - An Execution breakpoint is triggered when code
+	at the breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is
+	advisable to use software breakpoints ( break command ) instead
+	of execution hardware breakpoints, unless modification of code
+	is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory
+	location at the breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of
+	a write breakpoint indicates length of the datatype to be
+	watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
+	4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory
+	location at the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occurred.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occurred.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+SMP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
+client, all the processors are forced to enter the debugger. Current
+thread corresponds to the thread running on the processor where
+breakpoint occurred.  Threads running on other processor(s) appear
+similar to other non-running threads in the 'info threads' output.
+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
+records the values of "current" and "regs" for each CPU other than the
+one that hit the breakpoint.  "current" is a pointer to the task
+structure for the task that CPU is running, while "regs" points to the
+saved registers for the task.  This structure can be examined with the
+gdb "p" command.
+
+ia-32 hardware debugging registers on all processors are set to same
+values.  Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and
+restarting another) If the target machine was not inside debugger when
+you killed gdb, gdb cannot connect because the target machine won't
+respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
+e.g. echo -e "\003" > /dev/ttyS1
+This forces that target machine into the debugger, after which you
+can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+Check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+EVENTS
+======
+
+Ever want to know the order of things happening?  Which CPU did what and
+when?  How did the spinlock get the way it is?  Then events are for
+you.  Events are defined by calls to an event collection interface and
+saved for later examination.  In this case, kgdb events are saved by a
+very fast bit of code in kgdb which is fully SMP and interrupt protected
+and they are examined by using gdb to display them.  Kgdb keeps only
+the last N events, where N must be a power of two and is defined at
+configure time.
+
+
+Events are signaled to kgdb by calling:
+
+kgdb_ts(data0,data1)
+
+For each call kgdb records each call in an array along with other info.
+Here is the array definition:
+
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	int	data0;
+	int	data1;
+};
+
+For SMP machines the CPU is recorded, for all machines the TSC is
+recorded (gets a time stamp) as well as the line number and source file
+the call was made from.  The address of the (from), the "if" (interrupt
+flag) and the two data items are also recorded.  The macro kgdb_ts casts
+the types to int, so you can put any 32-bit values here.  There is a
+configure option to select the number of events you want to keep.  A
+nice number might be 128, but you can keep up to 1024 if you want.  The
+number must be a power of two.  An "andthen" macro library is provided
+for gdb to help you look at these events.  It is also possible to define
+a different structure for the event storage and cast the data to this
+structure.  For example the following structure is defined in kgdb:
+
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+
+If you use this for display, the data elements will be displayed as
+pointers to task_struct entries.  You may want to define your own
+structure to use in casting.  You should only change the last two items
+and you must keep the structure size the same.  Kgdb will handle these
+as 32-bit ints, but within that constraint you can define a structure to
+cast to any 32-bit quantity.  This need only be available to gdb and is
+only used for casting in the display code.
+
+Final Items
+===========
+
+I picked up this code from Amit S. Kale and enhanced it.
+
+If you make some really cool modification to this stuff, or if you
+fix a bug, please let me know.
+
+George Anzinger
+<george@mvista.com>
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
+
+(modified by George Anzinger <george@mvista.com>)
+    Extended threads to include the idle threads.
+    Enhancements to allow breakpoint() at first C code.
+    Use of module_init() and __setup() to automate the configure.
+    Enhanced the cpu "collection" code to work in early bring-up.
+    Added ability to call functions from gdb
+    Print info thread stuff without going back to schedule()
+    Now collect the "other" cpus with an IPI/ NMI.
--- diff/Documentation/i386/kgdb/kgdbeth.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdbeth.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,92 @@
+KGDB over ethernet
+==================
+
+Authors
+-------
+
+Robert Walsh <rjwalsh@durables.org>  (2.6 port)
+wangdi <wangdi@clusterfs.com>        (2.6 port)
+Matt Mackall <mpm@selenic.com>       (netpoll api)
+San Mehat                            (original 2.4 code)
+
+
+Introduction
+------------
+
+KGDB supports debugging over ethernet (kgdboe) via polling of a given
+network interface. Most cards should be supported automatically.
+Debugging facilities are available as soon as the network driver and
+kgdboe have initialized. Unfortunately, this is too late in the boot
+process for debugging some issues, but works quite well for many
+others. This should not interfere with normal network usage and
+doesn't require a dedicated NIC.
+
+Terminology
+-----------
+
+This document uses the following terms:
+
+  TARGET: the machine being debugged.
+  HOST:   the machine running gdb.
+
+
+Usage
+-----
+
+You need to use the following command-line option on the TARGET kernel:
+
+  kgdboe=[tgt-port]@<tgt-ip>/[dev],[host-port]@<host-ip>/[host-macaddr]
+
+    where
+        tgt-port      source for UDP packets (defaults to 6443)
+        tgt-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        host-port     HOST UDP port (6442) (not really used)
+        host-ip       IP address for HOST machine
+        host-macaddr  ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff)
+
+  examples:
+
+    kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D
+        this machine is 192.168.0.1 on eth1
+        remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D
+        listen for gdb packets on port 7000
+        send unsolicited gdb packets to port 7001
+
+    kgdboe=@192.168.0.1/,@192.168.0.2/
+        this machine is 192.168.0.1 on default interface eth0
+        remote machine is 192.168.0.2, use default broadcast MAC address
+        listen for gdb packets on default port 6443
+        send unsolicited gdb packets to port 6442
+
+Only packets originating from the configured HOST IP address will be
+accepted by the debugger.
+
+On the HOST side, run gdb as normal and use a remote UDP host as the
+target:
+
+   % gdb ./vmlinux
+   GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
+   Copyright 2003 Free Software Foundation, Inc.
+   GDB is free software, covered by the GNU General Public License, and you are
+   welcome to change it and/or distribute copies of it under certain conditions.
+   Type "show copying" to see the conditions.
+   There is absolutely no warranty for GDB.  Type "show warranty" for details.
+   This GDB was configured as "i386-redhat-linux-gnu"...
+   (gdb) target remote udp:HOSTNAME:6443
+
+You can now continue as if you were debugging over a serial line.
+
+Limitations
+-----------
+
+The current release of this code is exclusive of using kgdb on a
+serial interface, so you must boot without the kgdboe option to use
+serial debugging. Trying to debug the network driver while using it
+will prove interesting.
+
+Bug reports
+-----------
+
+Send bug reports to Robert Walsh <rjwalsh@durables.org> and Matt
+Mackall <mpm@selenic.com>.
--- diff/Documentation/i386/kgdb/loadmodule.sh	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/loadmodule.sh	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,78 @@
+#/bin/sh
+# This script loads a module on a target machine and generates a gdb script.
+# source generated gdb script to load the module file at appropriate addresses
+# in gdb.
+#
+# Usage:
+# Loading the module on target machine and generating gdb script)
+#	[foo]$ loadmodule.sh <modulename>
+#
+# Loading the module file into gdb
+#	(gdb) source <gdbscriptpath>
+#
+# Modify following variables according to your setup.
+#	TESTMACHINE - Name of the target machine
+#	GDBSCRIPTS - The directory where a gdb script will be generated
+#
+# Author: Amit S. Kale (akale@veritas.com).
+#
+# If you run into problems, please check files pointed to by following
+# variables.
+#	ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
+#	MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
+#	GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
+TESTMACHINE=foo
+GDBSCRIPTS=/home/bar
+
+if [ $# -lt 1 ] ; then {
+	echo Usage: $0 modulefile
+	exit
+} ; fi
+
+MODULEFILE=$1
+MODULEFILEBASENAME=`basename $1`
+
+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
+	MODULEFILE=`pwd`/$MODULEFILE
+} fi
+
+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
+MAPFILE=/tmp/$MODULEFILEBASENAME.map
+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
+
+function findaddr() {
+	local ADDR=0x$(echo "$SEGMENTS" | \
+		grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
+		sed 's/[ ]*[^ ]*$//')
+	echo $ADDR
+}
+
+function checkerrs() {
+	if [ "`cat $ERRFILE`" != "" ] ; then {
+		cat $ERRFILE
+		exit
+	} fi
+}
+
+#load the module
+echo Copying $MODULEFILE to $TESTMACHINE
+rcp $MODULEFILE root@${TESTMACHINE}:
+
+echo Loading module $MODULEFILE
+rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
+	> $MAPFILE 2> $ERRFILE
+checkerrs
+
+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
+TEXTADDR=$(findaddr "\\.text[^.]")
+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
+SEGADDRS=`echo "$SEGMENTS" | awk '//{
+	if ($1 != ".text" && $1 != ".this" &&
+	    $1 != ".kstrtab" && $1 != ".kmodtab") {
+		print " -s " $1 " 0x" $3 " "
+	}
+}'`
+LOADSTRING="$LOADSTRING $SEGADDRS"
+echo Generating script $GDBSCRIPT
+echo $LOADSTRING > $GDBSCRIPT
--- diff/Documentation/laptop-mode.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/laptop-mode.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,480 @@
+How to conserve battery power using laptop-mode
+-----------------------------------------------
+
+Document Author: Bart Samwel (bart@samwel.tk)
+Date created: January 2, 2004
+
+Introduction
+------------
+
+Laptopmode is used to minimize the time that the hard disk needs to be spun up,
+to conserve battery power on laptops. It has been reported to cause significant
+power savings.
+
+Contents
+--------
+
+* Introduction
+* The short story
+* Caveats
+* The details
+* Tips & Tricks
+* Control script
+* ACPI integration
+* Monitoring tool
+
+
+The short story
+---------------
+
+If you just want to use it, run the laptop_mode control script (which is included
+at the end of this document) as follows:
+
+# laptop_mode start
+
+Then set your harddisk spindown time to a relatively low value with hdparm:
+
+hdparm -S 4 /dev/hda
+
+The value -S 4 means 20 seconds idle time before spindown. Your harddisk will
+now only spin up when a disk cache miss occurs, or at least once every 10
+minutes to write back any pending changes.
+
+To stop laptop_mode, remount your filesystems with regular commit intervals
+(e.g., 5 seconds), and run "laptop_mode stop".
+
+
+Caveats
+-------
+
+* The downside of laptop mode is that you have a chance of losing up
+  to 10 minutes of work. If you cannot afford this, don't use it!
+
+* Most desktop hard drives have a very limited lifetime measured in spindown
+  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
+  Check your drive's rating, and don't wear down your drive's lifetime if you
+  don't need to.
+
+* If you mount some of your ext3/reiserfs filesystems with the -n option, then
+  the control script will not be able to remount them correctly. You must set
+  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
+  wrong options -- or it will fail because it cannot write to /etc/mtab.
+
+* If you have your filesystems listed as type "auto" in fstab, like I did, then
+  the control script will not recognize them as filesystems that need remounting.
+
+The details
+-----------
+
+Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this
+flag is set, any physical disk read operation (that might have caused the
+hard disk to spin up) causes Linux to flush all dirty blocks. The result
+of this is that after a disk has spun down, it will not be spun up anymore
+to write dirty blocks, because those blocks had already been written
+immediately after the most recent read operation
+
+To increase the effectiveness of the laptop_mode strategy, the laptop_mode
+control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
+/proc/sys/vm to about 10 minutes (by default), which means that pages that are
+dirtied are not forced to be written to disk as often. The control script also
+changes the dirty background ratio, so that background writeback of dirty pages
+is not done anymore. Combined with a higher commit value (also 10 minutes) for
+ext3 or ReiserFS filesystems (also done automatically by the control script),
+this results in concentration of disk activity in a small time interval which
+occurs only once every 10 minutes, or whenever the disk is forced to spin up by
+a cache miss. The disk can then be spun down in the periods of inactivity.
+
+If you want to find out which process caused the disk to spin up, you can
+gather information by setting the flag /proc/sys/vm/block_dump. When this flag
+is set, Linux reports all disk read and write operations that take place, and
+all block dirtyings done to files. This makes it possible to debug why a disk
+needs to spin up, and to increase battery life even more.
+
+If 10 minutes is too much or too little downtime for you, you can configure
+this downtime as follows. In the control script, set the MAX_AGE value to the
+maximum number of seconds of disk downtime that you would like. You should
+then set your filesystem's commit interval to the same value. The dirty ratio
+is also configurable from the control script.
+
+If you don't like the idea of the control script remounting your filesystems
+for you, you can change DO_REMOUNTS to 0 in the script.
+
+Thanks to Kiko Piris, the control script can be used to enable laptop mode on
+both the Linux 2.4 and 2.6 series.
+
+
+Tips & Tricks
+-------------
+
+* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
+  of his regular 3 to 3.5 hours) using very aggressive power management (hdparm
+  -B1) and a spindown time of 5 seconds (hdparm -S1).
+
+* You can spin down the disk while playing MP3, by setting the disk readahead
+  to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at
+  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
+  Kania.)
+
+* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
+  of colours that my display uses it consumes less battery power. I've seen
+  this on powerbooks too. I hope that this is a piece of information that
+  might be useful to the Laptop Mode patch or it's users."
+
+
+Control script
+--------------
+
+Please note that this control script works for the Linux 2.4 and 2.6 series.
+
+--------------------CONTROL SCRIPT BEGIN------------------------------------------
+#!/bin/sh
+
+# start or stop laptop_mode, best run by a power management daemon when
+# ac gets connected/disconnected from a laptop
+#
+# install as /sbin/laptop_mode
+#
+# Contributors to this script:   Kiko Piris
+#				 Bart Samwel
+#				 Dax Kelson
+# Original Linux 2.4 version by: Jens Axboe
+
+parse_mount_opts () {
+	echo "$*"			| \
+	sed 's/commit=[0-9]*//g'	| \
+	sed 's/,,*/,/g'			| \
+	sed 's/^,//'			| \
+	sed 's/,$//'			| \
+	cat -
+}
+
+KLEVEL="$(uname -r | cut -c1-3)"
+case "$KLEVEL" in
+	"2.4")
+		true
+		;;
+	"2.6")
+		true
+		;;
+	*)
+		echo "Unhandled kernel level: $KLEVEL ('uname -r' = '$(uname -r)')"
+		exit 1
+		;;
+esac
+
+# Shall we remount journaled fs. with appropiate commit interval? (1=yes)
+DO_REMOUNTS=1
+
+# age time, in seconds. should be put into a sysconfig file
+MAX_AGE=600
+
+# Allowed dirty ratio, in pct. should be put into a sysconfig file as well.
+DIRTY_RATIO=40
+
+# kernel default dirty buffer age
+DEF_AGE=30
+DEF_UPDATE=5
+DEF_DIRTY_BACKGROUND_RATIO=10
+DEF_DIRTY_RATIO=40
+
+
+if [ ! -e /proc/sys/vm/laptop_mode ]; then
+	echo "Kernel is not patched with laptop_mode patch."
+	exit 1
+fi
+
+if [ ! -w /proc/sys/vm/laptop_mode ]; then
+	echo "You do not have enough privileges to enable laptop_mode."
+	exit 1
+fi
+
+case "$1" in
+	start)
+		AGE=$((100*$MAX_AGE))
+		echo -n "Starting laptop_mode"
+		case "$KLEVEL" in
+			"2.4")
+				echo "1"				> /proc/sys/vm/laptop_mode
+				echo "30 500 0 0 $AGE $AGE 60 20 0"	> /proc/sys/vm/bdflush
+				;;
+			"2.6")
+				echo "1"				> /proc/sys/vm/laptop_mode
+				echo "$AGE"				> /proc/sys/vm/dirty_writeback_centisecs
+				echo "$AGE"				> /proc/sys/vm/dirty_expire_centisecs
+				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
+				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_background_ratio
+				;;
+		esac
+		if [ $DO_REMOUNTS -eq 1 ]; then
+			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
+				case "$FST" in
+					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
+				esac
+			done
+		fi
+		echo "."
+		;;
+	stop)
+		U_AGE=$((100*$DEF_UPDATE))
+		B_AGE=$((100*$DEF_AGE))
+		echo -n "Stopping laptop_mode"
+		case "$KLEVEL" in
+			"2.4")
+				echo "0"				> /proc/sys/vm/laptop_mode
+				echo "30 500 0 0 $U_AGE $B_AGE 60 20 0"	> /proc/sys/vm/bdflush
+				;;
+			"2.6")
+				echo "0"				> /proc/sys/vm/laptop_mode
+				echo "$U_AGE"				> /proc/sys/vm/dirty_writeback_centisecs
+				echo "$B_AGE"				> /proc/sys/vm/dirty_expire_centisecs
+				echo "$DEF_DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
+				echo "$DEF_DIRTY_BACKGROUND_RATIO"	> /proc/sys/vm/dirty_background_ratio
+				;;
+		esac
+		if [ $DO_REMOUNTS -eq 1 ]; then
+			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
+				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
+				case "$FST" in
+					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
+				esac
+			done
+		fi
+		echo "."
+		;;
+	*)
+		echo "$0 {start|stop}"
+		;;
+
+esac
+
+exit 0
+
+--------------------CONTROL SCRIPT END--------------------------------------------
+
+
+ACPI integration
+----------------
+
+Dax Kelson submitted this so that the ACPI acpid daemon will
+kick off the laptop_mode script and run hdparm.
+
+---------------------------/etc/acpi/events/ac_adapter BEGIN-------------------------------------------
+event=ac_adapter
+action=/etc/acpi/actions/battery.sh
+---------------------------/etc/acpi/events/ac_adapter END-------------------------------------------
+
+---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------------------------------
+#!/bin/sh
+
+# cpu throttling
+# cat /proc/acpi/processor/CPU0/throttling for more info
+ACAD_THR=0
+BATT_THR=2
+
+# spindown time for HD (man hdparm for valid values)
+# I prefer 2 hours for acad and 20 seconds for batt
+ACAD_HD=244
+BATT_HD=4
+
+# ac/battery event handler
+
+status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/AC/state`
+
+case $status in
+        "on-line")
+                echo "Setting HD spindown to 2 hours"
+                /sbin/laptop-mode stop
+                /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
+                /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
+                #echo -n $ACAD_CPU:$ACAD_THR > /proc/acpi/processor/CPU0/limit
+                exit 0
+        ;;
+        "off-line")
+                echo "Setting HD spindown to 20 seconds"
+                /sbin/laptop-mode start
+                /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
+                /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
+                #echo -n $BATT_CPU:$BATT_THR > /proc/acpi/processor/CPU0/limit
+                exit 0
+        ;;
+esac
+---------------------------/etc/acpi/actions/battery.sh END-------------------------------------------
+
+Monitoring tool
+---------------
+
+Bartek Kania submitted this, it can be used to measure how much time your disk
+spends spun up/down.
+
+---------------------------dslm.c BEGIN-------------------------------------------
+/*
+ * Simple Disk SLeep Monitor
+ *  by Bartek Kania
+ * Licenced under the GPL
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+
+#ifdef DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+int endit = 0;
+
+/* Check if the disk is in powersave-mode
+ * Most of the code is stolen from hdparm.
+ * 1 = active, 0 = standby/sleep, -1 = unknown */
+int check_powermode(int fd)
+{
+    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
+    int state;
+
+    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
+	&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
+	&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
+	if (errno != EIO || args[0] != 0 || args[1] != 0) {
+	    state = -1; /* "unknown"; */
+	} else
+	    state = 0; /* "sleeping"; */
+    } else {
+	state = (args[2] == 255) ? 1 : 0;
+    }
+    D(printf(" drive state is:  %s\n", state));
+
+    return state;
+}
+
+char *state_name(int i)
+{
+    if (i == -1) return "unknown";
+    if (i == 0) return "sleeping";
+    if (i == 1) return "active";
+
+    return "internal error";
+}
+
+char *myctime(time_t time)
+{
+    char *ts = ctime(&time);
+    ts[strlen(ts) - 1] = 0;
+
+    return ts;
+}
+
+void measure(int fd)
+{
+    time_t start_time;
+    int last_state;
+    time_t last_time;
+    int curr_state;
+    time_t curr_time = 0;
+    time_t time_diff;
+    time_t active_time = 0;
+    time_t sleep_time = 0;
+    time_t unknown_time = 0;
+    time_t total_time = 0;
+    int changes = 0;
+    float tmp;
+
+    printf("Starting measurements\n");
+
+    last_state = check_powermode(fd);
+    start_time = last_time = time(0);
+    printf("  System is in state %s\n\n", state_name(last_state));
+
+    while(!endit) {
+	sleep(1);
+	curr_state = check_powermode(fd);
+
+	if (curr_state != last_state || endit) {
+	    changes++;
+	    curr_time = time(0);
+	    time_diff = curr_time - last_time;
+
+	    if (last_state == 1) active_time += time_diff;
+	    else if (last_state == 0) sleep_time += time_diff;
+	    else unknown_time += time_diff;
+
+	    last_state = curr_state;
+	    last_time = curr_time;
+
+	    printf("%s: State-change to %s\n", myctime(curr_time),
+		   state_name(curr_state));
+	}
+    }
+    changes--; /* Compensate for SIGINT */
+
+    total_time = time(0) - start_time;
+    printf("\nTotal running time:  %lus\n", curr_time - start_time);
+    printf(" State changed %d times\n", changes);
+
+    tmp = (float)sleep_time / (float)total_time * 100;
+    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
+    tmp = (float)active_time / (float)total_time * 100;
+    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
+    tmp = (float)unknown_time / (float)total_time * 100;
+    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
+}
+
+void ender(int s)
+{
+    endit = 1;
+}
+
+void usage()
+{
+    puts("usage: dslm [-w <time>] <disk>");
+    exit(0);
+}
+
+int main(int ac, char **av)
+{
+    int fd;
+    char *disk = 0;
+    int settle_time = 60;
+
+    /* Parse the simple command-line */
+    if (ac == 2)
+	disk = av[1];
+    else if (ac == 4) {
+	settle_time = atoi(av[2]);
+	disk = av[3];
+    } else
+	usage();
+
+    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
+	printf("Can't open %s, because: %s\n", disk, strerror(errno));
+	exit(-1);
+    }
+
+    if (settle_time) {
+	printf("Waiting %d seconds for the system to settle down to "
+	       "'normal'\n", settle_time);
+	sleep(settle_time);
+    } else
+	puts("Not waiting for system to settle down");
+
+    signal(SIGINT, ender);
+
+    measure(fd);
+
+    close(fd);
+
+    return 0;
+}
+---------------------------dslm.c END---------------------------------------------
--- diff/Documentation/must-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/must-fix.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,288 @@
+
+Must-fix bugs
+=============
+
+drivers/char/
+~~~~~~~~~~~~~
+
+o TTY locking is broken.
+
+  o see FIXME in do_tty_hangup().  This causes ppp BUGs in local_bh_enable()
+
+  o Other problems: aviro, dipankar, Alan have details.
+
+  o somebody will have to document the tty driver and ldisc API
+
+drivers/tty
+~~~~~~~~~~~
+
+o viro: tty_driver refcounting, tty/misc/upper levels of sound still not
+  completely fixed.
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o loop.c: Concurrent write access on block devices might cause a deadlock
+  of the complete system. See:
+  http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w==
+  http://bugzilla.kernel.org/show_bug.cgi?id=1198
+  Thread of possible fix:
+  http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html
+
+  (Fruhwirth Clemens)
+
+o ideraid hasn't been ported to 2.5 at all yet.
+
+  We need to understand whether the proposed BIO split code will suffice
+  for this.
+
+drivers/input/
+~~~~~~~~~~~~~~
+
+o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0
+  currently on these remaining in my/Linus' tree.)
+
+o viro: large absence of locking.
+
+o viro: parport is nearly as bad as that and there the code is more hairy.
+  IMO parport is more of "figure out what API changes are needed for its
+  users, get them done ASAP, then fix generic layer at leisure"
+
+o (Albert Cahalan) Lots of people (check Google) get this message from the
+  kernel:
+
+  psmouse.c: Lost synchronization, throwing 2 bytes away.
+
+  (the number of bytes will be 1, 2, or 3)
+
+  At work, I get it when there is heavy NFS traffic.  The mouse goes crazy,
+  jumping around and doing random cut-and-paste all over everything.  This
+  is with a decently fast and modern PC.
+
+o There seem to be too many reports of keyboards and mice failing or acting
+  strangely.
+
+
+drivers/misc/
+~~~~~~~~~~~~~
+
+o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM
+  tree.  (touchscreen, audio, gpio, type device.)
+
+  These need to be moved out of drivers/misc/ and into real places
+
+o viro: actually, misc.c has a good chance to die.  With cdev-cidr that's
+  trivial.
+
+drivers/net/
+~~~~~~~~~~~~
+
+drivers/net/irda/
+~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes)
+
+o irport need to be converted to sir-kthread
+
+o dongle drivers need to be converted to sir-dev (in progress)
+
+o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress)
+
+
+drivers/pci/
+~~~~~~~~~~~~
+
+o alan: Some cardbus crashes the system
+
+  (bugzilla, please?)
+
+drivers/pcmcia/
+~~~~~~~~~~~~~~~
+
+o alan: This is a locking disaster.
+
+  (rmk, brodo: in progress)
+
+drivers/pld/
+~~~~~~~~~~~~
+
+o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld)
+
+  (rmk: will work out what to do here.  maybe drivers/arm/)
+
+drivers/video/
+~~~~~~~~~~~~~~
+
+o Lots of drivers don't compile, others do but don't work.
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping
+
+o Make inia100, cpqfc, pci2000 and dc390t compile
+
+o Convert
+
+   wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93
+
+   53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000
+   pci2220i dc390t
+
+  To new error handling
+
+  It also might be possible to shift the 53c7xx based drivers over to
+  53c700 which does the new EH stuff, but I don't have the hardware to check
+  such a shift.
+
+  For the non-compiling stuff, I've probably missed a few that just aren't
+  compilable on my platforms, so any updates would be welcome.  Also, are
+  some of our non-compiling or unconverted drivers obsolete?
+
+fs/
+~~~
+
+o AIO/direct-IO writes can race with truncate and wreck filesystems.
+  (Badari has a patch)
+
+o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr.
+  In progress.
+
+o forward-port sct's O_DIRECT fixes (Badari has a patch)
+
+o viro: there is some generic stuff for namei/namespace/super, but that's a
+  slow-merge and can go in 2.6 just fine
+
+o trond: NFS has a mmap-versus-truncate problem (fixed? needs testing)
+
+o trond: NFSv4 client, bugs in lockd, RPSEC_GSS for NFSv[23], some atomic open
+  bits. more info: http://www.fys.uio.no/~trondmy/src/Linux-2.6.x/2.6.0-test11/
+
+kernel/sched.c
+~~~~~~~~~~~~~~
+
+o Starvation, general interactivity need close monitoring.
+
+o SMT aware scheduler (Ingo, Rusty, Nick have implementations)
+
+kernel/
+~~~~~~~
+
+o Alan: 32bit uid support is *still* broken for process accounting.
+
+  Create a 32bit uid, turn accounting on.  Shock horror it doesn't work
+  because the field is 16bit.  We need an acct structure flag day for 2.6
+  IMHO
+
+  (alan has patch)
+
+o viro: core sysctl code is racy.  And its interaction wiuth sysfs
+
+o (ingo) rwsems (on x86) are limited to 32766 waiting processes.  This
+  means that setting pid_max to above 32K is unsafe :-(
+
+  An option is to use CONFIG_RWSEM_GENERIC_SPINLOCK variant all the time,
+  for all archs, and not inline any part of the ops.
+
+lib/kobject.c
+~~~~~~~~~~~~~
+
+o kobject refcounting (comments from Al Viro):
+
+  _anything_ can grab a temporary reference to kobject.  IOW, if kobject is
+  embedded into something that could be freed - it _MUST_ have a destructor
+  and that destructor _MUST_ be the destructor for containing object.
+
+  Any violation of the above (and we already have a bunch of those) is a
+  user-triggerable memory corruption.
+
+  We can tolerate it for a while in 2.5 (e.g.  during work on susbsystem we
+  can decide to switch to that way of handling objects and have subsystem
+  vulnerable for a while), but all such windows must be closed before 2.6
+  and during 2.6 we can't open them at all.
+
+o All block drivers which control multiple gendisks with a single
+  request_queue are broken, due to one-to-one assumptions in the request
+  queue sysfs hookup.
+
+mm/
+~~~
+
+o GFP_DMA32 (or something like that).  Lots of ideas.  jejb, zaitcev,
+  willy, arjan, wli.
+
+  Specifically, 64-bit systems need to be able to enforce 32-bit addressing
+  limits for device metadata like network cards' ring buffers and SCSI
+  command descriptors.
+
+o access_process_vm() doesn't flush right.  We probably need new flushing
+  primitives to do this (davem?)
+
+
+modules
+~~~~~~~
+
+  (Rusty)
+
+net/
+~~~~
+
+  (davem)
+
+o UDP apps can in theory deadlock, because the ip_append_data path can end
+  up sleeping while the socket lock is held.
+
+  It is OK to sleep with the socket held held, normally.  But in this case
+  the sleep happens while waiting for socket memory/space to become
+  available, if another context needs to take the socket lock to free up the
+  space we could hang.
+
+  I sent a rough patch on how to fix this to Alexey, and he is analyzing
+  the situation.  I expect a final fix from him next week or so.
+
+o Semantics for IPSEC during operations such as TCP connect suck currently.
+
+  When we first try to connect to a destination, we may need to ask the
+  IPSEC key management daemon to resolve the IPSEC routes for us.  For the
+  purposes of what the kernel needs to do, you can think of it like ARP.  We
+  can't send the packet out properly until we resolve the path.
+
+  What happens now for IPSEC is basically this:
+
+  O_NONBLOCK: returns -EAGAIN over and over until route is resolved
+
+  !O_NONBLOCK: Sleeps until route is resolved
+
+  These semantics are total crap.  The solution, which Alexey is working
+  on, is to allow incomplete routes to exist.  These "incomplete" routes
+  merely put the packet onto a "resolution queue", and once the key manager
+  does it's thing we finish the output of the packet.  This is precisely how
+  ARP works.
+
+  I don't know when Alexey will be done with this.
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+  (Rusty)
+
+sound/
+~~~~~~
+
+global
+~~~~~~
+
+o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit
+  means extra work on nfsd/raid/etc.
+
+o alan: Forward port 2.4 fixes
+  - Chris Wright: Security fixes including execve holes, execve vs proc races
+
+o There are about 60 or 70 security related checks that need doing
+  (copy_user etc) from Stanford tools.  (badari is looking into this, and
+  hollisb)
+
+o A couple of hundred real looking bugzilla bugs
+
+o viro: cdev rework. Mostly done.
+
--- diff/Documentation/networking/netconsole.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/networking/netconsole.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,57 @@
+
+started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
+2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+
+Please send bug reports to Matt Mackall <mpm@selenic.com>
+
+This module logs kernel printk messages over UDP allowing debugging of
+problem where disk logging fails and serial consoles are impractical.
+
+It can be used either built-in or as a module. As a built-in,
+netconsole initializes immediately after NIC cards and will bring up
+the specified interface as soon as possible. While this doesn't allow
+capture of early kernel panics, it does capture most of the boot
+process.
+
+It takes a string configuration parameter "netconsole" in the
+following format:
+
+ netconsole=[src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
+
+   where
+        src-port      source for UDP packets (defaults to 6665)
+        src-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        tgt-port      port for logging agent (6666)
+        tgt-ip        IP address for logging agent
+        tgt-macaddr   ethernet MAC address for logging agent (broadcast)
+
+Examples:
+
+ linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc
+
+  or
+
+ insmod netconsole netconsole=@/,@10.0.0.2/
+
+Built-in netconsole starts immediately after the TCP stack is
+initialized and attempts to bring up the supplied dev at the supplied
+address.
+
+The remote host can run either 'netcat -u -l -p <port>' or syslogd.
+
+WARNING: the default target ethernet setting uses the broadcast
+ethernet address to send packets, which can cause increased load on
+other systems on the same ethernet segment.
+
+NOTE: the network device (eth1 in the above case) can run any kind
+of other network traffic, netconsole is not intrusive. Netconsole
+might cause slight delays in other traffic if the volume of kernel
+messages is high, but should have no other impact.
+
+Netconsole was designed to be as instantaneous as possible, to
+enable the logging of even the most critical kernel bugs. It works
+from IRQ contexts as well, and does not enable interrupts while
+sending packets. Due to these unique needs, configuration can not
+be more automatic, and some fundamental limitations will remain:
+only IP networks, UDP packets and ethernet devices are supported.
--- diff/Documentation/sched-domains.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/sched-domains.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,55 @@
+Each CPU has a "base" scheduling domain (struct sched_domain). These are
+accessed via cpu_sched_domain(i) and this_sched_domain() macros. The domain
+hierarchy is built from these base domains via the ->parent pointer. ->parent
+MUST be NULL terminated, and domain structures should be per-CPU as they
+are locklessly updated.
+
+Each scheduling domain spans a number of CPUs (stored in the ->span field).
+A domain's span MUST be a superset of it child's span, and a base domain
+for CPU i MUST span at least i. The top domain for each CPU will generally
+span all CPUs in the system although strictly it doesn't have to, but this
+could lead to a case where some CPUs will never be given tasks to run unless
+the CPUs allowed mask is explicitly set. A sched domain's span means "balance
+process load among these CPUs".
+
+Each scheduling domain must have one or more CPU groups (struct sched_group)
+which are organised as a circular one way linked list from the ->groups
+pointer. The union of cpumasks of these groups MUST be the same as the
+domain's span. The intersection of cpumasks from any two of these groups
+MUST be the empty set. The group pointed to by the ->groups pointer MUST
+contain the CPU to which the domain belongs. Groups may be shared among
+CPUs as they contain read only data after they have been set up.
+
+Balancing within a sched domain occurs between groups. That is, each group
+is treated as one entity. The load of a group is defined as the sum of the
+load of each of its member CPUs, and only when the load of a group becomes
+out of balance are tasks moved between groups.
+
+In kernel/sched.c, rebalance_tick is run periodically on each CPU. This
+function takes its CPU's base sched domain and checks to see if has reached
+its rebalance interval. If so, then it will run load_balance on that domain.
+rebalance_tick then checks the parent sched_domain (if it exists), and the
+parent of the parent and so forth.
+
+*** Implementing sched domains ***
+The "base" domain will "span" the first level of the hierarchy. In the case
+of SMT, you'll span all siblings of the physical CPU, with each group being
+a single virtual CPU.
+
+In SMP, the parent of the base domain will span all physical CPUs in the
+node. Each group being a single physical CPU. Then with NUMA, the parent
+of the SMP domain will span the entire machine, with each group having the
+cpumask of a node. Or, you could do multi-level NUMA or Opteron, for example,
+might have just one domain covering its one NUMA level.
+
+The implementor should read comments in include/linux/sched.h:
+struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
+the specifics and what to tune.
+
+Implementors should change the line
+#undef SCHED_DOMAIN_DEBUG
+to
+#define SCHED_DOMAIN_DEBUG
+in kernel/sched.c as this enables an error checking parse of the sched domains
+which should catch most possible errors (described above). It also prints out
+the domain structure in a visual format.
--- diff/Documentation/should-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/should-fix.txt	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,545 @@
+Not-ready features and speedups
+===============================
+
+Legend:
+
+PRI1:	We're totally lame if this doesn't get in
+PRI2:	Would be nice
+PRI3:	Not very important
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o viro: paride drivers need a big cleanup. Partially done, but ATAPI drivers
+  need serious work and bug fixing.
+
+  PRI2
+
+drivers/char/rtc/
+~~~~~~~~~~~~~~~~~
+
+o rmk, trini: add support for alarms to the existing generic rtc driver.
+
+  PRI2
+
+console drivers
+~~~~~~~~~~~~~~~
+  (Pavel Machek <pavel@ucw.cz>)
+
+o There are few must-fix bugs in cursor handling.
+
+o Play with gpm selection for a while and your cursor gets corrupted with
+  random dots. Ouch.
+
+device mapper
+~~~~~~~~~~~~~
+
+o ioctl interface cleanup patch is ready (redo the structure layouts)
+
+  PRI1
+
+o A port of the 2.4 snapshot and mirror targets is in progress
+
+  PRI1
+
+o the fs interface to dm needs to be redone.  gregkh was going to work on
+  this.  viro is interested in seeing work thus-far.
+
+  PRI2
+
+drivers/net/wireless/
+~~~~~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes <jt@bougret.hpl.hp.com>)
+
+o get HostAP driver in the kernel.  No consolidation of the 802.11
+  management across driver can happen until this one is in (which is probably
+  2.7.X material).  I think Jouni is mostly ready but didn't find time for
+  it.
+
+  PRI2
+
+o get more wireless drivers into the kernel.  The most "integrable" drivers
+  at this point seem the NWN driver, Pavel's Spectrum driver.
+
+  PRI1
+
+drivers/usb/gadget/
+~~~~~~~~~~~~~~~~~~~
+
+o rmk: SA11xx USB client/gadget code (David B has been doing some work on
+  this, and keeps trying to prod me, but unfortunately I haven't had the time
+  to look at his work, sorry David.)
+
+  PRI3
+
+fs/
+~~~
+
+o ext3 and ext2 block allocators have serious failure modes - interleaved
+  allocations.
+
+  PRI3
+
+o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling
+  patches.  They make reiserfs a lot safer.
+
+  Ordered: PRI2
+  data journalled: PRI3
+
+o viro: convert more filesystems to use lib/parser.c for options.
+
+  PRI2
+
+o aio: fs IO isn't async at present.  suparna has restart patches, they're
+  in -mm.  Need to get Ben to review/comment.
+
+  PRI1.
+
+o drepper: various filesystems use ->pid wrongly
+
+  PRI1
+
+o hch: devfs: there's a fundamental lookup vs devfsd race that's only
+  fixable by introducing a lookup vs devfs deadlock.  I can't see how this is
+  fixable without getting rid of the current devfsd design.  Mandrake seems
+  to have a workaround for this so this is at least not triggered so easily,
+  but that's not what I'd consider a fix..
+
+  PRI2
+
+kernel/
+~~~~~~~
+
+o rusty: Zippel's Reference count simplification.  Tricky code, but cuts
+  about 120 lines from module.c.  Patch exists, needs stressing.
+
+  PRI3
+
+o rusty: Fix module-failed-init races by starting module "disabled".  Patch
+  exists, requires some subsystems (ie.  add_partition) to explicitly say
+  "make module live now".  Without patch we are no worse off than 2.4 etc.
+
+  PRI1
+
+o Integrate userspace irq balancing daemon.
+
+  PRI2
+
+o kexec.  Seems to work, was in -mm.
+
+  PRI3
+
+o rmk: lib/inflate.c must not use static variables (causes these to be
+  referenced via GOTOFF relocations in PIC decompressor.  We have a PIC
+  decompressor to avoid having to hard code a per platform zImage link
+  address into the makefiles.)
+
+  PRI2
+
+o klibc merge?
+
+  PRI2
+
+mm/
+~~~
+
+o dropbehind for large files
+
+  PRI2
+
+net/
+~~~~
+
+  (davem)
+
+o Real serious use of IPSEC is hampered by lack of MPLS support.  MPLS is a
+  switching technology that works by switching based upon fixed length labels
+  prepended to packets.  Many people use this and IPSEC to implement VPNs
+  over public networks, it is also used for things like traffic engineering.
+
+  A good reference site is:
+
+	http://www.mplsrc.com/
+
+  Anyways, an existing (crappy) implementation exists.  I've almost
+  completed a rewrite, I should have something in the tree next week.
+
+  PRI1
+
+o Sometimes we generate IP fragments when it truly isn't necessary.
+
+  The way IP fragmentation is specified, each fragment must be modulo 8
+  bytes in length.  So suppose the device has an MTU that is not 0 modulo 8,
+  ethernet even classifies in this way.  1500 == (8 * 187) + 4
+
+  Our IP fragmenting engine can fragment on packets that are sized within
+  the last modulo 8 bytes of the MTU.  This happens in obscure cases, but it
+  does happen.
+
+  I've proposed a fix to Alexey, whereby very late in the output path we
+  check the packet, if we fragmented but the data length would fit into the
+  MTU we unfragment the packet.
+
+  This is low priority, because technically it creates suboptimal behavior
+  rather than mis-operation.
+
+  PRI1
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+o Lots of misc. cleanups, which are happening slowly.
+
+  PRI2
+
+power management
+~~~~~~~~~~~~~~~~
+
+o Pat and Pavel disagree over swsusp. Need to sort that out.
+
+  PRI2
+
+o Frame buffer restore codepaths (that requires some deep PCI magic)
+
+  PRI2
+
+o XFree86 hooks
+
+  PRI2
+
+o AGP restoration
+
+  PRI2
+
+o DRI restoration
+
+  (davej/Alan: not super-critical, can crash laptop on restore.  davej
+  looking into it.)
+
+  PRI2
+
+o IDE suspend/resume without races (Ben is looking at this a little)
+
+  PRI2
+
+o Pat: There are already CPU device structures; MTRRs should be a
+  dynamically registered interface of CPUs, which implies there needs
+  to be some other glue to know that there are MTRRs that need to be
+  saved/restored.
+
+  PRI1
+
+global
+~~~~~~
+
+o We need a kernel side API for reporting error events to userspace (could
+  be async to 2.6 itself)
+
+  (Prototype core based on netlink exists)
+
+  PRI2
+
+o Kai: Introduce a sane, easy and standard way to build external modules
+  - make clean and make modules_install are both broken
+
+  PRI2
+
+drivers
+~~~~~~~
+
+o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do
+  multiheader right and so on
+
+  PRI1
+
+drivers/acpi/
+~~~~~~~~~~~~~
+
+o Fix acpi for all newer IBM Thinkpads see
+  http://bugme.osdl.org/show_bug.cgi?id=1038 for more information
+
+o alan: VIA APIC stuff is one bit of this, there are also some other
+  reports that were caused by ACPI not setting level v edge trigger some
+  times
+
+  PRI1
+
+o mochel: it seems the acpi irq routing code could use a serious rewrite.
+
+  grover: The problem is the ACPI irq routing code is trying to piggyback
+  on the existing MPS-specific data structures, and it's generally a hack.
+  So yes mochel is right, but it is also purging MPS-ities from common code
+  as well.  I've done some preliminary work in this area and it doesn't seem
+  to break anything (yet) but a rewrite in this area imho should not be
+  rushed out the door.  And, I think the above bugs can be fixed w/o the
+  rewrite.
+
+  PRI2
+
+o mochel: ACPI suspend doesn't work.  Important, not cricital.  Pat is
+  working it.
+
+  PRI2
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o More testing of floppy
+
+  PRI3
+
+drivers/char/
+~~~~~~~~~~~~~
+
+
+drivers/ide/
+~~~~~~~~~~~~
+
+  (Alan)
+
+o IDE PIO has occasional unexplained PIO disk eating reports
+
+  PRI1
+
+o IDE has multiple zillions of races/hangs in 2.5 still
+
+  PRI1
+
+o IDE scsi needs rewriting
+
+  PRI2
+
+o IDE needs significant reworking to handle Simplex right
+
+  PRI2
+
+o IDE hotplug handling for 2.5 is completely broken still
+
+  PRI2
+
+o There are lots of other IDE bugs that wont go away until the taskfile
+  stuff is included, the locking bugs that allow any user to hang the IDE
+  layer in 2.5, and some other updates are forward ported.  (esp.  HPT372N).
+
+  PRI1
+
+drivers/isdn/
+~~~~~~~~~~~~~
+
+  (Kai, rmk)
+
+o isdn_tty locking is completely broken (cli() and friends)
+
+  PRI2
+
+o fix other drivers
+
+  PRI2
+
+o lots more cleanups, adaption to recent APIs etc
+
+  PRI3
+
+o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent
+  3-set patch for serial stuff)
+
+  Alternatively, we could re-introduce the fallback to driver ioctl parsing
+  for these if not enough drivers get updated.
+
+  PRI3
+
+drivers/net/
+~~~~~~~~~~~~
+
+o davej: Either Wireless network drivers or PCMCIA broke somewhen.  A
+  configuration that worked fine under 2.4 doesn't receive any packets.  Need
+  to look into this more to make sure I don't have any misconfiguration that
+  just 'happened to work' under 2.4
+
+  PRI1
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o jejb: qlogic -
+
+  o Merge the feral driver.  It covers all qlogic chips: 1020 all the way
+    up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5
+
+  o qla2xxx: only for FC chips.  Has significant build issues.  hch
+    promises to send me a "must fix" list for this.
+    http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5
+
+  PRI2
+
+o hch, Mike Anderson, Badari Pulavarty: scsi locking issues
+
+  o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd
+    with very unclear locking, many of them probably want to become
+    atomic_t's or bitmaps (for the 1bit bitfields).
+
+  o there's lots of volatile abuse in the scsi code that needs to be
+    thought about.
+
+  o there's some global variables incremented without any locks
+
+  PRI2
+
+sound/
+~~~~~~
+
+o rmk: several OSS drivers for SA11xx-based hardware in need of
+  ALSA-ification and L3 bus support code for these.
+
+o rmk: need to complete ALSA-ification of the WaveArtist driver for both
+  NetWinder and other stuff (there's some fairly fundamental differences in
+  the way the mixer needs to be handled for the NetWinder.)
+
+  (Issues with forward-porting 2.4 bugfixes.)
+  (Killing off OSS is 2.7 material)
+
+PRI2
+
+arch/i386/
+~~~~~~~~~~
+
+o Also PC9800 merge needs finishing to the point we want for 2.6 (not all).
+
+  PRI3
+
+o davej: PAT support (for mtrr exhaustion w/ AGP)
+
+  PRI2
+
+o 2.5.x won't boot on some 440GX
+
+  alan: Problem understood now, feasible fix in 2.4/2.4-ac.  (440GX has two
+  IRQ routers, we use the $PIR table with the PIIX, but the 440GX doesnt use
+  the PIIX for its IRQ routing).  Fall back to BIOS for 440GX works and Intel
+  concurs.
+
+  PRI1
+
+o 2.5.x doesn't handle VIA APIC right yet.
+
+  1. We must write the PCI_INTERRUPT_LINE
+
+  2. We have quirk handlers that seem to trash it.
+
+  PRI1
+
+o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan
+  Hollis)
+
+  alan: ECC - I have some test bits from Dan's stuff - they need no kernel
+  core changes for most platforms.  That means we can treat it as a random
+  driver merge.
+
+  PRI3
+
+o alan: 2.4 has some fixes for tsc handling bugs.  One where some bioses in
+  SMM mode mess up our toggle on the time high/low or mangle the counter and
+  one where a few chips need religious use of _p for timer access and we
+  don't do that.  This is forward porting little bits of fixup.
+
+  ACPI HZ stuff we can't trap - a lot of ACPI is implemented as outb's
+  triggering SMM traps
+
+  PRI1
+
+arch/x86_64/
+~~~~~~~~~~~~
+
+  (Andi)
+
+o time handling is broken. Need to move up 2.4 time.c code.
+
+  PRI1
+
+o NMI watchdog seems to tick too fast
+
+  PRI2
+
+o need to coredump 64bit vsyscall code with dwarf2
+
+  PRI2
+
+o move 64bit signal trampolines into vsyscall code and add dwarf2 for it.
+  (in progress)
+
+  PRI1
+
+o describe kernel assembly with dwarf2 annotations for kgdb
+
+  PRI3
+
+arch/alpha/
+~~~~~~~~~~~
+
+o rth: Ptrace writes are broken.  This means we can't (reliably) set
+  breakpoints or modify variables from gdb.
+
+  PRI1
+
+arch/arm/
+~~~~~~~~~
+
+o rmk: missing raw keyboard translation tables for all ARM machines.
+  Haven't even looked into this at all.  This could be messy since there
+  isn't an ARM architecture standard.  I'm presently hoping that it won't be
+  an issue.  If it does, I guess we'll see drivers/char/keyboard.c explode.
+
+  PRI2
+
+arch/others/
+~~~~~~~~~~~~
+
+o SH needs resyncing, as do some other ports. SH64 needs merging.
+  No impact on mainstream platforms hopefully.
+
+  PRI2
+
+arch/s390/
+~~~~~~~~~
+
+o A nastly memory management problem causes random crashes.  These appear
+  to be fixed/hidden by the objrmap patch, more investigation is needed.
+
+  PRI1
+
+drivers/s390/
+~~~~~~~~~~~~~
+
+o Early userspace and 64 bit dev_t will allow the removal of most of
+  dasd_devmap.c and dasd_genhd.c.
+
+  PRI2
+
+o The 3270 console driver needs to be replaced with a working one
+  (prototype is there, needs to be finished).
+
+  PRI2
+
+o Minor interface changes are pending in cio/ when the z990 machines are
+  out.
+
+  PRI2
+
+o Jan Glauber is working on a fix for the timer issues related to running
+  on virtualized CPUs (wall-clock vs.  cpu time).
+
+  PRI1
+
+o a block device driver for ramdisks shared among virtual machines
+
+  PRI3
+
+o driver for crypto hardware
+
+  PRI3
+
+o 'claw' network device driver
+
+  PRI3
+
--- diff/Documentation/video4linux/bttv/Modprobe.conf	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/video4linux/bttv/Modprobe.conf	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,11 @@
+# i2c
+alias char-major-89	i2c-dev
+options i2c-core	i2c_debug=1
+options i2c-algo-bit	bit_test=1
+
+# bttv
+alias char-major-81	videodev
+alias char-major-81-0	bttv
+options	bttv		card=2 radio=1
+options	tuner		debug=1
+
--- diff/arch/arm/oprofile/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/arm/oprofile/Kconfig	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,23 @@
+
+menu "Profiling support"
+	depends on EXPERIMENTAL
+
+config PROFILING
+	bool "Profiling support (EXPERIMENTAL)"
+	help
+	  Say Y here to enable the extended profiling support mechanisms used
+	  by profilers such as OProfile.
+
+
+config OPROFILE
+	tristate "OProfile system profiling (EXPERIMENTAL)"
+	depends on PROFILING
+	help
+	  OProfile is a profiling system capable of profiling the
+	  whole system, include the kernel, kernel modules, libraries,
+	  and applications.
+
+	  If unsure, say N.
+
+endmenu
+
--- diff/arch/arm/oprofile/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/arm/oprofile/Makefile	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,9 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+		oprof.o cpu_buffer.o buffer_sync.o \
+		event_buffer.o oprofile_files.o \
+		oprofilefs.o oprofile_stats.o \
+		timer_int.o )
+
+oprofile-y				:= $(DRIVER_OBJS) init.o
--- diff/arch/arm/oprofile/init.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/arm/oprofile/init.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,22 @@
+/**
+ * @file init.c
+ *
+ * @remark Copyright 2004 Oprofile Authors
+ *
+ * @author Zwane Mwaikambo
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+int oprofile_arch_init(struct oprofile_operations **ops)
+{
+	int ret = -ENODEV;
+
+	return ret;
+}
+
+void oprofile_arch_exit(void)
+{
+}
--- diff/arch/i386/kernel/early_printk.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/early_printk.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,2 @@
+
+#include "../../x86_64/kernel/early_printk.c"
--- diff/arch/i386/kernel/entry_trampoline.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/entry_trampoline.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * linux/arch/i386/kernel/entry_trampoline.c
+ *
+ * (C) Copyright 2003 Ingo Molnar
+ *
+ * This file contains the needed support code for 4GB userspace
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/highmem.h>
+#include <asm/desc.h>
+#include <asm/atomic_kmap.h>
+
+extern char __entry_tramp_start, __entry_tramp_end, __start___entry_text;
+
+void __init init_entry_mappings(void)
+{
+#ifdef CONFIG_X86_HIGH_ENTRY
+	void *tramp;
+
+	/*
+	 * We need a high IDT and GDT for the 4G/4G split:
+	 */
+	trap_init_virtual_IDT();
+
+	__set_fixmap(FIX_ENTRY_TRAMPOLINE_0, __pa((unsigned long)&__entry_tramp_start), PAGE_KERNEL);
+	__set_fixmap(FIX_ENTRY_TRAMPOLINE_1, __pa((unsigned long)&__entry_tramp_start) + PAGE_SIZE, PAGE_KERNEL);
+	tramp = (void *)fix_to_virt(FIX_ENTRY_TRAMPOLINE_0);
+
+	printk("mapped 4G/4G trampoline to %p.\n", tramp);
+	BUG_ON((void *)&__start___entry_text != tramp);
+	/*
+	 * Virtual kernel stack:
+	 */
+	BUG_ON(__kmap_atomic_vaddr(KM_VSTACK0) & 8191);
+	BUG_ON(sizeof(struct desc_struct)*NR_CPUS*GDT_ENTRIES > 2*PAGE_SIZE);
+	BUG_ON((unsigned int)&__entry_tramp_end - (unsigned int)&__entry_tramp_start > 2*PAGE_SIZE);
+
+	/*
+	 * set up the initial thread's virtual stack related
+	 * fields:
+	 */
+	current->thread.stack_page0 = virt_to_page((char *)current->thread_info);
+	current->thread.stack_page1 = virt_to_page((char *)current->thread_info + PAGE_SIZE);
+	current->thread_info->virtual_stack = (void *)__kmap_atomic_vaddr(KM_VSTACK0);
+
+	__kunmap_atomic_type(KM_VSTACK0);
+	__kunmap_atomic_type(KM_VSTACK1);
+        __kmap_atomic(current->thread.stack_page0, KM_VSTACK0);
+        __kmap_atomic(current->thread.stack_page1, KM_VSTACK1);
+
+#endif
+	current->thread_info->real_stack = (void *)current->thread_info;
+	current->thread_info->user_pgd = NULL;
+	current->thread.esp0 = (unsigned long)current->thread_info->real_stack + THREAD_SIZE;
+}
+
+
+
+void __init entry_trampoline_setup(void)
+{
+	/*
+	 * old IRQ entries set up by the boot code will still hang
+	 * around - they are a sign of hw trouble anyway, now they'll
+	 * produce a double fault message.
+	 */
+	trap_init_virtual_GDT();
+}
--- diff/arch/i386/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/kgdb_stub.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,2457 @@
+/*
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 7 */
+	_PC /* 8 also known as eip */ ,
+	_PS /* 9 also known as eflags */ ,
+	_CS,			/* 10 */
+	_SS,			/* 11 */
+	_DS,			/* 12 */
+	_ES,			/* 13 */
+	_FS,			/* 14 */
+	_GS			/* 15 */
+};
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned int OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("EAX=%08lx ", regs->eax);
+	printk("EBX=%08lx ", regs->ebx);
+	printk("ECX=%08lx ", regs->ecx);
+	printk("EDX=%08lx ", regs->edx);
+	printk("\n");
+	printk("ESI=%08lx ", regs->esi);
+	printk("EDI=%08lx ", regs->edi);
+	printk("EBP=%08lx ", regs->ebp);
+	printk("ESP=%08lx ", (long) &regs->esp);
+	printk("\n");
+	printk(" DS=%08x ", regs->xds);
+	printk(" ES=%08x ", regs->xes);
+	printk(" SS=%08x ", __KERNEL_DS);
+	printk(" FL=%08lx ", regs->eflags);
+	printk("\n");
+	printk(" CS=%08x ", regs->xcs);
+	printk(" IP=%08lx ", regs->eip);
+#if 0
+	printk(" FS=%08x ", regs->fs);
+	printk(" GS=%08x ", regs->gs);
+#endif
+	printk("\n");
+
+}				/* print_regs */
+
+#define NEW_esp fn_call_lookaside[trap_cpu].esp
+
+static void
+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+	gdb_regs[_ESP] = NEW_esp;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+	NEW_esp = gdb_regs[_ESP];	/* keep the value */
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
+{
+	unsigned long stack_page;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_ESP] =
+			    (int) &kgdb_info.cpus_waiting[i].regs->esp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
+	gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
+	gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	stack_page = (unsigned long) p->thread_info;
+	if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > 8188 + stack_page)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (gdb_regs[_EBP] < stack_page ||
+		    gdb_regs[_EBP] > 8184 + stack_page)
+			return;
+		gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
+		gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
+		gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
+		if (gdb_regs[_PC] < first_sched || gdb_regs[_PC] >= last_sched)
+			return;
+	} while (count++ < 16);
+	return;
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int addr, length;
+	int breakno, breaktype;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	int gdb_regs[NUMREGBYTES / 4];
+	int dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+#define NUMREGS NUMREGBYTES/4
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time = 0, end_time, dum = 0;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movl %0,%%db7"
+	      :	/* no output */
+	      :"r"(0));
+
+	asm volatile ("movl %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (int) (&linux_regs->esp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? _GS : regno);
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						4, 0);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				hex2mem(ptr, (char *) addr, length, 1);
+
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%x\n", addr);
+
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movl %0, %%db6\n"::"r" (0));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		int *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (int);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->xcs;
+		*--ptr = linux_regs->eip;
+		*--ptr = linux_regs->ecx;
+		*--ptr = linux_regs->ebx;
+		*--ptr = linux_regs->eax;
+		linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
+		linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->eip = (unsigned int) fn_call_stub;
+		} else {
+			linux_regs->eip = (unsigned int) fn_rtn_stub;
+			linux_regs->eax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		return (0);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	return (0);
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/i386/kernel/timers/timer_pm.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/timers/timer_pm.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,217 @@
+/*
+ * (C) Dominik Brodowski <linux@brodo.de> 2003
+ *
+ * Driver to use the Power Management Timer (PMTMR) available in some
+ * southbridges as primary timing source for the Linux kernel.
+ *
+ * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
+ * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
+ *
+ * This file is licensed under the GPL v2.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/types.h>
+#include <asm/timer.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+#include <asm/arch_hooks.h>
+
+
+/* The I/O port the PMTMR resides at.
+ * The location is detected during setup_arch(),
+ * in arch/i386/acpi/boot.c */
+u32 pmtmr_ioport = 0;
+
+
+/* value of the Power timer at last timer interrupt */
+static u32 offset_tick;
+static u32 offset_delay;
+
+static unsigned long long monotonic_base;
+static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
+
+#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
+
+/*helper function to safely read acpi pm timesource*/
+static inline u32 read_pmtmr(void)
+{
+	u32 v1=0,v2=0,v3=0;
+	/* It has been reported that because of various broken
+	 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
+	 * source is not latched, so you must read it multiple
+	 * times to insure a safe value is read.
+	 */
+	do {
+		v1 = inl(pmtmr_ioport);
+		v2 = inl(pmtmr_ioport);
+		v3 = inl(pmtmr_ioport);
+	} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+			|| (v3 > v1 && v3 < v2));
+
+	/* mask the output to 24 bits */
+	return v2 & ACPI_PM_MASK;
+}
+
+static int init_pmtmr(char* override)
+{
+	u32 value1, value2;
+	unsigned int i;
+
+ 	if (override[0] && strncmp(override,"pmtmr",5))
+		return -ENODEV;
+
+	if (!pmtmr_ioport)
+		return -ENODEV;
+
+	/* we use the TSC for delay_pmtmr, so make sure it exists */
+	if (!cpu_has_tsc)
+		return -ENODEV;
+
+	/* "verify" this timing source */
+	value1 = read_pmtmr();
+	for (i = 0; i < 10000; i++) {
+		value2 = read_pmtmr();
+		if (value2 == value1)
+			continue;
+		if (value2 > value1)
+			goto pm_good;
+		if ((value2 < value1) && ((value2) < 0xFFF))
+			goto pm_good;
+		printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2);
+		return -EINVAL;
+	}
+	printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1);
+	return -ENODEV;
+
+pm_good:
+	init_cpu_khz();
+	return 0;
+}
+
+static inline u32 cyc2us(u32 cycles)
+{
+	/* The Power Management Timer ticks at 3.579545 ticks per microsecond.
+	 * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
+	 *
+	 * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
+	 * easily be multiplied with 286 (=0x11E) without having to fear
+	 * u32 overflows.
+	 */
+	cycles *= 286;
+	return (cycles >> 10);
+}
+
+/*
+ * this gets called during each timer interrupt
+ *   - Called while holding the writer xtime_lock
+ */
+static void mark_offset_pmtmr(void)
+{
+	u32 lost, delta, last_offset;
+	static int first_run = 1;
+	last_offset = offset_tick;
+
+	write_seqlock(&monotonic_lock);
+
+	offset_tick = read_pmtmr();
+
+	/* calculate tick interval */
+	delta = (offset_tick - last_offset) & ACPI_PM_MASK;
+
+	/* convert to usecs */
+	delta = cyc2us(delta);
+
+	/* update the monotonic base value */
+	monotonic_base += delta * NSEC_PER_USEC;
+	write_sequnlock(&monotonic_lock);
+
+	/* convert to ticks */
+	delta += offset_delay;
+	lost = delta / (USEC_PER_SEC / HZ);
+	offset_delay = delta % (USEC_PER_SEC / HZ);
+
+
+	/* compensate for lost ticks */
+	if (lost >= 2)
+		jiffies_64 += lost - 1;
+
+	/* don't calculate delay for first run,
+	   or if we've got less then a tick */
+	if (first_run || (lost < 1)) {
+		first_run = 0;
+		offset_delay = 0;
+	}
+}
+
+
+static unsigned long long monotonic_clock_pmtmr(void)
+{
+	u32 last_offset, this_offset;
+	unsigned long long base, ret;
+	unsigned seq;
+
+
+	/* atomically read monotonic base & last_offset */
+	do {
+		seq = read_seqbegin(&monotonic_lock);
+		last_offset = offset_tick;
+		base = monotonic_base;
+	} while (read_seqretry(&monotonic_lock, seq));
+
+	/* Read the pmtmr */
+	this_offset =  read_pmtmr();
+
+	/* convert to nanoseconds */
+	ret = (this_offset - last_offset) & ACPI_PM_MASK;
+	ret = base + (cyc2us(ret) * NSEC_PER_USEC);
+	return ret;
+}
+
+static void delay_pmtmr(unsigned long loops)
+{
+	unsigned long bclock, now;
+
+	rdtscl(bclock);
+	do
+	{
+		rep_nop();
+		rdtscl(now);
+	} while ((now-bclock) < loops);
+}
+
+
+/*
+ * get the offset (in microseconds) from the last call to mark_offset()
+ *	- Called holding a reader xtime_lock
+ */
+static unsigned long get_offset_pmtmr(void)
+{
+	u32 now, offset, delta = 0;
+
+	offset = offset_tick;
+	now = read_pmtmr();
+	delta = (now - offset)&ACPI_PM_MASK;
+
+	return (unsigned long) offset_delay + cyc2us(delta);
+}
+
+
+/* acpi timer_opts struct */
+struct timer_opts timer_pmtmr = {
+	.name			= "pmtmr",
+	.init 			= init_pmtmr,
+	.mark_offset		= mark_offset_pmtmr,
+	.get_offset		= get_offset_pmtmr,
+	.monotonic_clock 	= monotonic_clock_pmtmr,
+	.delay 			= delay_pmtmr,
+};
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86");
--- diff/arch/i386/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/lib/kgdb_serial.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,499 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+static inline int kgdb_mem_init_done(void)
+{
+	return highmem_start_page != NULL;
+}
+#else
+static inline int kgdb_mem_init_done(void)
+{
+	return max_mapnr != 0;
+}
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/arch/i386/pci/mmconfig.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/pci/mmconfig.c	2004-02-18 09:03:57.000000000 +0000
@@ -0,0 +1,109 @@
+/*
+ * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci.h"
+
+/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
+u32 pci_mmcfg_base_addr;
+
+#define mmcfg_virt_addr (fix_to_virt(FIX_PCIE_MCFG))
+
+/* The base address of the last MMCONFIG device accessed */
+static u32 mmcfg_last_accessed_device;
+
+/*
+ * Functions for accessing PCI configuration space with MMCONFIG accesses
+ */
+
+static inline void pci_exp_set_dev_base(int bus, int devfn)
+{
+	u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
+	if (dev_base != mmcfg_last_accessed_device) {
+		mmcfg_last_accessed_device = dev_base;
+		set_fixmap(FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	pci_exp_set_dev_base(bus, devfn);
+
+	switch (len) {
+	case 1:
+		*value = readb(mmcfg_virt_addr + reg);
+		break;
+	case 2:
+		*value = readw(mmcfg_virt_addr + reg);
+		break;
+	case 4:
+		*value = readl(mmcfg_virt_addr + reg);
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (devfn > 255) || (reg > 4095))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	pci_exp_set_dev_base(bus, devfn);
+
+	switch (len) {
+	case 1:
+		writeb(value, mmcfg_virt_addr + reg);
+		break;
+	case 2:
+		writew(value, mmcfg_virt_addr + reg);
+		break;
+	case 4:
+		writel(value, mmcfg_virt_addr + reg);
+		break;
+	}
+
+	/* Dummy read to flush PCI write */
+	readl(mmcfg_virt_addr);
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static struct pci_raw_ops pci_mmcfg = {
+	.read =		pci_mmcfg_read,
+	.write =	pci_mmcfg_write,
+};
+
+static int __init pci_mmcfg_init(void)
+{
+	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+		goto out;
+	if (!pci_mmcfg_base_addr)
+		goto out;
+
+	printk(KERN_INFO "PCI: Using MMCONFIG\n");
+	raw_pci_ops = &pci_mmcfg;
+	pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+
+ out:
+	return 0;
+}
+
+arch_initcall(pci_mmcfg_init);
--- diff/arch/x86_64/Kconfig.kgdb	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/Kconfig.kgdb	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,176 @@
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
--- diff/arch/x86_64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/kernel/kgdb_stub.c	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,2595 @@
+/*
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *  X86_64 changes from Andi Kleen's patch merged by Jim Houston
+ * 	(jim.houston@ccur.com).  If it works thank Andi if its broken
+ * 	blame me.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <asm/kdebug.h>
+#include <asm/uaccess.h>
+#include <linux/ptrace.h>
+
+#define Dearly_printk(x...)
+int kgdb_enabled = 0;
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES (NUMREGS * sizeof(unsigned long))
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ *
+ * Could add XMM and segment registers here.
+ */
+enum regnames {_RAX,
+	       _RBX,
+	       _RCX,
+	       _RDX,
+	       _RSI,
+	       _RDI,
+	       _RBP,
+	       _RSP,
+	       _R8,
+	       _R9,
+	       _R10,
+	       _R11,
+	       _R12,
+	       _R13,
+	       _R14,
+	       _R15,
+	       _PC,
+	       _PS,
+	       NUMREGS };
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned long rsp;
+	unsigned long array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned long OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movq %rax,%rsp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addq $-8,%rbx\n\t"
+	"movq (%rbx), %rax\n\t"
+	"pushq %rax\n\t"
+	"cmpq %rsp,%rcx\n\t"
+	"jne  1b\n\t"
+	"popq %rax\n\t"
+	"popq %rbx\n\t"
+	"popq %rcx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char lbuf[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("RAX=%016lx RBX=%016lx RCX=%016lx\n",
+		regs->rax, regs->rbx, regs->rcx);
+	printk("RDX=%016lx RSI=%016lx RDI=%016lx\n",
+		regs->rdx, regs->rsi, regs->rdi);
+	printk("RBP=%016lx PS=%016lx PC=%016lx\n",
+		regs->rbp, regs->eflags, regs->rip);
+ 	printk("R8=%016lx R9=%016lx R10=%016lx\n",
+		regs->r8, regs->r9, regs->r10);
+	printk("R11=%016lx R12=%016lx R13=%016lx\n",
+		regs->r11, regs->r12, regs->r13);
+	printk("R14=%016lx R15=%016lx RSP=%016lx\n",
+		regs->r14, regs->r15, regs->rsp);
+}
+
+#define NEW_esp fn_call_lookaside[trap_cpu].rsp
+
+static void
+regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_RAX] =  regs->rax;
+	gdb_regs[_RBX] =  regs->rbx;
+	gdb_regs[_RCX] =  regs->rcx;
+	gdb_regs[_RDX] =  regs->rdx;
+	gdb_regs[_RSI] =  regs->rsi;
+	gdb_regs[_RDI] =  regs->rdi;
+	gdb_regs[_RBP] =  regs->rbp;
+	gdb_regs[ _PS] =  regs->eflags;
+	gdb_regs[ _PC] =  regs->rip;
+	gdb_regs[ _R8] =  regs->r8;
+	gdb_regs[ _R9] =  regs->r9;
+	gdb_regs[_R10] = regs->r10;
+	gdb_regs[_R11] = regs->r11;
+	gdb_regs[_R12] = regs->r12;
+	gdb_regs[_R13] = regs->r13;
+	gdb_regs[_R14] = regs->r14;
+	gdb_regs[_R15] = regs->r15;
+	gdb_regs[_RSP] =  regs->rsp;
+
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+}
+
+static void
+gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->rax	=     gdb_regs[_RAX] ;
+	regs->rbx	=     gdb_regs[_RBX] ;
+	regs->rcx	=     gdb_regs[_RCX] ;
+	regs->rdx	=     gdb_regs[_RDX] ;
+	regs->rsi	=     gdb_regs[_RSI] ;
+	regs->rdi	=     gdb_regs[_RDI] ;
+	regs->rbp	=     gdb_regs[_RBP] ;
+	regs->eflags	=     gdb_regs[ _PS] ;
+	regs->rip	=     gdb_regs[ _PC] ;
+	regs->r8	=     gdb_regs[ _R8] ;
+	regs->r9	=     gdb_regs[ _R9] ;
+	regs->r10	=     gdb_regs[ _R10] ;
+	regs->r11	=     gdb_regs[ _R11] ;
+	regs->r12	=     gdb_regs[ _R12] ;
+	regs->r13	=     gdb_regs[ _R13] ;
+	regs->r14	=     gdb_regs[ _R14] ;
+	regs->r15	=     gdb_regs[ _R15] ;
+ #if 0					/* can't change these */
+	regs->rsp	=     gdb_regs[_RSP] ;
+	regs->ss	=     gdb_regs[ _SS] ;
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+}				/* gdb_regs_to_regs */
+
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched	((unsigned long) scheduling_functions_start_here)
+#define last_sched	((unsigned long) scheduling_functions_end_here)
+
+int thread_list = 0;
+extern void thread_return(void);
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, unsigned long *gdb_regs)
+{
+	unsigned long **rbp, *rsp, *rsp0, pc;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_RSP] =
+			    (unsigned long)&kgdb_info.cpus_waiting[i].regs->rsp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	rsp = (unsigned long *)p->thread.rsp;
+	rbp = (unsigned long **)rsp[0];
+	rsp += 2;
+	gdb_regs[_PC] =  (unsigned long)thread_return;
+	gdb_regs[_RBP] = (unsigned long)rbp;
+	gdb_regs[_RSP] = (unsigned long)rsp;
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	rsp0 = (unsigned long *)p->thread.rsp0;
+	if (rsp < (unsigned long *) p->thread_info || rsp > rsp0)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (*rbp < rsp || *rbp > rsp0)
+			break;
+		rbp = (unsigned long **)*rbp;
+		rsp = (unsigned long *)rbp;
+		pc = rsp[1];
+
+		if (pc < first_sched || pc >= last_sched)
+			break;
+		gdb_regs[_PC] = (unsigned long)pc;
+		gdb_regs[_RSP] = (unsigned long)rsp;
+		gdb_regs[_RBP] = (unsigned long)rbp;
+	} while (count++ < 16);
+	return;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* returns nonzero if any memory access fails. */
+int mem2hex( char* mem, char* buf, int   count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = 0;
+		ret |= __get_user(ch, mem);
+		mem++;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (ret) {
+		Dearly_printk("mem2hex: fault at accessing %p\n", mem);
+	}
+	return(ret);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return nonzero if any memory access fails. */
+int hex2mem( char* buf, char* mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		ret |= __put_user(ch, mem);
+		mem++;
+	}
+	if (ret) {
+		Dearly_printk("hex2mem: fault at %p\n", mem);
+	}
+	return(ret);
+}
+
+#if 0
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+#endif
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *value)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*value = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*value = (*value << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+		if (!cpu_online(pid - PID_MAX))
+			return NULL;
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned long hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned long dr7;
+
+	asm volatile ("movq %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned long addr0, addr1, addr2, addr3;
+		asm volatile ("movq %%db0, %0\n"
+			      "movq %%db1, %1\n"
+			      "movq %%db2, %2\n"
+			      "movq %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movq %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movq %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movq %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movq %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movq %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int cpu;
+	if (!kgdb_enabled)
+		return 0;
+	cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned long dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * The ThreadExtraInfo query allows us to pass an arbitrary string
+ * for display with the "info threads" command.
+ */
+
+void
+print_extra_info(task_t *p, char *buf)
+{
+	if (!p) {
+		sprintf(buf, "Invalid thread");
+		return;
+	}
+	sprintf(buf, "0x%p %8d %4d  %c  %s",
+		   (void *)p,  p->parent->pid,
+		   task_cpu(p),
+		   (p->state == 0) ? (task_curr(p)?'R':'r') :
+		     (p->state < 0) ? 'U' :
+		     (p->state & TASK_UNINTERRUPTIBLE) ? 'D' :
+		     (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' :
+		     (p->state & (TASK_ZOMBIE | TASK_DEAD)) ? 'Z' :
+		     (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?',
+		   p->comm);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	struct task_struct *p;
+	unsigned long addr, length;
+	unsigned long breakno, breaktype;
+	char *ptr;
+	unsigned long newPC;
+	threadref thref;
+	unsigned long threadid, tmpid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGS];
+	unsigned long dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->cs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time, end_time, dum;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movq %0,%%db7"
+	      :	/* no output */
+	      :"r"(0UL));
+
+	asm volatile ("movq %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+#if 0
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+#endif
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (unsigned long) (&linux_regs->rsp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).
+				 */
+				unsigned long regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToLong(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					if (regno >= NUMREGS)
+						break;
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						8);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToLong(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				if (mem2hex((char *) addr,
+					remcomOutBuffer, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToLong(&ptr, &length)) && (*(ptr++) == ':')) {
+				if (hex2mem(ptr, (char *) addr, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				regs.rip = addr;
+			}
+
+			newPC = regs.rip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				/* If start flag set start at 0. */
+				if (remcomInBuffer[2] == '1')
+					threadid = 0;
+				else
+					threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':
+				ptr = &remcomInBuffer[0];
+				if (strncmp(ptr, "qThreadExtraInfo,",
+					strlen("qThreadExtraInfo,")) == 0) {
+					ptr += strlen("qThreadExtraInfo,");
+					hexToLong(&ptr, &tmpid);
+					p = getthread(tmpid);
+					print_extra_info(p, lbuf);
+					mem2hex(lbuf, remcomOutBuffer,
+						strlen(lbuf));
+				}
+				break;
+#if 0
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+#endif
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			ptr++;
+			hexToLong(&ptr, &breaktype);
+			ptr++;
+			hexToLong(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		unsigned long *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (unsigned long);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->cs;
+		*--ptr = linux_regs->rip;
+		*--ptr = linux_regs->rcx;
+		*--ptr = linux_regs->rbx;
+		*--ptr = linux_regs->rax;
+		linux_regs->rcx = NEW_esp - (sizeof (unsigned long) * 6);
+		linux_regs->rbx = (unsigned long) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->rip = (unsigned long) fn_call_stub;
+		} else {
+			linux_regs->rip = (unsigned long) fn_rtn_stub;
+			linux_regs->rax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		local_irq_restore(flags);
+		return (1);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	local_irq_restore(flags);
+	return (1);
+}
+
+#undef regs
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	struct die_args *d = ptr;
+
+	if (!kgdb_enabled || (cmd == DIE_DEBUG && user_mode(d->regs)))
+		return NOTIFY_DONE;
+	if (cmd == DIE_NMI_IPI) {
+		if (in_kgdb(d->regs))
+			return NOTIFY_BAD;
+	} else if (kgdb_handle_exception(d->trapnr, d->signr, d->err, d->regs))
+		return NOTIFY_BAD; /* skip */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0,
+};
+
+void set_debug_traps(void)
+{
+	static int initialized = 0;
+
+	if (!initialized) {
+		initialized = 1;
+		notifier_chain_register(&die_chain, &kgdb_notifier);
+	}
+}
+
+/*
+ * Provide the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+void breakpoint(void)
+{
+
+	set_debug_traps();
+	kgdb_enabled = 1;
+#if 0
+	/*
+	 * These calls were not enough to allow breakpoint to be
+	 * called before trap_init().  I moved the argument parsing
+	 * after trap_init() and it seems to work.
+	 */
+	set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+#endif
+
+        BREAKPOINT;
+}
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		kgdb_enabled = 1;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/x86_64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/lib/kgdb_serial.c	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,490 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	set_debug_traps();
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#define kgdb_mem_init_done()    (1)
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/drivers/block/cfq-iosched.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/block/cfq-iosched.c	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,707 @@
+/*
+ *  linux/drivers/block/cfq-iosched.c
+ *
+ *  CFQ, or complete fairness queueing, disk scheduler.
+ *
+ *  Based on ideas from a previously unfinished io
+ *  scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
+ *
+ *  Copyright (C) 2003 Jens Axboe <axboe@suse.de>
+ */
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/hash.h>
+#include <linux/rbtree.h>
+#include <linux/mempool.h>
+
+/*
+ * tunables
+ */
+static int cfq_quantum = 4;
+static int cfq_queued = 8;
+
+#define CFQ_QHASH_SHIFT		6
+#define CFQ_QHASH_ENTRIES	(1 << CFQ_QHASH_SHIFT)
+#define list_entry_qhash(entry)	list_entry((entry), struct cfq_queue, cfq_hash)
+
+#define CFQ_MHASH_SHIFT		8
+#define CFQ_MHASH_BLOCK(sec)	((sec) >> 3)
+#define CFQ_MHASH_ENTRIES	(1 << CFQ_MHASH_SHIFT)
+#define CFQ_MHASH_FN(sec)	(hash_long(CFQ_MHASH_BLOCK((sec)),CFQ_MHASH_SHIFT))
+#define ON_MHASH(crq)		!list_empty(&(crq)->hash)
+#define rq_hash_key(rq)		((rq)->sector + (rq)->nr_sectors)
+#define list_entry_hash(ptr)	list_entry((ptr), struct cfq_rq, hash)
+
+#define list_entry_cfqq(ptr)	list_entry((ptr), struct cfq_queue, cfq_list)
+
+#define RQ_DATA(rq)		((struct cfq_rq *) (rq)->elevator_private)
+
+static kmem_cache_t *crq_pool;
+static kmem_cache_t *cfq_pool;
+static mempool_t *cfq_mpool;
+
+struct cfq_data {
+	struct list_head rr_list;
+	struct list_head *dispatch;
+	struct list_head *cfq_hash;
+
+	struct list_head *crq_hash;
+
+	unsigned int busy_queues;
+	unsigned int max_queued;
+
+	mempool_t *crq_pool;
+};
+
+struct cfq_queue {
+	struct list_head cfq_hash;
+	struct list_head cfq_list;
+	struct rb_root sort_list;
+	int pid;
+	int queued[2];
+#if 0
+	/*
+	 * with a simple addition like this, we can do io priorities. almost.
+	 * does need a split request free list, too.
+	 */
+	int io_prio
+#endif
+};
+
+struct cfq_rq {
+	struct rb_node rb_node;
+	sector_t rb_key;
+
+	struct request *request;
+
+	struct cfq_queue *cfq_queue;
+
+	struct list_head hash;
+};
+
+static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq);
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid);
+static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq);
+
+/*
+ * lots of deadline iosched dupes, can be abstracted later...
+ */
+static inline void __cfq_del_crq_hash(struct cfq_rq *crq)
+{
+	list_del_init(&crq->hash);
+}
+
+static inline void cfq_del_crq_hash(struct cfq_rq *crq)
+{
+	if (ON_MHASH(crq))
+		__cfq_del_crq_hash(crq);
+}
+
+static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
+{
+	cfq_del_crq_hash(crq);
+
+	if (q->last_merge == crq->request)
+		q->last_merge = NULL;
+}
+
+static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
+{
+	struct request *rq = crq->request;
+
+	BUG_ON(ON_MHASH(crq));
+
+	list_add(&crq->hash, &cfqd->crq_hash[CFQ_MHASH_FN(rq_hash_key(rq))]);
+}
+
+static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
+{
+	struct list_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)];
+	struct list_head *entry, *next = hash_list->next;
+
+	while ((entry = next) != hash_list) {
+		struct cfq_rq *crq = list_entry_hash(entry);
+		struct request *__rq = crq->request;
+
+		next = entry->next;
+
+		BUG_ON(!ON_MHASH(crq));
+
+		if (!rq_mergeable(__rq)) {
+			__cfq_del_crq_hash(crq);
+			continue;
+		}
+
+		if (rq_hash_key(__rq) == offset)
+			return __rq;
+	}
+
+	return NULL;
+}
+
+/*
+ * rb tree support functions
+ */
+#define RB_NONE		(2)
+#define RB_EMPTY(node)	((node)->rb_node == NULL)
+#define RB_CLEAR(node)	((node)->rb_color = RB_NONE)
+#define RB_CLEAR_ROOT(root)	((root)->rb_node = NULL)
+#define ON_RB(node)	((node)->rb_color != RB_NONE)
+#define rb_entry_crq(node)	rb_entry((node), struct cfq_rq, rb_node)
+#define rq_rb_key(rq)		(rq)->sector
+
+static inline void cfq_del_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
+{
+	if (ON_RB(&crq->rb_node)) {
+		cfqq->queued[rq_data_dir(crq->request)]--;
+		rb_erase(&crq->rb_node, &cfqq->sort_list);
+		crq->cfq_queue = NULL;
+	}
+}
+
+static struct cfq_rq *
+__cfq_add_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
+{
+	struct rb_node **p = &cfqq->sort_list.rb_node;
+	struct rb_node *parent = NULL;
+	struct cfq_rq *__crq;
+
+	while (*p) {
+		parent = *p;
+		__crq = rb_entry_crq(parent);
+
+		if (crq->rb_key < __crq->rb_key)
+			p = &(*p)->rb_left;
+		else if (crq->rb_key > __crq->rb_key)
+			p = &(*p)->rb_right;
+		else
+			return __crq;
+	}
+
+	rb_link_node(&crq->rb_node, parent, p);
+	return 0;
+}
+
+static void
+cfq_add_crq_rb(struct cfq_data *cfqd, struct cfq_queue *cfqq,struct cfq_rq *crq)
+{
+	struct request *rq = crq->request;
+	struct cfq_rq *__alias;
+
+	crq->rb_key = rq_rb_key(rq);
+	cfqq->queued[rq_data_dir(rq)]++;
+retry:
+	__alias = __cfq_add_crq_rb(cfqq, crq);
+	if (!__alias) {
+		rb_insert_color(&crq->rb_node, &cfqq->sort_list);
+		crq->cfq_queue = cfqq;
+		return;
+	}
+
+	cfq_del_crq_rb(cfqq, __alias);
+	cfq_dispatch_sort(cfqd->dispatch, __alias);
+	goto retry;
+}
+
+static struct request *
+cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+{
+	struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
+	struct rb_node *n;
+
+	if (!cfqq)
+		goto out;
+
+	n = cfqq->sort_list.rb_node;
+	while (n) {
+		struct cfq_rq *crq = rb_entry_crq(n);
+
+		if (sector < crq->rb_key)
+			n = n->rb_left;
+		else if (sector > crq->rb_key)
+			n = n->rb_right;
+		else
+			return crq->request;
+	}
+
+out:
+	return NULL;
+}
+
+static void cfq_remove_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	if (crq) {
+		struct cfq_queue *cfqq = crq->cfq_queue;
+
+		cfq_remove_merge_hints(q, crq);
+		list_del_init(&rq->queuelist);
+
+		if (cfqq) {
+			cfq_del_crq_rb(cfqq, crq);
+
+			if (RB_EMPTY(&cfqq->sort_list))
+				cfq_put_queue(cfqd, cfqq);
+		}
+	}
+}
+
+static int
+cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct request *__rq;
+	int ret;
+
+	ret = elv_try_last_merge(q, bio);
+	if (ret != ELEVATOR_NO_MERGE) {
+		__rq = q->last_merge;
+		goto out_insert;
+	}
+
+	__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
+	if (__rq) {
+		BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
+
+		if (elv_rq_merge_ok(__rq, bio)) {
+			ret = ELEVATOR_BACK_MERGE;
+			goto out;
+		}
+	}
+
+	__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
+	if (__rq) {
+		if (elv_rq_merge_ok(__rq, bio)) {
+			ret = ELEVATOR_FRONT_MERGE;
+			goto out;
+		}
+	}
+
+	return ELEVATOR_NO_MERGE;
+out:
+	q->last_merge = __rq;
+out_insert:
+	*req = __rq;
+	return ret;
+}
+
+static void cfq_merged_request(request_queue_t *q, struct request *req)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(req);
+
+	cfq_del_crq_hash(crq);
+	cfq_add_crq_hash(cfqd, crq);
+
+	if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) {
+		struct cfq_queue *cfqq = crq->cfq_queue;
+
+		cfq_del_crq_rb(cfqq, crq);
+		cfq_add_crq_rb(cfqd, cfqq, crq);
+	}
+
+	q->last_merge = req;
+}
+
+static void
+cfq_merged_requests(request_queue_t *q, struct request *req,
+		    struct request *next)
+{
+	cfq_merged_request(q, req);
+	cfq_remove_request(q, next);
+}
+
+static void cfq_dispatch_sort(struct list_head *head, struct cfq_rq *crq)
+{
+	struct list_head *entry = head;
+	struct request *__rq;
+
+	if (!list_empty(head)) {
+		__rq = list_entry_rq(head->next);
+
+		if (crq->request->sector < __rq->sector) {
+			entry = head->prev;
+			goto link;
+		}
+	}
+
+	while ((entry = entry->prev) != head) {
+		__rq = list_entry_rq(entry);
+
+		if (crq->request->sector <= __rq->sector)
+			break;
+	}
+
+link:
+	list_add_tail(&crq->request->queuelist, entry);
+}
+
+static inline void
+__cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd,
+			struct cfq_queue *cfqq)
+{
+	struct cfq_rq *crq = rb_entry_crq(rb_first(&cfqq->sort_list));
+
+	cfq_del_crq_rb(cfqq, crq);
+	cfq_remove_merge_hints(q, crq);
+	cfq_dispatch_sort(cfqd->dispatch, crq);
+}
+
+static int cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd)
+{
+	struct cfq_queue *cfqq;
+	struct list_head *entry, *tmp;
+	int ret, queued, good_queues;
+
+	if (list_empty(&cfqd->rr_list))
+		return 0;
+
+	queued = ret = 0;
+restart:
+	good_queues = 0;
+	list_for_each_safe(entry, tmp, &cfqd->rr_list) {
+		cfqq = list_entry_cfqq(cfqd->rr_list.next);
+
+		BUG_ON(RB_EMPTY(&cfqq->sort_list));
+
+		__cfq_dispatch_requests(q, cfqd, cfqq);
+
+		if (RB_EMPTY(&cfqq->sort_list))
+			cfq_put_queue(cfqd, cfqq);
+		else
+			good_queues++;
+
+		queued++;
+		ret = 1;
+	}
+
+	if ((queued < cfq_quantum) && good_queues)
+		goto restart;
+
+	return ret;
+}
+
+static struct request *cfq_next_request(request_queue_t *q)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct request *rq;
+
+	if (!list_empty(cfqd->dispatch)) {
+		struct cfq_rq *crq;
+dispatch:
+		rq = list_entry_rq(cfqd->dispatch->next);
+
+		BUG_ON(q->last_merge == rq);
+		crq = RQ_DATA(rq);
+		if (crq)
+			BUG_ON(ON_MHASH(crq));
+
+		return rq;
+	}
+
+	if (cfq_dispatch_requests(q, cfqd))
+		goto dispatch;
+
+	return NULL;
+}
+
+static inline struct cfq_queue *
+__cfq_find_cfq_hash(struct cfq_data *cfqd, int pid, const int hashval)
+{
+	struct list_head *hash_list = &cfqd->cfq_hash[hashval];
+	struct list_head *entry;
+
+	list_for_each(entry, hash_list) {
+		struct cfq_queue *__cfqq = list_entry_qhash(entry);
+
+		if (__cfqq->pid == pid)
+			return __cfqq;
+	}
+
+	return NULL;
+}
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid)
+{
+	const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
+
+	return __cfq_find_cfq_hash(cfqd, pid, hashval);
+}
+
+static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	cfqd->busy_queues--;
+	list_del(&cfqq->cfq_list);
+	list_del(&cfqq->cfq_hash);
+	mempool_free(cfqq, cfq_mpool);
+}
+
+static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, int pid)
+{
+	const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
+	struct cfq_queue *cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval);
+
+	if (!cfqq) {
+		cfqq = mempool_alloc(cfq_mpool, GFP_NOIO);
+
+		INIT_LIST_HEAD(&cfqq->cfq_hash);
+		INIT_LIST_HEAD(&cfqq->cfq_list);
+		RB_CLEAR_ROOT(&cfqq->sort_list);
+
+		cfqq->pid = pid;
+		cfqq->queued[0] = cfqq->queued[1] = 0;
+		list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+	}
+
+	return cfqq;
+}
+
+static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+{
+	struct cfq_queue *cfqq;
+
+	cfqq = cfq_get_queue(cfqd, current->tgid);
+
+	cfq_add_crq_rb(cfqd, cfqq, crq);
+
+	if (list_empty(&cfqq->cfq_list)) {
+		list_add(&cfqq->cfq_list, &cfqd->rr_list);
+		cfqd->busy_queues++;
+	}
+}
+
+static void
+cfq_insert_request(request_queue_t *q, struct request *rq, int where)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	switch (where) {
+		case ELEVATOR_INSERT_BACK:
+			while (cfq_dispatch_requests(q, cfqd))
+				;
+			list_add_tail(&rq->queuelist, cfqd->dispatch);
+			break;
+		case ELEVATOR_INSERT_FRONT:
+			list_add(&rq->queuelist, cfqd->dispatch);
+			break;
+		case ELEVATOR_INSERT_SORT:
+			BUG_ON(!blk_fs_request(rq));
+			cfq_enqueue(cfqd, crq);
+			break;
+		default:
+			printk("%s: bad insert point %d\n", __FUNCTION__,where);
+			return;
+	}
+
+	if (rq_mergeable(rq)) {
+		cfq_add_crq_hash(cfqd, crq);
+
+		if (!q->last_merge)
+			q->last_merge = rq;
+	}
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+
+	if (list_empty(cfqd->dispatch) && list_empty(&cfqd->rr_list))
+		return 1;
+
+	return 0;
+}
+
+static struct request *
+cfq_former_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_rq *crq = RQ_DATA(rq);
+	struct rb_node *rbprev = rb_prev(&crq->rb_node);
+
+	if (rbprev)
+		return rb_entry_crq(rbprev)->request;
+
+	return NULL;
+}
+
+static struct request *
+cfq_latter_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_rq *crq = RQ_DATA(rq);
+	struct rb_node *rbnext = rb_next(&crq->rb_node);
+
+	if (rbnext)
+		return rb_entry_crq(rbnext)->request;
+
+	return NULL;
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_queue *cfqq;
+	int ret = 1;
+
+	if (!cfqd->busy_queues)
+		goto out;
+
+	cfqq = cfq_find_cfq_hash(cfqd, current->tgid);
+	if (cfqq) {
+		int limit = (q->nr_requests - cfq_queued) / cfqd->busy_queues;
+
+		if (limit < 3)
+			limit = 3;
+		else if (limit > cfqd->max_queued)
+			limit = cfqd->max_queued;
+
+		if (cfqq->queued[rw] > limit)
+			ret = 0;
+	}
+out:
+	return ret;
+}
+
+static void cfq_put_request(request_queue_t *q, struct request *rq)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = RQ_DATA(rq);
+
+	if (crq) {
+		BUG_ON(q->last_merge == rq);
+		BUG_ON(ON_MHASH(crq));
+
+		mempool_free(crq, cfqd->crq_pool);
+		rq->elevator_private = NULL;
+	}
+}
+
+static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+{
+	struct cfq_data *cfqd = q->elevator.elevator_data;
+	struct cfq_rq *crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
+
+	if (crq) {
+		RB_CLEAR(&crq->rb_node);
+		crq->request = rq;
+		crq->cfq_queue = NULL;
+		INIT_LIST_HEAD(&crq->hash);
+		rq->elevator_private = crq;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void cfq_exit(request_queue_t *q, elevator_t *e)
+{
+	struct cfq_data *cfqd = e->elevator_data;
+
+	e->elevator_data = NULL;
+	mempool_destroy(cfqd->crq_pool);
+	kfree(cfqd->crq_hash);
+	kfree(cfqd->cfq_hash);
+	kfree(cfqd);
+}
+
+static int cfq_init(request_queue_t *q, elevator_t *e)
+{
+	struct cfq_data *cfqd;
+	int i;
+
+	cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
+	if (!cfqd)
+		return -ENOMEM;
+
+	memset(cfqd, 0, sizeof(*cfqd));
+	INIT_LIST_HEAD(&cfqd->rr_list);
+
+	cfqd->crq_hash = kmalloc(sizeof(struct list_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
+	if (!cfqd->crq_hash)
+		goto out_crqhash;
+
+	cfqd->cfq_hash = kmalloc(sizeof(struct list_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL);
+	if (!cfqd->cfq_hash)
+		goto out_cfqhash;
+
+	cfqd->crq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, crq_pool);
+	if (!cfqd->crq_pool)
+		goto out_crqpool;
+
+	for (i = 0; i < CFQ_MHASH_ENTRIES; i++)
+		INIT_LIST_HEAD(&cfqd->crq_hash[i]);
+	for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
+		INIT_LIST_HEAD(&cfqd->cfq_hash[i]);
+
+	cfqd->dispatch = &q->queue_head;
+	e->elevator_data = cfqd;
+
+	/*
+	 * just set it to some high value, we want anyone to be able to queue
+	 * some requests. fairness is handled differently
+	 */
+	cfqd->max_queued = q->nr_requests;
+	q->nr_requests = 8192;
+
+	return 0;
+out_crqpool:
+	kfree(cfqd->cfq_hash);
+out_cfqhash:
+	kfree(cfqd->crq_hash);
+out_crqhash:
+	kfree(cfqd);
+	return -ENOMEM;
+}
+
+static int __init cfq_slab_setup(void)
+{
+	crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0,
+					NULL, NULL);
+
+	if (!crq_pool)
+		panic("cfq_iosched: can't init crq pool\n");
+
+	cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
+					NULL, NULL);
+
+	if (!cfq_pool)
+		panic("cfq_iosched: can't init cfq pool\n");
+
+	cfq_mpool = mempool_create(64, mempool_alloc_slab, mempool_free_slab, cfq_pool);
+
+	if (!cfq_mpool)
+		panic("cfq_iosched: can't init cfq mpool\n");
+
+	return 0;
+}
+
+subsys_initcall(cfq_slab_setup);
+
+elevator_t iosched_cfq = {
+	.elevator_name =		"cfq",
+	.elevator_merge_fn = 		cfq_merge,
+	.elevator_merged_fn =		cfq_merged_request,
+	.elevator_merge_req_fn =	cfq_merged_requests,
+	.elevator_next_req_fn =		cfq_next_request,
+	.elevator_add_req_fn =		cfq_insert_request,
+	.elevator_remove_req_fn =	cfq_remove_request,
+	.elevator_queue_empty_fn =	cfq_queue_empty,
+	.elevator_former_req_fn =	cfq_former_request,
+	.elevator_latter_req_fn =	cfq_latter_request,
+	.elevator_set_req_fn =		cfq_set_request,
+	.elevator_put_req_fn =		cfq_put_request,
+	.elevator_may_queue_fn =	cfq_may_queue,
+	.elevator_init_fn =		cfq_init,
+	.elevator_exit_fn =		cfq_exit,
+};
+
+EXPORT_SYMBOL(iosched_cfq);
--- diff/drivers/char/drm/drm_irq.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/drm/drm_irq.h	2004-02-18 09:03:58.000000000 +0000
@@ -0,0 +1,377 @@
+/**
+ * \file drm_irq.h 
+ * IRQ support
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Gareth Hughes <gareth@valinux.com>
+ */
+
+/*
+ * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "drmP.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+#ifndef __HAVE_SHARED_IRQ
+#define __HAVE_SHARED_IRQ	0
+#endif
+
+#if __HAVE_SHARED_IRQ
+#define DRM_IRQ_TYPE		SA_SHIRQ
+#else
+#define DRM_IRQ_TYPE		0
+#endif
+
+/**
+ * Get interrupt from bus id.
+ * 
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_irq_busid structure.
+ * \return zero on success or a negative number on failure.
+ * 
+ * Finds the PCI device with the specified bus id and gets its IRQ number.
+ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
+ * to that of the device that this DRM instance attached to.
+ */
+int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_irq_busid_t p;
+
+	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+		return -EFAULT;
+
+	if ((p.busnum >> 8) != dev->pci_domain ||
+	    (p.busnum & 0xff) != dev->pci_bus ||
+	    p.devnum != dev->pci_slot ||
+	    p.funcnum != dev->pci_func)
+		return -EINVAL;
+
+	p.irq = dev->irq;
+
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+		  p.busnum, p.devnum, p.funcnum, p.irq);
+	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+		return -EFAULT;
+	return 0;
+}
+
+#if __HAVE_IRQ
+
+/**
+ * Install IRQ handler.
+ *
+ * \param dev DRM device.
+ * \param irq IRQ number.
+ *
+ * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
+ * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
+ * before and after the installation.
+ */
+int DRM(irq_install)( drm_device_t *dev )
+{
+	int ret;
+ 
+	if ( dev->irq == 0 )
+		return -EINVAL;
+
+	down( &dev->struct_sem );
+
+	/* Driver must have been initialized */
+	if ( !dev->dev_private ) {
+		up( &dev->struct_sem );
+		return -EINVAL;
+	}
+
+	if ( dev->irq_enabled ) {
+		up( &dev->struct_sem );
+		return -EBUSY;
+	}
+	dev->irq_enabled = 1;
+	up( &dev->struct_sem );
+
+	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+#if 0 /* this is already done in DRM(setup) - why do it here ?? */
+	dev->context_flag = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag = 0;
+#endif
+
+#if __HAVE_DMA
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue = NULL;
+	dev->dma->this_buffer = NULL;
+#endif
+
+#if __HAVE_IRQ_BH
+	INIT_WORK(&dev->work, DRM(irq_immediate_bh), dev);
+#endif
+
+#if __HAVE_VBL_IRQ
+	init_waitqueue_head(&dev->vbl_queue);
+
+	spin_lock_init( &dev->vbl_lock );
+
+	INIT_LIST_HEAD( &dev->vbl_sigs.head );
+
+	dev->vbl_pending = 0;
+#endif
+
+				/* Before installing handler */
+	DRM(driver_irq_preinstall)(dev);
+
+				/* Install handler */
+	ret = request_irq( dev->irq, DRM(irq_handler),
+			   DRM_IRQ_TYPE, dev->devname, dev );
+	if ( ret < 0 ) {
+		down( &dev->struct_sem );
+		dev->irq_enabled = 0;
+		up( &dev->struct_sem );
+		return ret;
+	}
+
+				/* After installing handler */
+	DRM(driver_irq_postinstall)(dev);
+
+	return 0;
+}
+
+/**
+ * Uninstall the IRQ handler.
+ *
+ * \param dev DRM device.
+ *
+ * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq.
+ */
+int DRM(irq_uninstall)( drm_device_t *dev )
+{
+	int irq_enabled;
+
+	down( &dev->struct_sem );
+	irq_enabled = dev->irq_enabled;
+	dev->irq_enabled = 0;
+	up( &dev->struct_sem );
+
+	if ( !irq_enabled )
+		return -EINVAL;
+
+	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
+
+	DRM(driver_irq_uninstall)( dev );
+
+	free_irq( dev->irq, dev );
+
+	return 0;
+}
+
+/**
+ * IRQ control ioctl.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_control structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Calls irq_install() or irq_uninstall() according to \p arg.
+ */
+int DRM(control)( struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg )
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_control_t ctl;
+
+	if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
+		return -EFAULT;
+
+	switch ( ctl.func ) {
+	case DRM_INST_HANDLER:
+		if (dev->if_version < DRM_IF_VERSION(1, 2) &&
+		    ctl.irq != dev->irq)
+			return -EINVAL;
+		return DRM(irq_install)( dev );
+	case DRM_UNINST_HANDLER:
+		return DRM(irq_uninstall)( dev );
+	default:
+		return -EINVAL;
+	}
+}
+
+#if __HAVE_VBL_IRQ
+
+/**
+ * Wait for VBLANK.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param data user argument, pointing to a drm_wait_vblank structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Verifies the IRQ is installed. 
+ *
+ * If a signal is requested checks if this task has already scheduled the same signal
+ * for the same vblank sequence number - nothing to be done in
+ * that case. If the number of tasks waiting for the interrupt exceeds 100 the
+ * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
+ * task.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+int DRM(wait_vblank)( DRM_IOCTL_ARGS )
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_wait_vblank_t vblwait;
+	struct timeval now;
+	int ret = 0;
+	unsigned int flags;
+
+	if (!dev->irq)
+		return -EINVAL;
+
+	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
+				  sizeof(vblwait) );
+
+	switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
+	case _DRM_VBLANK_RELATIVE:
+		vblwait.request.sequence += atomic_read( &dev->vbl_received );
+		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+	case _DRM_VBLANK_ABSOLUTE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+	
+	if ( flags & _DRM_VBLANK_SIGNAL ) {
+		unsigned long irqflags;
+		drm_vbl_sig_t *vbl_sig;
+		
+		vblwait.reply.sequence = atomic_read( &dev->vbl_received );
+
+		spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+		/* Check if this task has already scheduled the same signal
+		 * for the same vblank sequence number; nothing to be done in
+		 * that case
+		 */
+		list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
+			if (vbl_sig->sequence == vblwait.request.sequence
+			    && vbl_sig->info.si_signo == vblwait.request.signal
+			    && vbl_sig->task == current)
+			{
+				spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+				goto done;
+			}
+		}
+
+		if ( dev->vbl_pending >= 100 ) {
+			spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+			return -EBUSY;
+		}
+
+		dev->vbl_pending++;
+
+		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+
+		if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) {
+			return -ENOMEM;
+		}
+
+		memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
+
+		vbl_sig->sequence = vblwait.request.sequence;
+		vbl_sig->info.si_signo = vblwait.request.signal;
+		vbl_sig->task = current;
+
+		spin_lock_irqsave( &dev->vbl_lock, irqflags );
+
+		list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
+
+		spin_unlock_irqrestore( &dev->vbl_lock, irqflags );
+	} else {
+		ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
+
+		do_gettimeofday( &now );
+		vblwait.reply.tval_sec = now.tv_sec;
+		vblwait.reply.tval_usec = now.tv_usec;
+	}
+
+done:
+	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
+				sizeof(vblwait) );
+
+	return ret;
+}
+
+/**
+ * Send the VBLANK signals.
+ *
+ * \param dev DRM device.
+ *
+ * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
+ *
+ * If a signal is not requested, then calls vblank_wait().
+ */
+void DRM(vbl_send_signals)( drm_device_t *dev )
+{
+	struct list_head *list, *tmp;
+	drm_vbl_sig_t *vbl_sig;
+	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
+	unsigned long flags;
+
+	spin_lock_irqsave( &dev->vbl_lock, flags );
+
+	list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
+		vbl_sig = list_entry( list, drm_vbl_sig_t, head );
+		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
+			vbl_sig->info.si_code = vbl_seq;
+			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
+
+			list_del( list );
+
+			DRM_FREE( vbl_sig, sizeof(*vbl_sig) );
+
+			dev->vbl_pending--;
+		}
+	}
+
+	spin_unlock_irqrestore( &dev->vbl_lock, flags );
+}
+
+#endif	/* __HAVE_VBL_IRQ */
+
+#endif /* __HAVE_IRQ */
--- diff/drivers/i2c/busses/i2c-ixp42x.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/i2c/busses/i2c-ixp42x.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,180 @@
+/*
+ * drivers/i2c/i2c-adap-ixp42x.c
+ *
+ * Intel's IXP42x XScale NPU chipsets (IXP420, 421, 422, 425) do not have
+ * an on board I2C controller but provide 16 GPIO pins that are often
+ * used to create an I2C bus. This driver provides an i2c_adapter 
+ * interface that plugs in under algo_bit and drives the GPIO pins
+ * as instructed by the alogorithm driver.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (c) 2003-2004 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ *
+ * NOTE: Since different platforms will use different GPIO pins for
+ *       I2C, this driver uses an IXP42x-specific platform_data
+ *       pointer to pass the GPIO numbers to the driver. This 
+ *       allows us to support all the different IXP42x platforms
+ *       w/o having to put #ifdefs in this driver.
+ *
+ *       See arch/arm/mach-ixp42x/ixdp425.c for an example of building a 
+ *       device list and filling in the ixp42x_i2c_pins data structure 
+ *       that is passed as the platform_data to this driver.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define DEBUG	1
+#endif
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>	/* Pick up IXP42x-specific bits */
+
+static inline int ixp42x_scl_pin(void *data)
+{
+	return ((struct ixp42x_i2c_pins*)data)->scl_pin;
+}
+
+static inline int ixp42x_sda_pin(void *data)
+{
+	return ((struct ixp42x_i2c_pins*)data)->sda_pin;
+}
+
+static void ixp42x_bit_setscl(void *data, int val)
+{
+	gpio_line_set(ixp42x_scl_pin(data), 0);
+	gpio_line_config(ixp42x_scl_pin(data),
+		val ? IXP425_GPIO_IN : IXP425_GPIO_OUT );
+}
+
+static void ixp42x_bit_setsda(void *data, int val)
+{
+	gpio_line_set(ixp42x_sda_pin(data), 0);
+	gpio_line_config(ixp42x_sda_pin(data),
+		val ? IXP425_GPIO_IN : IXP425_GPIO_OUT );
+}
+
+static int ixp42x_bit_getscl(void *data)
+{
+	int scl;
+
+	gpio_line_config(ixp42x_scl_pin(data), IXP425_GPIO_IN );
+	gpio_line_get(ixp42x_scl_pin(data), &scl);
+
+	return scl;
+}	
+
+static int ixp42x_bit_getsda(void *data)
+{
+	int sda;
+
+	gpio_line_config(ixp42x_sda_pin(data), IXP425_GPIO_IN );
+	gpio_line_get(ixp42x_sda_pin(data), &sda);
+
+	return sda;
+}	
+
+struct ixp42x_i2c_data {
+	struct ixp42x_i2c_pins *gpio_pins;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo_data;
+};
+
+static int ixp42x_i2c_remove(struct device *dev)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct ixp42x_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev);
+
+	dev_set_drvdata(&plat_dev->dev, NULL);
+
+	i2c_bit_del_bus(&drv_data->adapter);
+
+	kfree(drv_data);
+
+	return 0;
+}
+
+static int ixp42x_i2c_probe(struct device *dev)
+{
+	int err;
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct ixp42x_i2c_pins *gpio = plat_dev->dev.platform_data;
+	struct ixp42x_i2c_data *drv_data = 
+		kmalloc(sizeof(struct ixp42x_i2c_data), GFP_KERNEL);
+
+	if(!drv_data)
+		return -ENOMEM;
+
+	memzero(drv_data, sizeof(struct ixp42x_i2c_data));
+	drv_data->gpio_pins = gpio;
+
+	/*
+	 * We could make a lot of these structures static, but
+	 * certain platforms may have multiple GPIO-based I2C
+	 * buses for various device domains, so we need per-device
+	 * algo_data->data. 
+	 */
+	drv_data->algo_data.data = gpio;
+	drv_data->algo_data.setsda = ixp42x_bit_setsda;
+	drv_data->algo_data.setscl = ixp42x_bit_setscl;
+	drv_data->algo_data.getsda = ixp42x_bit_getsda;
+	drv_data->algo_data.getscl = ixp42x_bit_getscl;
+	drv_data->algo_data.udelay = 10;
+	drv_data->algo_data.mdelay = 10;
+	drv_data->algo_data.timeout = 100;
+
+	drv_data->adapter.id = I2C_HW_B_IXP425,
+	drv_data->adapter.algo_data = &drv_data->algo_data,
+
+	drv_data->adapter.dev.parent = &plat_dev->dev;
+
+	gpio_line_config(gpio->scl_pin, IXP425_GPIO_IN);
+	gpio_line_config(gpio->sda_pin, IXP425_GPIO_IN);
+	gpio_line_set(gpio->scl_pin, 0);
+	gpio_line_set(gpio->sda_pin, 0);
+
+	if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) {
+		printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id);
+
+		kfree(drv_data);
+		return err;
+	}
+
+	dev_set_drvdata(&plat_dev->dev, drv_data);
+
+	return 0;
+}
+
+static struct device_driver ixp42x_i2c_driver = {
+	.name		= "IXP42X-I2C",
+	.bus		= &platform_bus_type,
+	.probe		= ixp42x_i2c_probe,
+	.remove		= ixp42x_i2c_remove,
+};
+
+static int __init ixp42x_i2c_init(void)
+{
+	return driver_register(&ixp42x_i2c_driver);
+}
+
+static void __exit ixp42x_i2c_exit(void)
+{
+	driver_unregister(&ixp42x_i2c_driver);
+}
+
+module_init(ixp42x_i2c_init);
+module_exit(ixp42x_i2c_exit);
+
+MODULE_DESCRIPTION("GPIO-based I2C driver for IXP42x systems");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+
--- diff/drivers/i2c/chips/lm80.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/i2c/chips/lm80.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,567 @@
+/*
+ * lm80.c - From lm_sensors, Linux kernel modules for hardware
+ * monitoring
+ * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ * and Philip Edelbrock <phil@netroedge.com>
+ *
+ * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_CHIP
+#define DEBUG	1
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x28, 0x2f, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(lm80);
+
+/* Many LM80 constants specified below */
+
+/* The LM80 registers */
+#define LM80_REG_IN_MAX(nr)		(0x2a + (nr) * 2)
+#define LM80_REG_IN_MIN(nr)		(0x2b + (nr) * 2)
+#define LM80_REG_IN(nr)			(0x20 + (nr))
+
+#define LM80_REG_FAN1_MIN		0x3c
+#define LM80_REG_FAN2_MIN		0x3d
+#define LM80_REG_FAN1			0x28
+#define LM80_REG_FAN2			0x29
+
+#define LM80_REG_TEMP			0x27
+#define LM80_REG_TEMP_HOT_MAX		0x38
+#define LM80_REG_TEMP_HOT_HYST		0x39
+#define LM80_REG_TEMP_OS_MAX		0x3a
+#define LM80_REG_TEMP_OS_HYST		0x3b
+
+#define LM80_REG_CONFIG			0x00
+#define LM80_REG_ALARM1			0x01
+#define LM80_REG_ALARM2			0x02
+#define LM80_REG_MASK1			0x03
+#define LM80_REG_MASK2			0x04
+#define LM80_REG_FANDIV			0x05
+#define LM80_REG_RES			0x06
+
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG
+   variants. Note that you should be a bit careful with which arguments
+   these macros are called: arguments may be evaluated more than once.
+   Fixing this is just not worth it. */
+
+#define IN_TO_REG(val)		(SENSORS_LIMIT((val)/10,0,255))
+#define IN_FROM_REG(val)	((val)*10)
+
+static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+	return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div)	((val)==0?-1:\
+				(val)==255?0:1350000/((div)*(val)))
+
+static inline long TEMP_FROM_REG(u16 temp)
+{
+	long res;
+
+	temp >>= 4;
+	if (temp < 0x0800)
+		res = 625 * (long) temp;
+	else
+		res = ((long) temp - 0x01000) * 625;
+
+	return res / 10;
+}
+
+#define TEMP_LIMIT_FROM_REG(val)	(((val)>0x80?(val)-0x100:(val))*1000)
+
+#define TEMP_LIMIT_TO_REG(val)		SENSORS_LIMIT((val)<0?\
+					((val)-500)/1000:((val)+500)/1000,0,255)
+
+#define ALARMS_FROM_REG(val)		(val)
+
+#define DIV_FROM_REG(val)		(1 << (val))
+#define DIV_TO_REG(val)			((val)==8?3:(val)==4?2:(val)==1?0:1)
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm80_data {
+	struct semaphore update_lock;
+	char valid;		/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u8 in[7];		/* Register value */
+	u8 in_max[7];		/* Register value */
+	u8 in_min[7];		/* Register value */
+	u8 fan[2];		/* Register value */
+	u8 fan_min[2];		/* Register value */
+	u8 fan_div[2];		/* Register encoding, shifted right */
+	u16 temp;		/* Register values, shifted right */
+	u8 temp_hot_max;	/* Register value */
+	u8 temp_hot_hyst;	/* Register value */
+	u8 temp_os_max;		/* Register value */
+	u8 temp_os_hyst;	/* Register value */
+	u16 alarms;		/* Register encoding, combined */
+};
+
+/* 
+ * Functions declaration
+ */
+
+static int lm80_attach_adapter(struct i2c_adapter *adapter);
+static int lm80_detect(struct i2c_adapter *adapter, int address, int kind);
+static void lm80_init_client(struct i2c_client *client);
+static int lm80_detach_client(struct i2c_client *client);
+static void lm80_update_client(struct i2c_client *client);
+static int lm80_read_value(struct i2c_client *client, u8 reg);
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
+
+/*
+ * Internal variables
+ */
+
+static int lm80_id = 0;
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver lm80_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "lm80",
+	.id		= I2C_DRIVERID_LM80,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= lm80_attach_adapter,
+	.detach_client	= lm80_detach_client,
+};
+
+/*
+ * Sysfs stuff
+ */
+
+#define show_in(suffix, value) \
+static ssize_t show_in_##suffix(struct device *dev, char *buf) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	lm80_update_client(client); \
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \
+}
+show_in(min0, in_min[0]);
+show_in(min1, in_min[1]);
+show_in(min2, in_min[2]);
+show_in(min3, in_min[3]);
+show_in(min4, in_min[4]);
+show_in(min5, in_min[5]);
+show_in(min6, in_min[6]);
+show_in(max0, in_max[0]);
+show_in(max1, in_max[1]);
+show_in(max2, in_max[2]);
+show_in(max3, in_max[3]);
+show_in(max4, in_max[4]);
+show_in(max5, in_max[5]);
+show_in(max6, in_max[6]);
+show_in(input0, in[0]);
+show_in(input1, in[1]);
+show_in(input2, in[2]);
+show_in(input3, in[3]);
+show_in(input4, in[4]);
+show_in(input5, in[5]);
+show_in(input6, in[6]);
+
+#define set_in(suffix, value, reg) \
+static ssize_t set_in_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtol(buf, NULL, 10); \
+	data->value = IN_TO_REG(val); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_in(min0, in_min[0], LM80_REG_IN_MIN(0));
+set_in(min1, in_min[1], LM80_REG_IN_MIN(1));
+set_in(min2, in_min[2], LM80_REG_IN_MIN(2));
+set_in(min3, in_min[3], LM80_REG_IN_MIN(3));
+set_in(min4, in_min[4], LM80_REG_IN_MIN(4));
+set_in(min5, in_min[5], LM80_REG_IN_MIN(5));
+set_in(min6, in_min[6], LM80_REG_IN_MIN(6));
+set_in(max0, in_max[0], LM80_REG_IN_MAX(0));
+set_in(max1, in_max[1], LM80_REG_IN_MAX(1));
+set_in(max2, in_max[2], LM80_REG_IN_MAX(2));
+set_in(max3, in_max[3], LM80_REG_IN_MAX(3));
+set_in(max4, in_max[4], LM80_REG_IN_MAX(4));
+set_in(max5, in_max[5], LM80_REG_IN_MAX(5));
+set_in(max6, in_max[6], LM80_REG_IN_MAX(6));
+
+#define show_fan(suffix, value, div) \
+static ssize_t show_fan_##suffix(struct device *dev, char *buf) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	lm80_update_client(client); \
+	return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \
+		       DIV_FROM_REG(data->div))); \
+}
+show_fan(min1, fan_min[0], fan_div[0]);
+show_fan(min2, fan_min[1], fan_div[1]);
+show_fan(input1, fan[0], fan_div[0]);
+show_fan(input2, fan[1], fan_div[1]);
+
+#define show_fan_div(suffix, value) \
+static ssize_t show_fan_div##suffix(struct device *dev, char *buf) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	lm80_update_client(client); \
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \
+}
+show_fan_div(1, fan_div[0]);
+show_fan_div(2, fan_div[1]);
+
+#define set_fan(suffix, value, reg, div) \
+static ssize_t set_fan_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtoul(buf, NULL, 10); \
+	data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_fan(min1, fan_min[0], LM80_REG_FAN1_MIN, fan_div[0]);
+set_fan(min2, fan_min[1], LM80_REG_FAN2_MIN, fan_div[1]);
+
+static ssize_t show_temp_input1(struct device *dev, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm80_data *data = i2c_get_clientdata(client);
+	lm80_update_client(client);
+	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp));
+}
+
+#define show_temp(suffix, value) \
+static ssize_t show_temp_##suffix(struct device *dev, char *buf) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	lm80_update_client(client); \
+	return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \
+}
+show_temp(hot_max, temp_hot_max);
+show_temp(hot_hyst, temp_hot_hyst);
+show_temp(os_max, temp_os_max);
+show_temp(os_hyst, temp_os_hyst);
+
+#define set_temp(suffix, value, reg) \
+static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm80_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtoul(buf, NULL, 10); \
+	data->value = TEMP_LIMIT_TO_REG(val); \
+	lm80_write_value(client, reg, data->value); \
+	return count; \
+}
+set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
+set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);
+set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);
+set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm80_data *data = i2c_get_clientdata(client);
+	lm80_update_client(client);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
+}
+
+static DEVICE_ATTR(in_min0, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0);
+static DEVICE_ATTR(in_min1, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1);
+static DEVICE_ATTR(in_min2, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2);
+static DEVICE_ATTR(in_min3, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3);
+static DEVICE_ATTR(in_min4, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4);
+static DEVICE_ATTR(in_min5, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5);
+static DEVICE_ATTR(in_min6, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6);
+static DEVICE_ATTR(in_max0, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0);
+static DEVICE_ATTR(in_max1, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1);
+static DEVICE_ATTR(in_max2, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2);
+static DEVICE_ATTR(in_max3, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3);
+static DEVICE_ATTR(in_max4, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4);
+static DEVICE_ATTR(in_max5, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5);
+static DEVICE_ATTR(in_max6, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6);
+static DEVICE_ATTR(in_input0, S_IRUGO, show_in_input0, NULL);
+static DEVICE_ATTR(in_input1, S_IRUGO, show_in_input1, NULL);
+static DEVICE_ATTR(in_input2, S_IRUGO, show_in_input2, NULL);
+static DEVICE_ATTR(in_input3, S_IRUGO, show_in_input3, NULL);
+static DEVICE_ATTR(in_input4, S_IRUGO, show_in_input4, NULL);
+static DEVICE_ATTR(in_input5, S_IRUGO, show_in_input5, NULL);
+static DEVICE_ATTR(in_input6, S_IRUGO, show_in_input6, NULL);
+static DEVICE_ATTR(fan_min1, S_IWUSR | S_IRUGO, show_fan_min1,
+    set_fan_min1);
+static DEVICE_ATTR(fan_min2, S_IWUSR | S_IRUGO, show_fan_min2,
+    set_fan_min2);
+static DEVICE_ATTR(fan_input1, S_IRUGO, show_fan_input1, NULL);
+static DEVICE_ATTR(fan_input2, S_IRUGO, show_fan_input2, NULL);
+static DEVICE_ATTR(fan_div1, S_IRUGO, show_fan_div1, NULL);
+static DEVICE_ATTR(fan_div2, S_IRUGO, show_fan_div2, NULL);
+static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_hot_max,
+    set_temp_hot_max);
+static DEVICE_ATTR(temp_max1_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst,
+    set_temp_hot_hyst);
+static DEVICE_ATTR(temp_crit1, S_IWUSR | S_IRUGO, show_temp_os_max,
+    set_temp_os_max);
+static DEVICE_ATTR(temp_crit1_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst,
+    set_temp_os_hyst);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+/*
+ * Real code
+ */
+
+static int lm80_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
+	return i2c_detect(adapter, &addr_data, lm80_detect);
+}
+
+int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	int i, cur;
+	struct i2c_client *new_client;
+	struct lm80_data *data;
+	int err = 0;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto exit;
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access lm80_{read,write}_value. */
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+	    sizeof(struct lm80_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(new_client, 0x00, sizeof(struct i2c_client) +
+	       sizeof(struct lm80_data));
+
+	data = (struct lm80_data *) (new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &lm80_driver;
+	new_client->flags = 0;
+
+	/* Now, we do the remaining detection. It is lousy. */
+	if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0)
+		goto error_free;
+	for (i = 0x2a; i <= 0x3d; i++) {
+		cur = i2c_smbus_read_byte_data(new_client, i);
+		if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur)
+		 || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur)
+		 || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur))
+		    goto error_free;
+	}
+
+	/* Determine the chip type - only one kind supported! */
+	kind = lm80;
+	name = "lm80";
+
+	/* Fill in the remaining client fields and put it into the global list */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+
+	new_client->id = lm80_id++;
+	data->valid = 0;
+	init_MUTEX(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto error_free;
+
+	/* Initialize the LM80 chip */
+	lm80_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_in_min0);
+	device_create_file(&new_client->dev, &dev_attr_in_min1);
+	device_create_file(&new_client->dev, &dev_attr_in_min2);
+	device_create_file(&new_client->dev, &dev_attr_in_min3);
+	device_create_file(&new_client->dev, &dev_attr_in_min4);
+	device_create_file(&new_client->dev, &dev_attr_in_min5);
+	device_create_file(&new_client->dev, &dev_attr_in_min6);
+	device_create_file(&new_client->dev, &dev_attr_in_max0);
+	device_create_file(&new_client->dev, &dev_attr_in_max1);
+	device_create_file(&new_client->dev, &dev_attr_in_max2);
+	device_create_file(&new_client->dev, &dev_attr_in_max3);
+	device_create_file(&new_client->dev, &dev_attr_in_max4);
+	device_create_file(&new_client->dev, &dev_attr_in_max5);
+	device_create_file(&new_client->dev, &dev_attr_in_max6);
+	device_create_file(&new_client->dev, &dev_attr_in_input0);
+	device_create_file(&new_client->dev, &dev_attr_in_input1);
+	device_create_file(&new_client->dev, &dev_attr_in_input2);
+	device_create_file(&new_client->dev, &dev_attr_in_input3);
+	device_create_file(&new_client->dev, &dev_attr_in_input4);
+	device_create_file(&new_client->dev, &dev_attr_in_input5);
+	device_create_file(&new_client->dev, &dev_attr_in_input6);
+	device_create_file(&new_client->dev, &dev_attr_fan_min1);
+	device_create_file(&new_client->dev, &dev_attr_fan_min2);
+	device_create_file(&new_client->dev, &dev_attr_fan_input1);
+	device_create_file(&new_client->dev, &dev_attr_fan_input2);
+	device_create_file(&new_client->dev, &dev_attr_fan_div1);
+	device_create_file(&new_client->dev, &dev_attr_fan_div2);
+	device_create_file(&new_client->dev, &dev_attr_temp_input1);
+	device_create_file(&new_client->dev, &dev_attr_temp_max1);
+	device_create_file(&new_client->dev, &dev_attr_temp_max1_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp_crit1);
+	device_create_file(&new_client->dev, &dev_attr_temp_crit1_hyst);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+
+	return 0;
+
+error_free:
+	kfree(new_client);
+exit:
+	return err;
+}
+
+static int lm80_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+	return 0;
+}
+
+static int lm80_read_value(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* Called when we have found a new LM80. */
+static void lm80_init_client(struct i2c_client *client)
+{
+	/* Reset all except Watchdog values and last conversion values
+	   This sets fan-divs to 2, among others. This makes most other
+	   initializations unnecessary */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x80);
+	/* Set 11-bit temperature resolution */
+	lm80_write_value(client, LM80_REG_RES, 0x08);
+
+	/* Start monitoring */
+	lm80_write_value(client, LM80_REG_CONFIG, 0x01);
+}
+
+static void lm80_update_client(struct i2c_client *client)
+{
+	struct lm80_data *data = i2c_get_clientdata(client);
+	int i;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > 2 * HZ) ||
+	    (jiffies < data->last_updated) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting lm80 update\n");
+		for (i = 0; i <= 6; i++) {
+			data->in[i] =
+			    lm80_read_value(client, LM80_REG_IN(i));
+			data->in_min[i] =
+			    lm80_read_value(client, LM80_REG_IN_MIN(i));
+			data->in_max[i] =
+			    lm80_read_value(client, LM80_REG_IN_MAX(i));
+		}
+		data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
+		data->fan_min[0] =
+		    lm80_read_value(client, LM80_REG_FAN1_MIN);
+		data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
+		data->fan_min[1] =
+		    lm80_read_value(client, LM80_REG_FAN2_MIN);
+
+		data->temp =
+		    (lm80_read_value(client, LM80_REG_TEMP) << 8) |
+		    (lm80_read_value(client, LM80_REG_RES) & 0xf0);
+		data->temp_os_max =
+		    lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
+		data->temp_os_hyst =
+		    lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
+		data->temp_hot_max =
+		    lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
+		data->temp_hot_hyst =
+		    lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
+
+		i = lm80_read_value(client, LM80_REG_FANDIV);
+		data->fan_div[0] = (i >> 2) & 0x03;
+		data->fan_div[1] = (i >> 4) & 0x03;
+		data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
+		    (lm80_read_value(client, LM80_REG_ALARM2) << 8);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+}
+
+static int __init sensors_lm80_init(void)
+{
+	return i2c_add_driver(&lm80_driver);
+}
+
+static void __exit sensors_lm80_exit(void)
+{
+	i2c_del_driver(&lm80_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+	"Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("LM80 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm80_init);
+module_exit(sensors_lm80_exit);
--- diff/drivers/ieee1394/csr1212.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/ieee1394/csr1212.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,1566 @@
+/*
+ * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
+ * 
+ * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
+ *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *    3. The name of the author may not be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/* TODO List:
+ * - Verify interface consistency: i.e., public functions that take a size
+ *   parameter expect size to be in bytes.
+ * - Convenience functions for reading a block of data from a given offset.
+ */
+
+#ifndef __KERNEL__
+#include <string.h>
+#endif
+
+#include "csr1212.h"
+
+
+/* Permitted key type for each key id */
+#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
+#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
+#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
+#define __L (1 << CSR1212_KV_TYPE_LEAF)
+static const u_int8_t csr1212_key_id_type_map[0x30] = {
+	0,			/* Reserved */
+	__D | __L,		/* Descriptor */
+	__I | __D | __L,	/* Bus_Dependent_Info */
+	__I | __D | __L,	/* Vendor */
+	__I,			/* Hardware_Version */
+	0, 0,			/* Reserved */
+	__D | __L,		/* Module */
+	0, 0, 0, 0,		/* Reserved */
+	__I,			/* Node_Capabilities */
+	__L,			/* EUI_64 */
+	0, 0, 0,		/* Reserved */
+	__D,			/* Unit */
+	__I,			/* Specifier_ID */
+	__I,			/* Version */
+	__I | __C | __D | __L,	/* Dependent_Info */
+	__L,			/* Unit_Location */
+	0,			/* Reserved */
+	__I,			/* Model */
+	__D,			/* Instance */
+	__L,			/* Keyword */
+	__D,			/* Feature */
+	__L,			/* Extended_ROM */
+	__I,			/* Extended_Key_Specifier_ID */
+	__I,			/* Extended_Key */
+	__I | __C | __D | __L,	/* Extended_Data */
+	__L,			/* Modifiable_Descriptor */
+	__I,			/* Directory_ID */
+	__I,			/* Revision */
+};
+#undef __I
+#undef __C
+#undef __D
+#undef __L
+
+
+#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t))
+#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t))
+
+static inline void free_keyval(struct csr1212_keyval *kv)
+{
+	if (kv->key.type == CSR1212_KV_TYPE_LEAF)
+		CSR1212_FREE(kv->value.leaf.data);
+
+	CSR1212_FREE(kv);
+}
+
+static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
+{
+	int shift;
+	u_int32_t data;
+	u_int16_t sum, crc = 0;
+
+	for (; length; length--) {
+		data = CSR1212_BE32_TO_CPU(*buffer);
+		buffer++;
+		for (shift = 28; shift >= 0; shift -= 4 ) {
+			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
+			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
+		}
+		crc &= 0xffff;
+	}
+
+	return CSR1212_CPU_TO_BE16(crc);
+}
+
+#if 0
+/* Microsoft computes the CRC with the bytes in reverse order.  Therefore we
+ * have a special version of the CRC algorithm to account for their buggy
+ * software. */
+static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
+{
+	int shift;
+	u_int32_t data;
+	u_int16_t sum, crc = 0;
+
+	for (; length; length--) {
+		data = CSR1212_LE32_TO_CPU(*buffer);
+		buffer++;
+		for (shift = 28; shift >= 0; shift -= 4 ) {
+			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
+			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
+		}
+		crc &= 0xffff;
+	}
+
+	return CSR1212_CPU_TO_BE16(crc);
+}
+#endif
+
+static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir,
+							 struct csr1212_keyval *kv)
+{
+	struct csr1212_dentry *pos;
+
+	for (pos = dir->value.directory.dentries_head;
+	     pos != NULL; pos = pos->next) {
+		if (pos->kv == kv)
+			return pos;
+	}
+	return NULL;
+}
+
+
+static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list,
+								u_int32_t offset)
+{
+	struct csr1212_keyval *kv;
+
+	for (kv = kv_list; kv != NULL; kv = kv->next) {
+		if (kv->offset == offset)
+			return kv;
+	}
+	return NULL;
+}
+
+
+/* Creation Routines */
+struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
+				       size_t bus_info_size, void *private)
+{
+	struct csr1212_csr *csr;
+
+	csr = CSR1212_MALLOC(sizeof(*csr));
+	if (!csr)
+		return NULL;
+
+	csr->cache_head = 
+		csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
+					 CSR1212_CONFIG_ROM_SPACE_SIZE);
+	if (!csr->cache_head) {
+		CSR1212_FREE(csr);
+		return NULL;
+	}
+
+        /* The keyval key id is not used for the root node, but a valid key id
+         * that can be used for a directory needs to be passed to
+         * csr1212_new_directory(). */
+	csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
+	if (!csr->root_kv) {
+		CSR1212_FREE(csr->cache_head);
+		CSR1212_FREE(csr);
+		return NULL;
+	}
+
+	csr->bus_info_data = csr->cache_head->data;
+	csr->bus_info_len = bus_info_size;
+	csr->crc_len = bus_info_size;
+	csr->ops = ops;
+	csr->private = private;
+	csr->cache_tail = csr->cache_head;
+
+	return csr;
+}
+
+
+
+void csr1212_init_local_csr(struct csr1212_csr *csr,
+			    const u_int32_t *bus_info_data, int max_rom)
+{
+	csr->max_rom = max_rom;
+	memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
+}
+
+
+static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
+{
+	struct csr1212_keyval *kv;
+
+	if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
+		return NULL;
+
+	kv = CSR1212_MALLOC(sizeof(*kv));
+	if (!kv)
+		return NULL;
+
+	kv->key.type = type;
+	kv->key.id = key;
+
+	kv->associate = NULL;
+	kv->refcnt = 1;
+
+	kv->next = NULL;
+	kv->prev = NULL;
+	kv->offset = 0;
+	kv->valid = 0;
+	return kv;
+}
+
+struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
+{
+	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
+	
+	if (!kv)
+		return NULL;
+
+	kv->value.immediate = value;
+	kv->valid = 1;
+	return kv;
+}
+
+struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len)
+{
+	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
+
+	if (!kv)
+		return NULL;
+	
+	if (data_len > 0) {
+		kv->value.leaf.data = CSR1212_MALLOC(data_len);
+		if (!kv->value.leaf.data)
+		{
+			CSR1212_FREE(kv);
+			return NULL;
+		}
+
+		if (data)
+			memcpy(kv->value.leaf.data, data, data_len);
+	} else {
+		kv->value.leaf.data = NULL;
+	}
+
+	kv->value.leaf.len = bytes_to_quads(data_len);
+	kv->offset = 0;
+	kv->valid = 1;
+
+	return kv;
+}
+
+struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset)
+{
+	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
+
+	if (!kv)
+		return NULL;
+
+	kv->value.csr_offset = csr_offset;
+
+	kv->offset = 0;
+	kv->valid = 1;
+	return kv;
+}
+
+struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
+{
+	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
+
+	if (!kv)
+		return NULL;
+
+	kv->value.directory.len = 0;
+	kv->offset = 0;
+	kv->value.directory.dentries_head = NULL;
+	kv->value.directory.dentries_tail = NULL;
+	kv->valid = 1;
+	return kv;
+}
+
+int csr1212_associate_keyval(struct csr1212_keyval *kv,
+			     struct csr1212_keyval *associate)
+{
+	if (!kv || !associate)
+		return CSR1212_EINVAL;
+
+	if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
+	   (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
+	    associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
+	    associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
+	    associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
+	    associate->key.id < 0x30))
+		return CSR1212_EINVAL;
+
+	if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
+	   associate->key.id != CSR1212_KV_ID_EXTENDED_KEY)
+		return CSR1212_EINVAL;
+
+	if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+	   associate->key.id != CSR1212_KV_ID_EXTENDED_DATA)
+		return CSR1212_EINVAL;
+
+	if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+	   kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID)
+		return CSR1212_EINVAL;
+
+	if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
+	   kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)
+		return CSR1212_EINVAL;
+
+	if (kv->associate)
+		csr1212_release_keyval(kv->associate);
+
+	associate->refcnt++;
+	kv->associate = associate;
+
+	return CSR1212_SUCCESS;
+}
+
+int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
+				       struct csr1212_keyval *kv)
+{
+	struct csr1212_dentry *dentry;
+
+	if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
+		return CSR1212_EINVAL;
+
+	dentry = CSR1212_MALLOC(sizeof(*dentry));
+	if (!dentry)
+		return CSR1212_ENOMEM;
+
+	dentry->kv = kv;
+
+	kv->refcnt++;
+
+	dentry->next = NULL;
+	dentry->prev = dir->value.directory.dentries_tail;
+
+	if (!dir->value.directory.dentries_head)
+		dir->value.directory.dentries_head = dentry;
+
+	if (dir->value.directory.dentries_tail)
+		dir->value.directory.dentries_tail->next = dentry;
+	dir->value.directory.dentries_tail = dentry;
+
+	return CSR1212_SUCCESS;
+}
+
+struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key,
+						      u_int32_t value)
+{
+	struct csr1212_keyval *kvs, *kvk, *kvv;
+
+	kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
+	kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
+	kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value);
+
+	if (!kvs || !kvk || !kvv) {
+		if (kvs)
+			free_keyval(kvs);
+		if (kvk)
+			free_keyval(kvk);
+		if (kvv)
+			free_keyval(kvv);
+		return NULL;
+	}
+
+	/* Don't keep a local reference to the extended key or value. */
+	kvk->refcnt = 0;
+	kvv->refcnt = 0;
+
+	csr1212_associate_keyval(kvk, kvv);
+	csr1212_associate_keyval(kvs, kvk);
+
+	return kvs;
+}
+
+struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, u_int32_t key,
+						 const void *data, size_t data_len)
+{
+	struct csr1212_keyval *kvs, *kvk, *kvv;
+
+	kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
+	kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
+	kvv = csr1212_new_leaf(CSR1212_KV_ID_EXTENDED_DATA, data, data_len);
+
+	if (!kvs || !kvk || !kvv) {
+		if (kvs)
+			free_keyval(kvs);
+		if (kvk)
+			free_keyval(kvk);
+		if (kvv)
+			free_keyval(kvv);
+		return NULL;
+	}
+
+	/* Don't keep a local reference to the extended key or value. */
+	kvk->refcnt = 0;
+	kvv->refcnt = 0;
+
+	csr1212_associate_keyval(kvk, kvv);
+	csr1212_associate_keyval(kvs, kvk);
+
+	return kvs;
+}
+
+struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id,
+						   const void *data, size_t data_len)
+{
+	struct csr1212_keyval *kv;
+
+	kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
+			      data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
+	if (!kv)
+		return NULL;
+
+	CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
+	CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
+
+	if (data) {
+		memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
+	}
+
+	return kv;
+}
+
+
+struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
+							   u_int16_t cset,
+							   u_int16_t language,
+							   const void *data,
+							   size_t data_len)
+{
+	struct csr1212_keyval *kv;
+	char *lstr;
+
+	kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
+					 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
+	if (!kv)
+		return NULL;
+
+	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
+	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
+	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
+
+	lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
+
+	/* make sure last quadlet is zeroed out */
+	*((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0;
+
+	/* don't copy the NUL terminator */
+	memcpy(lstr, data, data_len);
+
+	return kv;
+}
+
+static int csr1212_check_minimal_ascii(const char *s)
+{
+	static const char minimal_ascii_table[] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+		0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
+		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+		0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+		0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+		0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+		0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+		0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+		0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
+		0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+		0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+		0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+		0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
+	};
+	for (; *s; s++) {
+		if (minimal_ascii_table[*s & 0x7F] != *s)
+			return -1; /* failed */
+	}
+	/* String conforms to minimal-ascii, as specified by IEEE 1212,
+	 * par. 7.4 */
+	return 0;
+}
+
+struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
+{
+	/* Check if string conform to minimal_ascii format */
+	if (csr1212_check_minimal_ascii(s))
+		return NULL;
+
+	/* IEEE 1212, par. 7.5.4.1  Textual descriptors (minimal ASCII) */
+	return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
+}
+
+struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
+							u_int8_t palette_depth,
+							u_int8_t color_space,
+							u_int16_t language,
+							u_int16_t hscan,
+							u_int16_t vscan,
+							u_int32_t *palette,
+							u_int32_t *pixels)
+{
+	static const int pd[4] = { 0, 4, 16, 256 };
+	static const int cs[16] = { 4, 2 };
+	struct csr1212_keyval *kv;
+	int palette_size = pd[palette_depth] * cs[color_space];
+	int pixel_size = (hscan * vscan + 3) & ~0x3;
+
+	if ((palette_depth && !palette) || !pixels)
+		return NULL;
+
+	kv = csr1212_new_descriptor_leaf(1, 0, NULL,
+					 palette_size + pixel_size +
+					 CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
+	if (!kv)
+		return NULL;
+
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version);
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth);
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space);
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan);
+	CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan);
+
+	if (palette_size)
+		memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette,
+		       palette_size);
+
+	memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size);
+
+	return kv;
+}
+
+struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
+							      u_int64_t address)
+{
+	struct csr1212_keyval *kv;
+
+	/* IEEE 1212, par. 7.5.4.3  Modifiable descriptors */
+	kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t));
+	if(!kv)
+		return NULL;
+
+	CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size);
+	CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address);
+	CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address);
+        
+	return kv;
+}
+
+static int csr1212_check_keyword(const char *s)
+{
+	for (; *s; s++) {
+
+		if (('A' <= *s) && (*s <= 'Z'))
+			continue;
+		if (('0' <= *s) && (*s <= '9'))
+			continue;
+		if (*s == '-')
+			continue;
+
+		return -1; /* failed */
+	}
+	/* String conforms to keyword, as specified by IEEE 1212,
+	 * par. 7.6.5 */
+	return CSR1212_SUCCESS;
+}
+
+struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[])
+{
+	struct csr1212_keyval *kv;
+	char *buffer;
+	int i, data_len = 0;
+
+	/* Check all keywords to see if they conform to restrictions:
+	 * Only the following characters is allowed ['A'..'Z','0'..'9','-']
+	 * Each word is zero-terminated.
+	 * Also calculate the total length of the keywords.
+	 */
+	for (i = 0; i < strc; i++) {
+		if (!strv[i] || csr1212_check_keyword(strv[i])) {
+			return NULL;
+		}
+		data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */
+	}
+
+	/* IEEE 1212, par. 7.6.5 Keyword leaves */
+	kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len);
+	if (!kv)
+		return NULL;
+
+	buffer = (char *)kv->value.leaf.data;
+
+	/* make sure last quadlet is zeroed out */
+	*((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0;
+	
+	/* Copy keyword(s) into leaf data buffer */
+	for (i = 0; i < strc; i++) {
+		int len = strlen(strv[i]) + 1;
+		memcpy(buffer, strv[i], len);
+		buffer += len;
+	}
+	return kv;
+}
+
+
+/* Destruction Routines */
+
+void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
+					  struct csr1212_keyval *kv)
+{
+	struct csr1212_dentry *dentry;
+
+	if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
+		return;
+
+	dentry = csr1212_find_keyval(dir, kv);
+	
+	if (!dentry)
+		return;
+
+	if (dentry->prev)
+		dentry->prev->next = dentry->next;
+	if (dentry->next)
+		dentry->next->prev = dentry->prev;
+	if (dir->value.directory.dentries_head == dentry)
+		dir->value.directory.dentries_head = dentry->next;
+	if (dir->value.directory.dentries_tail == dentry)
+		dir->value.directory.dentries_tail = dentry->prev;
+
+	CSR1212_FREE(dentry);
+
+	csr1212_release_keyval(kv);
+}
+
+
+void csr1212_disassociate_keyval(struct csr1212_keyval *kv)
+{
+	if (kv->associate) {
+		csr1212_release_keyval(kv->associate);
+	}
+
+	kv->associate = NULL;
+}
+
+
+/* This function is used to free the memory taken by a keyval.  If the given
+ * keyval is a directory type, then any keyvals contained in that directory
+ * will be destroyed as well if their respective refcnts are 0.  By means of
+ * list manipulation, this routine will descend a directory structure in a
+ * non-recursive manner. */
+void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
+{
+	struct csr1212_keyval *k, *a;
+	struct csr1212_dentry dentry;
+	struct csr1212_dentry *head, *tail;
+
+	dentry.kv = kv;
+	dentry.next = NULL;
+	dentry.prev = NULL;
+
+	head = &dentry;
+	tail = head;
+
+	while (head) {
+		k = head->kv;
+
+		while (k) {
+			k->refcnt--;
+
+			if (k->refcnt > 0)
+				break;
+
+			a = k->associate;
+
+			if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
+				/* If the current entry is a directory, then move all
+				 * the entries to the destruction list. */
+				tail->next = k->value.directory.dentries_head;
+				if (k->value.directory.dentries_head)
+					k->value.directory.dentries_head->prev = tail;
+				tail = k->value.directory.dentries_tail;
+			}
+			free_keyval(k);
+			k = a;
+		}
+
+		head = head->next;
+		if (head) {
+			if (head->prev && head->prev != &dentry) {
+				CSR1212_FREE(head->prev);
+			}
+			head->prev = NULL;
+		} else if (tail != &dentry)
+			CSR1212_FREE(tail);
+	}
+}
+
+
+void csr1212_destroy_csr(struct csr1212_csr *csr)
+{
+	struct csr1212_csr_rom_cache *c, *oc;
+	struct csr1212_cache_region *cr, *ocr;
+
+	csr1212_release_keyval(csr->root_kv);
+
+	c = csr->cache_head;
+	while (c) {
+		oc = c;
+		cr = c->filled_head;
+		while (cr) {
+			ocr = cr;
+			cr = cr->next;
+			CSR1212_FREE(ocr);
+		}
+		c = c->next;
+		CSR1212_FREE(oc);
+	}
+
+	CSR1212_FREE(csr);
+}
+
+
+
+/* CSR Image Creation */
+
+static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
+{
+	struct csr1212_csr_rom_cache *cache;
+	u_int64_t csr_addr;
+
+	if (!csr || !csr->ops->allocate_addr_range ||
+	    !csr->ops->release_addr)
+		return CSR1212_ENOMEM;
+
+	/* ROM size must be a multiple of csr->max_rom */
+	romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
+
+	csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
+	if (csr_addr == ~0ULL) {
+		return CSR1212_ENOMEM;
+	}
+	if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
+		/* Invalid address returned from allocate_addr_range(). */
+		csr->ops->release_addr(csr_addr, csr->private);
+		return CSR1212_ENOMEM;
+	}
+
+	cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
+	if (!cache) {
+		csr->ops->release_addr(csr_addr, csr->private);
+		return CSR1212_ENOMEM;
+	}
+
+	cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
+	if (!cache->ext_rom) {
+		csr->ops->release_addr(csr_addr, csr->private);
+		CSR1212_FREE(cache);
+		return CSR1212_ENOMEM;
+	}
+
+	if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS)
+	{
+		csr1212_release_keyval(cache->ext_rom);
+		csr->ops->release_addr(csr_addr, csr->private);
+		CSR1212_FREE(cache);
+		return CSR1212_ENOMEM;
+	}
+	cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
+	cache->ext_rom->value.leaf.len = 0;
+
+	/* Add cache to tail of cache list */
+	cache->prev = csr->cache_tail;
+	csr->cache_tail->next = cache;
+	csr->cache_tail = cache;
+	return CSR1212_SUCCESS;
+}
+
+static inline void csr1212_remove_cache(struct csr1212_csr *csr,
+					struct csr1212_csr_rom_cache *cache)
+{
+	if (csr->cache_head == cache)
+		csr->cache_head = cache->next;
+	if (csr->cache_tail == cache)
+		csr->cache_tail = cache->prev;
+
+	if (cache->prev)
+		cache->prev->next = cache->next;
+	if (cache->next)
+		cache->next->prev = cache->prev;
+
+	if (cache->ext_rom) {
+		csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
+		csr1212_release_keyval(cache->ext_rom);
+	}
+
+	CSR1212_FREE(cache);
+}
+
+static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
+					  struct csr1212_keyval **layout_tail)
+{
+	struct csr1212_dentry *dentry;
+	struct csr1212_keyval *dkv;
+	struct csr1212_keyval *last_extkey_spec = NULL;
+	struct csr1212_keyval *last_extkey = NULL;
+	int num_entries = 0;
+
+	for (dentry = dir->value.directory.dentries_head; dentry;
+	     dentry = dentry->next) {
+		for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
+			/* Special Case: Extended Key Specifier_ID */
+			if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+				if (last_extkey_spec == NULL) {
+					last_extkey_spec = dkv;
+				} else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
+					last_extkey_spec = dkv;
+				} else {
+					continue;
+				}
+			/* Special Case: Extended Key */
+			} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
+				if (last_extkey == NULL) {
+					last_extkey = dkv;
+				} else if (dkv->value.immediate != last_extkey->value.immediate) {
+					last_extkey = dkv;
+				} else {
+					continue;
+				}
+			}
+
+			num_entries += 1;
+
+			switch(dkv->key.type) {
+			default:
+			case CSR1212_KV_TYPE_IMMEDIATE:
+			case CSR1212_KV_TYPE_CSR_OFFSET:
+				continue;
+			case CSR1212_KV_TYPE_LEAF:
+			case CSR1212_KV_TYPE_DIRECTORY:
+				/* Remove from list */
+				if (dkv->prev)
+					dkv->prev->next = dkv->next;
+				if (dkv->next)
+					dkv->next->prev = dkv->prev;
+				if (dkv == *layout_tail)
+					*layout_tail = dkv->prev;
+
+				/* Special case: Extended ROM leafs */
+				if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
+					dkv->value.leaf.len = 0; /* initialize to zero */
+					/* Don't add Extended ROM leafs in the layout list,
+					 * they are handled differently. */
+					break;
+				}
+
+				/* Add to tail of list */
+				dkv->next = NULL;
+				dkv->prev = *layout_tail;
+				(*layout_tail)->next = dkv;
+				*layout_tail = dkv;
+				break;
+			}
+		}
+	}
+	return num_entries;
+}
+
+size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
+{
+	struct csr1212_keyval *ltail = kv;
+	size_t agg_size = 0;
+
+	while(kv) {
+		switch(kv->key.type) {
+		case CSR1212_KV_TYPE_LEAF:
+			/* Add 1 quadlet for crc/len field */
+			agg_size += kv->value.leaf.len + 1;
+			break;
+
+		case CSR1212_KV_TYPE_DIRECTORY:
+			kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
+			/* Add 1 quadlet for crc/len field */
+			agg_size += kv->value.directory.len + 1;
+			break;
+		}
+		kv = kv->next;
+	}
+	return quads_to_bytes(agg_size);
+}
+
+struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
+                                                  struct csr1212_keyval *start_kv,
+                                                  int start_pos)
+{
+	struct csr1212_keyval *kv = start_kv;
+	struct csr1212_keyval *okv = start_kv;
+	int pos = start_pos;
+	int kv_len = 0, okv_len = 0;
+
+	cache->layout_head = kv;
+
+	while(kv && pos < cache->size) {
+		kv->offset = cache->offset + pos;
+
+		switch(kv->key.type) {
+		case CSR1212_KV_TYPE_LEAF:
+			kv_len = kv->value.leaf.len;
+			break;
+
+		case CSR1212_KV_TYPE_DIRECTORY:
+			kv_len = kv->value.directory.len;
+			break;
+
+		default:
+			/* Should never get here */
+			break;
+		}
+
+		pos += quads_to_bytes(kv_len + 1);
+
+		if (pos <= cache->size) {
+			okv = kv;
+			okv_len = kv_len;
+			kv = kv->next;
+		}
+	}
+
+	cache->layout_tail = okv;
+	cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
+
+	return kv;
+}
+
+static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir,
+					 u_int32_t *data_buffer)
+{
+	struct csr1212_dentry *dentry;
+	struct csr1212_keyval *last_extkey_spec = NULL;
+	struct csr1212_keyval *last_extkey = NULL;
+	int index = 0;
+
+	for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
+		struct csr1212_keyval *a;
+
+		for (a = dentry->kv; a; a = a->associate) {
+			u_int32_t value = 0;
+
+			/* Special Case: Extended Key Specifier_ID */
+			if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+				if (last_extkey_spec == NULL) {
+					last_extkey_spec = a;
+				} else if (a->value.immediate != last_extkey_spec->value.immediate) {
+					last_extkey_spec = a;
+				} else {
+					continue;
+				}
+			/* Special Case: Extended Key */
+			} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
+				if (last_extkey == NULL) {
+					last_extkey = a;
+				} else if (a->value.immediate != last_extkey->value.immediate) {
+					last_extkey = a;
+				} else {
+					continue;
+				}
+			}
+
+			switch(a->key.type) {
+			case CSR1212_KV_TYPE_IMMEDIATE:
+				value = a->value.immediate;
+				break;
+			case CSR1212_KV_TYPE_CSR_OFFSET:
+				value = a->value.csr_offset;
+				break;
+			case CSR1212_KV_TYPE_LEAF:
+				value = a->offset;
+				value -= dir->offset + quads_to_bytes(1+index);
+				value = bytes_to_quads(value);
+				break;
+			case CSR1212_KV_TYPE_DIRECTORY:
+				value = a->offset;
+				value -= dir->offset + quads_to_bytes(1+index);
+				value = bytes_to_quads(value);
+				break;
+			default:
+				/* Should never get here */
+				break; /* GDB breakpoint */
+			}
+
+			value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
+			value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
+				(CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
+			data_buffer[index] = CSR1212_CPU_TO_BE32(value);
+			index++;
+		}
+	}
+}
+
+void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
+{
+	struct csr1212_keyval *kv, *nkv;
+	struct csr1212_keyval_img *kvi;
+
+	for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
+		kvi = (struct csr1212_keyval_img *)
+			(cache->data + bytes_to_quads(kv->offset - cache->offset));
+		switch(kv->key.type) {
+		default:
+		case CSR1212_KV_TYPE_IMMEDIATE:
+		case CSR1212_KV_TYPE_CSR_OFFSET:
+			/* Should never get here */
+			break; /* GDB breakpoint */
+
+		case CSR1212_KV_TYPE_LEAF:
+			/* Don't copy over Extended ROM areas, they are
+			 * already filled out! */
+			if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
+				memcpy(kvi->data, kv->value.leaf.data,
+				       quads_to_bytes(kv->value.leaf.len));
+
+			kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len);
+			kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
+			break;
+
+		case CSR1212_KV_TYPE_DIRECTORY:
+			csr1212_generate_tree_subdir(kv, kvi->data);
+
+			kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len);
+			kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
+			break;
+		}
+
+		nkv = kv->next;
+		kv->prev = NULL;
+		kv->next = NULL;
+	}
+}
+
+int csr1212_generate_csr_image(struct csr1212_csr *csr)
+{
+	struct csr1212_bus_info_block_img *bi;
+	struct csr1212_csr_rom_cache *cache;
+	struct csr1212_keyval *kv;
+	size_t agg_size;
+	int ret;
+	int init_offset;
+
+	if (!csr)
+		return CSR1212_EINVAL;
+
+	cache = csr->cache_head;
+
+	bi = (struct csr1212_bus_info_block_img*)cache->data;
+
+	bi->length = bytes_to_quads(csr->bus_info_len) - 1;
+	bi->crc_length = bi->length;
+	bi->crc = csr1212_crc16(bi->data, bi->crc_length);
+
+	agg_size = csr1212_generate_layout_order(csr->root_kv);
+
+	init_offset = csr->bus_info_len;
+
+	for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
+		if (!cache) {
+			/* Estimate approximate number of additional cache
+			 * regions needed (it assumes that the cache holding
+			 * the first 1K Config ROM space always exists). */
+			int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
+						(2 * sizeof(u_int32_t))) + 1;
+
+			/* Add additional cache regions, extras will be
+			 * removed later */
+			for (; est_c; est_c--) {
+				ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
+				if (ret != CSR1212_SUCCESS)
+					return ret;
+			}
+			/* Need to re-layout for additional cache regions */
+			agg_size = csr1212_generate_layout_order(csr->root_kv);
+			kv = csr->root_kv;
+			cache = csr->cache_head;
+			init_offset = csr->bus_info_len;
+		}
+		kv = csr1212_generate_positions(cache, kv, init_offset);
+		agg_size -= cache->len;
+		init_offset = sizeof(u_int32_t);
+	}
+
+	/* Remove unused, excess cache regions */
+	while (cache) {
+		struct csr1212_csr_rom_cache *oc = cache;
+		
+		cache = cache->next;
+		csr1212_remove_cache(csr, oc);
+	}
+
+
+	/* Go through the list backward so that when done, the correct CRC
+	 * will be calculated for the Extended ROM areas. */
+	for(cache = csr->cache_tail; cache; cache = cache->prev) {
+		/* Only Extended ROM caches should have this set. */
+		if (cache->ext_rom) {
+			int leaf_size;
+
+			/* Make sure the Extended ROM leaf is a multiple of
+			 * max_rom in size. */
+			leaf_size = (cache->len + (csr->max_rom - 1)) &
+				(csr->max_rom - 1);
+
+			/* Zero out the unused ROM region */
+			memset(cache->data + bytes_to_quads(cache->len), 0x00,
+			       leaf_size - cache->len);
+
+			/* Subtract leaf header */
+			leaf_size -= sizeof(u_int32_t);
+
+			/* Update the Extended ROM leaf length */
+			cache->ext_rom->value.leaf.len =
+				bytes_to_quads(leaf_size);
+		} else {
+			/* Zero out the unused ROM region */
+			memset(cache->data + bytes_to_quads(cache->len), 0x00,
+			       cache->size - cache->len);
+		}
+
+		/* Copy the data into the cache buffer */
+		csr1212_fill_cache(cache);
+	}
+
+	return CSR1212_SUCCESS;
+}
+
+int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len)
+{
+	struct csr1212_csr_rom_cache *cache;
+
+	for (cache = csr->cache_head; cache; cache = cache->next) {
+		if (offset >= cache->offset &&
+		    (offset + len) <= (cache->offset + cache->size)) {
+			memcpy(buffer,
+			       &cache->data[bytes_to_quads(offset - cache->offset)],
+			       len);
+			return CSR1212_SUCCESS;
+		} else if (((offset < cache->offset) &&
+			    ((offset + len) >= cache->offset)) ||
+			   ((offset >= cache->offset) &&
+			    ((offset + len) > (cache->offset + cache->size)))) {
+			return CSR1212_EINVAL;
+		}
+	}
+	return CSR1212_ENOENT;
+}
+
+
+
+/* Parse a chunk of data as a Config ROM */
+
+static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
+{
+	struct csr1212_bus_info_block_img *bi;
+	struct csr1212_cache_region *cr;
+	int i;
+	int ret;
+
+	/* IEEE 1212 says that the entire bus info block should be readable in
+	 * a single transaction regardless of the max_rom value.
+	 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
+	 * bus info block will be read 1 quadlet at a time.  The rest of the
+	 * ConfigROM will be read according to the max_rom field. */
+	for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) {
+		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
+					 sizeof(csr1212_quad_t),
+					 &csr->cache_head->data[bytes_to_quads(i)],
+					 csr->private);
+		if (ret != CSR1212_SUCCESS)
+			return ret;
+	}
+
+	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
+	csr->crc_len = quads_to_bytes(bi->crc_length);
+
+	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
+	 * always the case, so read the rest of the crc area 1 quadlet at a time. */
+	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) {
+		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
+					 sizeof(csr1212_quad_t),
+					 &csr->cache_head->data[bytes_to_quads(i)],
+					 csr->private);
+		if (ret != CSR1212_SUCCESS)
+			return ret;
+	}
+
+	if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)
+		return CSR1212_EINVAL;
+
+#if 0
+        /* Apparently there are too many differnt wrong implementations of the
+         * CRC algorithm that verifying them is moot. */
+	if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
+	    (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
+		return CSR1212_EINVAL;
+#endif
+
+	cr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region));
+	if (!cr)
+		return CSR1212_ENOMEM;
+
+	cr->next = NULL;
+	cr->prev = NULL;
+	cr->offset_start = 0;
+	cr->offset_end = csr->crc_len + 4;
+
+	csr->cache_head->filled_head = cr;
+	csr->cache_head->filled_tail = cr;
+
+	return CSR1212_SUCCESS;
+}
+
+static inline int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
+					  csr1212_quad_t ki,
+					  u_int32_t kv_pos,
+					  struct csr1212_csr_rom_cache *cache)
+{
+	int ret = CSR1212_SUCCESS;
+	struct csr1212_keyval *k = NULL;
+	u_int32_t offset;
+
+	switch(CSR1212_KV_KEY_TYPE(ki)) {
+	case CSR1212_KV_TYPE_IMMEDIATE:
+		k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
+					  CSR1212_KV_VAL(ki));
+		if (!k) {
+			ret = CSR1212_ENOMEM;
+			goto fail;
+		}
+		
+		k->refcnt = 0;	/* Don't keep local reference when parsing. */
+		break;
+
+	case CSR1212_KV_TYPE_CSR_OFFSET:
+		k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
+					   CSR1212_KV_VAL(ki));
+		if (!k) {
+			ret = CSR1212_ENOMEM;
+			goto fail;
+		}
+		k->refcnt = 0;	/* Don't keep local reference when parsing. */
+		break;
+
+	default:
+		/* Compute the offset from 0xffff f000 0000. */
+		offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
+		if (offset == kv_pos) {
+			/* Uh-oh.  Can't have a relative offset of 0 for Leaves
+			 * or Directories.  The Config ROM image is most likely
+			 * messed up, so we'll just abort here. */
+			ret = CSR1212_EIO;
+			goto fail;
+		}
+
+		k = csr1212_find_keyval_offset(cache->layout_head, offset);
+
+		if (k)
+			break;		/* Found it. */
+
+		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
+			k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
+		} else {
+			k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
+		}
+		if (!k) {
+			ret = CSR1212_ENOMEM;
+			goto fail;
+		}
+		k->refcnt = 0;	/* Don't keep local reference when parsing. */
+		k->valid = 0;	/* Contents not read yet so it's not valid. */
+		k->offset = offset;
+
+		k->prev = cache->layout_tail;
+		k->next = NULL;
+		if (cache->layout_tail)
+			cache->layout_tail->next = k;
+		cache->layout_tail = k;
+	}
+	ret = csr1212_attach_keyval_to_directory(dir, k);
+
+fail:
+	if (ret != CSR1212_SUCCESS) {
+		if (k)
+			free_keyval(k);
+	}
+	return ret;
+}
+
+int csr1212_parse_keyval(struct csr1212_keyval *kv,
+			 struct csr1212_csr_rom_cache *cache)
+{
+	struct csr1212_keyval_img *kvi;
+	int i;
+	int ret = CSR1212_SUCCESS;
+	int kvi_len;
+
+	kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
+								      cache->offset)];
+	kvi_len = CSR1212_BE16_TO_CPU(kvi->length);
+
+#if 0
+        /* Apparently there are too many differnt wrong implementations of the
+         * CRC algorithm that verifying them is moot. */
+	if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
+	    (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
+		ret = CSR1212_EINVAL;
+		goto fail;
+	}
+#endif
+
+	switch(kv->key.type) {
+	case CSR1212_KV_TYPE_DIRECTORY:
+		for (i = 0; i < kvi_len; i++) {
+			csr1212_quad_t ki = kvi->data[i];
+			ret = csr1212_parse_dir_entry(kv, ki,
+						      (kv->offset +
+						       quads_to_bytes(i + 1)),
+						      cache);
+		}
+		kv->value.directory.len = kvi_len;
+		break;
+
+	case CSR1212_KV_TYPE_LEAF:
+		if (kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
+			kv->value.leaf.data = cache->data;
+		} else {
+			kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
+			if (!kv->value.leaf.data)
+			{
+				ret = CSR1212_ENOMEM;
+				goto fail;
+			}
+
+			kv->value.leaf.len = kvi_len;
+			memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
+		}
+		break;
+	}
+
+	kv->valid = 1;
+
+fail:
+	return ret;
+}
+
+
+int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
+{
+	struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
+	struct csr1212_keyval_img *kvi = NULL;
+	struct csr1212_csr_rom_cache *cache;
+	int cache_index;
+	u_int64_t addr;
+	u_int32_t *cache_ptr;
+	u_int16_t kv_len = 0;
+
+
+	if (!csr || !kv)
+		return CSR1212_EINVAL;
+
+	/* First find which cache the data should be in (or go in if not read
+	 * yet). */
+	for (cache = csr->cache_head; cache; cache = cache->next) {
+		if (kv->offset >= cache->offset &&
+		    kv->offset < (cache->offset + cache->size))
+			break;
+	}
+
+	if (!cache) {
+		csr1212_quad_t q;
+		struct csr1212_csr_rom_cache *nc;
+
+		/* Only create a new cache for Extended ROM leaves. */
+		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
+			return CSR1212_EINVAL;
+
+		if (csr->ops->bus_read(csr,
+				       CSR1212_REGISTER_SPACE_BASE + kv->offset,
+				       sizeof(csr1212_quad_t), &q, csr->private)) {
+			return CSR1212_EIO;
+		}
+
+		kv->value.leaf.len = quads_to_bytes(CSR1212_BE32_TO_CPU(q)>>16);
+
+		nc = csr1212_rom_cache_malloc(kv->offset, kv->value.leaf.len);
+		cache->next = nc;
+		nc->prev = cache;
+		csr->cache_tail = nc;
+		cache->filled_head =
+			CSR1212_MALLOC(sizeof(struct csr1212_cache_region));
+		if (!cache->filled_head) {
+			return CSR1212_ENOMEM;
+		}
+
+		cache->filled_head->offset_start = 0;
+		cache->filled_head->offset_end = sizeof(csr1212_quad_t);
+		cache->filled_tail = cache->filled_head;
+		cache->filled_head->next = NULL;
+		cache->filled_head->prev = NULL;
+		cache->data[0] = q;
+	}
+
+	cache_index = kv->offset - cache->offset;
+
+	/* Now seach read portions of the cache to see if it is there. */
+	for (cr = cache->filled_head; cr; cr = cr->next) {
+		if (cache_index < cr->offset_start) {
+			newcr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region));
+			if (!newcr)
+				return CSR1212_ENOMEM;
+			
+			newcr->offset_start = cache_index & ~(csr->max_rom - 1);
+			newcr->offset_end = newcr->offset_start;
+			newcr->next = cr;
+			newcr->prev = cr->prev;
+			cr->prev = newcr;
+			cr = newcr;
+			break;
+		} else if ((cache_index >= cr->offset_start) &&
+			   (cache_index < cr->offset_end)) {
+			kvi = (struct csr1212_keyval_img*)
+				(&cache->data[bytes_to_quads(cache_index)]);
+			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
+						1);
+			break;
+		} else if (cache_index == cr->offset_end)
+			break;
+	}
+
+	if (!cr) {
+		cr = cache->filled_tail;
+		newcr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region));
+		if (!newcr)
+			return CSR1212_ENOMEM;
+			
+		newcr->offset_start = cache_index & ~(csr->max_rom - 1);
+		newcr->offset_end = newcr->offset_start;
+		newcr->prev = cr;
+		newcr->next = cr->next;
+		cr->next = newcr;
+		cr = newcr;
+		cache->filled_tail = newcr;
+	}
+
+	while(!kvi || cr->offset_end < cache_index + kv_len) {
+		cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
+							~(csr->max_rom - 1))];
+
+		addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
+			cr->offset_end) & ~(csr->max_rom - 1);
+
+		if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
+				       csr->private)) {
+			if (csr->max_rom == 4)
+				/* We've got problems! */
+				return CSR1212_EIO;
+
+			/* Apperently the max_rom value was a lie, set it to
+			 * do quadlet reads and try again. */
+			csr->max_rom = 4;
+			continue;
+		}
+
+		cr->offset_end += csr->max_rom - (cr->offset_end &
+						  (csr->max_rom - 1));
+
+		if (!kvi && (cr->offset_end > cache_index)) {
+			kvi = (struct csr1212_keyval_img*)
+				(&cache->data[bytes_to_quads(cache_index)]);
+			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
+						1);
+		}
+
+		if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
+			/* The Leaf or Directory claims its length extends
+			 * beyond the ConfigROM image region and thus beyond the
+			 * end of our cache region.  Therefore, we abort now
+			 * rather than seg faulting later. */
+			return CSR1212_EIO;
+		}
+
+		ncr = cr->next;
+
+		if (ncr && (cr->offset_end >= ncr->offset_start)) {
+			/* consolidate region entries */
+			ncr->offset_start = cr->offset_start;
+
+			if (cr->prev)
+				cr->prev->next = cr->next;
+			ncr->prev = cr->prev;
+			if (cache->filled_head == cr)
+				cache->filled_head = ncr;
+			CSR1212_FREE(cr);
+			cr = ncr;
+		}
+	}
+
+	return csr1212_parse_keyval(kv, cache);
+}
+
+
+
+int csr1212_parse_csr(struct csr1212_csr *csr)
+{
+	static const int mr_map[] = { 4, 64, 1024, 0 };
+	int ret;
+
+	if (!csr || !csr->ops->bus_read)
+		return CSR1212_EINVAL;
+
+	ret = csr1212_parse_bus_info_block(csr);
+	if (ret != CSR1212_SUCCESS)
+		return ret;
+
+	if (!csr->ops->get_max_rom)
+		csr->max_rom = mr_map[0];	/* default value */
+	else
+		csr->max_rom = mr_map[csr->ops->get_max_rom(csr->bus_info_data,
+							    csr->private)];
+
+	csr->cache_head->layout_head = csr->root_kv;
+	csr->cache_head->layout_tail = csr->root_kv;
+
+	csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
+		csr->bus_info_len;
+
+	csr->root_kv->valid = 0;
+	csr1212_get_keyval(csr, csr->root_kv);
+
+	return CSR1212_SUCCESS;
+}
--- diff/drivers/ieee1394/csr1212.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/ieee1394/csr1212.h	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,724 @@
+/*
+ * csr1212.h -- IEEE 1212 Control and Status Register support for Linux
+ * 
+ * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
+ *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *    3. The name of the author may not be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CSR1212_H__
+#define __CSR1212_H__
+
+
+/* Compatibility layer */
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#define CSR1212_MALLOC(size)		kmalloc((size), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+#define CSR1212_FREE(ptr)		kfree(ptr)
+#define CSR1212_BE16_TO_CPU(quad)	be16_to_cpu(quad)
+#define CSR1212_CPU_TO_BE16(quad)	cpu_to_be16(quad)
+#define CSR1212_BE32_TO_CPU(quad)	be32_to_cpu(quad)
+#define CSR1212_CPU_TO_BE32(quad)	cpu_to_be32(quad)
+#define CSR1212_BE64_TO_CPU(quad)	be64_to_cpu(quad)
+#define CSR1212_CPU_TO_BE64(quad)	cpu_to_be64(quad)
+
+#define CSR1212_LE16_TO_CPU(quad)	le16_to_cpu(quad)
+#define CSR1212_CPU_TO_LE16(quad)	cpu_to_le16(quad)
+#define CSR1212_LE32_TO_CPU(quad)	le32_to_cpu(quad)
+#define CSR1212_CPU_TO_LE32(quad)	cpu_to_le32(quad)
+#define CSR1212_LE64_TO_CPU(quad)	le64_to_cpu(quad)
+#define CSR1212_CPU_TO_LE64(quad)	cpu_to_le64(quad)
+
+#include <linux/errno.h>
+#define CSR1212_SUCCESS (0)
+#define CSR1212_EINVAL	(-EINVAL)
+#define CSR1212_ENOMEM	(-ENOMEM)
+#define CSR1212_ENOENT	(-ENOENT)
+#define CSR1212_EIO	(-EIO)
+#define CSR1212_EBUSY	(-EBUSY)
+
+#else	/* Userspace */
+
+#include <sys/types.h>
+#include <malloc.h>
+#define CSR1212_MALLOC(size)		malloc(size)
+#define CSR1212_FREE(ptr)		free(ptr)
+#include <endian.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#include <byteswap.h>
+#define CSR1212_BE16_TO_CPU(quad)	bswap_16(quad)
+#define CSR1212_CPU_TO_BE16(quad)	bswap_16(quad)
+#define CSR1212_BE32_TO_CPU(quad)	bswap_32(quad)
+#define CSR1212_CPU_TO_BE32(quad)	bswap_32(quad)
+#define CSR1212_BE64_TO_CPU(quad)	bswap_64(quad)
+#define CSR1212_CPU_TO_BE64(quad)	bswap_64(quad)
+
+#define CSR1212_LE16_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_LE16(quad)	(quad)
+#define CSR1212_LE32_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_LE32(quad)	(quad)
+#define CSR1212_LE64_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_LE64(quad)	(quad)
+#else
+#define CSR1212_BE16_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_BE16(quad)	(quad)
+#define CSR1212_BE32_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_BE32(quad)	(quad)
+#define CSR1212_BE64_TO_CPU(quad)	(quad)
+#define CSR1212_CPU_TO_BE64(quad)	(quad)
+
+#define CSR1212_LE16_TO_CPU(quad)	bswap_16(quad)
+#define CSR1212_CPU_TO_LE16(quad)	bswap_16(quad)
+#define CSR1212_LE32_TO_CPU(quad)	bswap_32(quad)
+#define CSR1212_CPU_TO_LE32(quad)	bswap_32(quad)
+#define CSR1212_LE64_TO_CPU(quad)	bswap_64(quad)
+#define CSR1212_CPU_TO_LE64(quad)	bswap_64(quad)
+#endif
+
+#include <errno.h>
+#define CSR1212_SUCCESS (0)
+#define CSR1212_EINVAL	(EINVAL)
+#define CSR1212_ENOMEM	(ENOMEM)
+#define CSR1212_ENOENT	(ENOENT)
+#define CSR1212_EIO	(EIO)
+#define CSR1212_EBUSY	(EBUSY)
+
+#endif
+
+
+#define CSR1212_KV_VAL_MASK			0xffffff
+#define CSR1212_KV_KEY_SHIFT			24
+#define CSR1212_KV_KEY_TYPE_SHIFT		6
+#define CSR1212_KV_KEY_ID_MASK			0x3f
+#define CSR1212_KV_KEY_TYPE_MASK		0x3		/* After shift */
+
+
+/* CSR 1212 key types */
+#define CSR1212_KV_TYPE_IMMEDIATE		0
+#define CSR1212_KV_TYPE_CSR_OFFSET		1
+#define CSR1212_KV_TYPE_LEAF			2
+#define CSR1212_KV_TYPE_DIRECTORY		3
+
+
+/* CSR 1212 key ids */
+#define CSR1212_KV_ID_DESCRIPTOR		0x01
+#define CSR1212_KV_ID_BUS_DEPENDENT_INFO	0x02
+#define CSR1212_KV_ID_VENDOR			0x03
+#define CSR1212_KV_ID_HARDWARE_VERSION		0x04
+#define CSR1212_KV_ID_MODULE			0x07
+#define CSR1212_KV_ID_NODE_CAPABILITIES		0x0C
+#define CSR1212_KV_ID_EUI_64			0x0D
+#define CSR1212_KV_ID_UNIT			0x11
+#define CSR1212_KV_ID_SPECIFIER_ID		0x12
+#define CSR1212_KV_ID_VERSION			0x13
+#define CSR1212_KV_ID_DEPENDENT_INFO		0x14
+#define CSR1212_KV_ID_UNIT_LOCATION		0x15
+#define CSR1212_KV_ID_MODEL			0x17
+#define CSR1212_KV_ID_INSTANCE			0x18
+#define CSR1212_KV_ID_KEYWORD			0x19
+#define CSR1212_KV_ID_FEATURE			0x1A
+#define CSR1212_KV_ID_EXTENDED_ROM		0x1B
+#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID	0x1C
+#define CSR1212_KV_ID_EXTENDED_KEY		0x1D
+#define CSR1212_KV_ID_EXTENDED_DATA		0x1E
+#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR	0x1F
+#define CSR1212_KV_ID_DIRECTORY_ID		0x20
+#define CSR1212_KV_ID_REVISION			0x21
+
+
+/* IEEE 1212 Address space map */
+#define CSR1212_ALL_SPACE_BASE			(0x000000000000ULL)
+#define CSR1212_ALL_SPACE_SIZE			(1ULL << 48)
+#define CSR1212_ALL_SPACE_END			(CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
+
+#define  CSR1212_MEMORY_SPACE_BASE		(0x000000000000ULL)
+#define  CSR1212_MEMORY_SPACE_SIZE		((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
+#define  CSR1212_MEMORY_SPACE_END		(CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
+
+#define  CSR1212_PRIVATE_SPACE_BASE		(0xffffe0000000ULL)
+#define  CSR1212_PRIVATE_SPACE_SIZE		(256ULL * (1ULL << 20))
+#define  CSR1212_PRIVATE_SPACE_END		(CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
+
+#define  CSR1212_REGISTER_SPACE_BASE		(0xfffff0000000ULL)
+#define  CSR1212_REGISTER_SPACE_SIZE		(256ULL * (1ULL << 20))
+#define  CSR1212_REGISTER_SPACE_END		(CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
+
+#define  CSR1212_CSR_ARCH_REG_SPACE_BASE	(0xfffff0000000ULL)
+#define  CSR1212_CSR_ARCH_REG_SPACE_SIZE	(512)
+#define  CSR1212_CSR_ARCH_REG_SPACE_END		(CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
+#define  CSR1212_CSR_ARCH_REG_SPACE_OFFSET	(CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
+
+#define  CSR1212_CSR_BUS_DEP_REG_SPACE_BASE	(0xfffff0000200ULL)
+#define  CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE	(512)
+#define  CSR1212_CSR_BUS_DEP_REG_SPACE_END	(CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
+#define  CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET	(CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
+
+#define  CSR1212_CONFIG_ROM_SPACE_BASE		(0xfffff0000400ULL)
+#define  CSR1212_CONFIG_ROM_SPACE_SIZE		(1024)
+#define  CSR1212_CONFIG_ROM_SPACE_END		(CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
+#define  CSR1212_CONFIG_ROM_SPACE_OFFSET	(CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
+
+#define  CSR1212_UNITS_SPACE_BASE		(0xfffff0000800ULL)
+#define  CSR1212_UNITS_SPACE_SIZE		((256ULL * (1ULL << 20)) - 2048)
+#define  CSR1212_UNITS_SPACE_END		(CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
+#define  CSR1212_UNITS_SPACE_OFFSET		(CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
+
+#define  CSR1212_EXTENDED_ROM_SIZE		(0x10000 * sizeof(u_int32_t))
+
+
+/* Config ROM image structures */
+struct csr1212_bus_info_block_img {
+	u_int8_t length;
+	u_int8_t crc_length;
+	u_int16_t crc;
+
+	/* Must be last */
+	u_int32_t data[0];	/* older gcc can't handle [] which is standard */
+};
+
+#define CSR1212_KV_KEY(quad)		(CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT)
+#define CSR1212_KV_KEY_TYPE(quad)	(CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT)
+#define CSR1212_KV_KEY_ID(quad)		(CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK)
+#define CSR1212_KV_VAL(quad)		(CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK)
+
+#define CSR1212_SET_KV_KEY(quad, key)	((quad) = \
+	CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT)))
+#define CSR1212_SET_KV_VAL(quad, val)	((quad) = \
+	CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val)))
+#define CSR1212_SET_KV_TYPEID(quad, type, id)	((quad) = \
+	CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \
+	(((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \
+	  ((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT)))
+
+typedef u_int32_t csr1212_quad_t;
+
+
+struct csr1212_keyval_img {
+	u_int16_t length;
+	u_int16_t crc;
+
+	/* Must be last */
+	csr1212_quad_t data[0];	/* older gcc can't handle [] which is standard */
+};
+
+struct csr1212_leaf {
+	int len;
+	u_int32_t *data;
+};
+
+struct csr1212_dentry {
+	struct csr1212_dentry *next, *prev;
+	struct csr1212_keyval *kv;
+};
+
+struct csr1212_directory {
+	int len;
+	struct csr1212_dentry *dentries_head, *dentries_tail;
+};
+
+struct csr1212_keyval {
+	struct {
+		u_int8_t type;
+		u_int8_t id;
+	} key;
+	union {
+		u_int32_t immediate;
+		u_int32_t csr_offset;
+		struct csr1212_leaf leaf;
+		struct csr1212_directory directory;
+	} value;
+	struct csr1212_keyval *associate;
+	int refcnt;
+
+	/* used in generating and/or parsing CSR image */
+	struct csr1212_keyval *next, *prev;	/* flat list of CSR elements */
+	u_int32_t offset;	/* position in CSR from 0xffff f000 0000 */
+	u_int8_t valid;		/* flag indicating keyval has valid data*/
+};
+
+
+struct csr1212_cache_region {
+	struct csr1212_cache_region *next, *prev;
+	u_int32_t offset_start;		/* inclusive */
+	u_int32_t offset_end;		/* exclusive */
+};
+
+struct csr1212_csr_rom_cache {
+	struct csr1212_csr_rom_cache *next, *prev;
+	struct csr1212_cache_region *filled_head, *filled_tail;
+	struct csr1212_keyval *layout_head, *layout_tail;
+	size_t size;
+	u_int32_t offset;
+	struct csr1212_keyval *ext_rom;
+	size_t len;
+
+	/* Must be last */
+	u_int32_t data[0];	/* older gcc can't handle [] which is standard */
+};
+
+struct csr1212_csr {
+	size_t bus_info_len;	/* bus info block length in bytes */
+	size_t crc_len;		/* crc length in bytes */
+	u_int32_t *bus_info_data;	/* bus info data incl bus name and EUI */
+
+	void *private;		/* private, bus specific data */
+	struct csr1212_bus_ops *ops;
+
+	struct csr1212_keyval *root_kv;
+
+	int max_rom;		/* max bytes readable in Config ROM region */
+
+	/* Items below used for image parsing and generation */
+	struct csr1212_csr_rom_cache *cache_head, *cache_tail;
+};
+
+struct csr1212_bus_ops {
+	/* This function is used by csr1212 to read additional information
+	 * from remote nodes when parsing a Config ROM (i.e., read Config ROM
+	 * entries located in the Units Space.  Must return 0 on success
+	 * anything else indicates an error. */
+	int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr,
+			 u_int16_t length, void *buffer, void *private);
+
+	/* This function is used by csr1212 to allocate a region in units space
+	 * in the event that Config ROM entries don't all fit in the predefined
+	 * 1K region.  The void *private parameter is private member of struct
+	 * csr1212_csr. */
+	u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment,
+					  void *private);
+
+
+	/* This function is used by csr1212 to release a region in units space
+	 * that is no longer needed. */
+	void (*release_addr) (u_int64_t addr, void *private);
+
+	/* This function is used by csr1212 to determine the max read request
+	 * supported by a remote node when reading the ConfigROM space.  Must
+	 * return 0, 1, or 2 per IEEE 1212.  */
+	int (*get_max_rom) (u_int32_t *bus_info, void *private);
+};
+
+
+
+
+/* Descriptor Leaf manipulation macros */
+#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
+#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
+#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+
+#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
+#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \
+	 CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
+#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
+	(&((kv)->value.leaf.data[1]))
+
+#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
+	((kv)->value.leaf.data[0] = \
+	 CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
+			     ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
+#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
+	((kv)->value.leaf.data[0] = \
+	 CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
+			      CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
+			     ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
+
+/* Text Descriptor Leaf manipulation macros */
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff  /* after shift */
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
+	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
+	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
+			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
+			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \
+	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
+	(&((kv)->value.leaf.data[2]))
+
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
+	((kv)->value.leaf.data[1] = \
+	 ((kv)->value.leaf.data[1] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
+				CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((width) & \
+			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
+			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
+	((kv)->value.leaf.data[1] = \
+	 ((kv)->value.leaf.data[1] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
+				CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((char_set) & \
+			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
+			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
+	((kv)->value.leaf.data[1] = \
+	 ((kv)->value.leaf.data[1] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
+	 CSR1212_CPU_TO_BE32(((language) & \
+			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
+
+
+/* Icon Descriptor Leaf manipulation macros */
+#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff
+#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30
+#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3 /* after shift */
+#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16
+#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf /* after shift */
+#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
+#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16
+#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff /* after shift */
+#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff
+#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \
+	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
+	  CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \
+	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \
+	  CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \
+	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \
+	 CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \
+	(&((kv)->value.leaf.data[5]))
+
+static inline u_int32_t *CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(struct csr1212_keyval *kv)
+{
+	static const int pd[4] = { 0, 4, 16, 256 };
+	static const int cs[16] = { 4, 2 };
+	int ps = pd[CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv)];
+	
+	return &kv->value.leaf.data[5 +
+				    (ps * cs[CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv)]) /
+			   sizeof(u_int32_t)];
+}
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \
+	((kv)->value.leaf.data[2] = \
+	 ((kv)->value.leaf.data[2] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \
+	 CSR1212_CPU_TO_BE32(((version) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \
+	((kv)->value.leaf.data[3] = \
+	 ((kv)->value.leaf.data[3] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \
+				CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((palette_depth) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \
+			     CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \
+	((kv)->value.leaf.data[3] = \
+	 ((kv)->value.leaf.data[3] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \
+				CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((color_space) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \
+			     CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
+	((kv)->value.leaf.data[3] = \
+	 ((kv)->value.leaf.data[3] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
+	 CSR1212_CPU_TO_BE32(((language) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \
+	((kv)->value.leaf.data[4] = \
+	 ((kv)->value.leaf.data[4] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \
+				CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((hscan) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \
+			     CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))
+
+#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \
+	((kv)->value.leaf.data[4] = \
+	 (((kv)->value.leaf.data[4] & \
+	  CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \
+	 CSR1212_CPU_TO_BE32(((vscan) & \
+			      CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)))
+
+
+/* Modifiable Descriptor Leaf manipulation macros */
+#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16
+#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff
+#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32
+#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff
+#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL
+
+#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \
+	CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT)
+
+#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \
+	(CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \
+			     CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \
+	 CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]))
+
+#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \
+	((kv)->value.leaf.data[0] = \
+	 ((kv)->value.leaf.data[0] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \
+				CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \
+	 CSR1212_CPU_TO_BE32(((size) & \
+			      CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \
+			     CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))
+
+#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \
+	((kv)->value.leaf.data[0] = \
+	 ((kv)->value.leaf.data[0] & \
+	  CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \
+	  CSR1212_CPU_TO_BE32(((addr) & \
+			       CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK)))
+
+#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \
+	((kv)->value.leaf.data[1] = \
+	 CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK))
+
+
+
+/* The following 2 function are for creating new Configuration ROM trees.  The
+ * first function is used for both creating local trees and parsing remote
+ * trees.  The second function adds pertinent information to local Configuration
+ * ROM trees - namely data for the bus information block. */
+extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
+					      size_t bus_info_size,
+					      void *private);
+extern void csr1212_init_local_csr(struct csr1212_csr *csr,
+				   const u_int32_t *bus_info_data, int max_rom);
+
+
+/* The following function destroys a Configuration ROM tree and release all
+ * memory taken by the tree. */
+extern void csr1212_destroy_csr(struct csr1212_csr *csr);
+
+
+/* The following set of functions are fore creating new keyvals for placement in
+ * a Configuration ROM tree.  Code that creates new keyvals with these functions
+ * must release those keyvals with csr1212_release_keyval() when they are no
+ * longer needed. */
+extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value);
+extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data,
+					       size_t data_len);
+extern struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key,
+						     u_int32_t csr_offset);
+extern struct csr1212_keyval *csr1212_new_directory(u_int8_t key);
+extern struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec,
+							     u_int32_t key,
+							     u_int32_t value);
+extern struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec,
+							u_int32_t key,
+							const void *data,
+							size_t data_len);
+extern struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype,
+							  u_int32_t specifier_id,
+							  const void *data,
+							  size_t data_len);
+extern struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
+								  u_int16_t cset,
+								  u_int16_t language,
+								  const void *data,
+								  size_t data_len);
+extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
+extern struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
+							       u_int8_t palette_depth,
+							       u_int8_t color_space,
+							       u_int16_t language,
+							       u_int16_t hscan,
+							       u_int16_t vscan,
+							       u_int32_t *palette,
+							       u_int32_t *pixels);
+extern struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
+								     u_int64_t address);
+extern struct csr1212_keyval *csr1212_new_keyword_leaf(int strc,
+						       const char *strv[]);
+
+
+/* The following functions manage association between keyvals.  Typically,
+ * Descriptor Leaves and Directories will be associated with another keyval and
+ * it is desirable for the Descriptor keyval to be place immediately after the
+ * keyval that it is associated with.*/
+extern int csr1212_associate_keyval(struct csr1212_keyval *kv,
+				    struct csr1212_keyval *associate);
+extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv);
+
+
+/* The following functions manage the association of a keyval and directories.
+ * A keyval may be attached to more than one directory. */
+extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
+					      struct csr1212_keyval *kv);
+extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
+						 struct csr1212_keyval *kv);
+
+
+/* The following functions create a Configuration ROM image from the tree of
+ * keyvals provided.  csr1212_generate_csr_image() creates a complete image in
+ * the list of caches available via csr->cache_head.  The other functions are
+ * provided should there be a need to create a flat image without restrictions
+ * placed by IEEE 1212. */
+extern struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
+							 struct csr1212_keyval *start_kv,
+							 int start_pos);
+extern size_t csr1212_generate_layout_order(struct csr1212_keyval *kv);
+extern void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache);
+extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
+
+
+/* This is a convience function for reading a block of data out of one of the
+ * caches in the csr->cache_head list. */
+extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer,
+			u_int32_t len);
+
+
+/* The following functions are in place for parsing Configuration ROM images.
+ * csr1212_parse_keyval() is used should there be a need to directly parse a
+ * Configuration ROM directly. */
+extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
+				struct csr1212_csr_rom_cache *cache);
+extern int csr1212_parse_csr(struct csr1212_csr *csr);
+
+/* These are internal functions referenced by inline functions below. */
+extern int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
+extern void _csr1212_destroy_keyval(struct csr1212_keyval *kv);
+
+
+/* This function allocates a new cache which may be used for either parsing or
+ * generating sub-sets of Configuration ROM images. */
+static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset,
+								     size_t size)
+{
+	struct csr1212_csr_rom_cache *cache;
+
+	cache = CSR1212_MALLOC(sizeof(struct csr1212_csr_rom_cache) + size);
+	if (!cache)
+		return NULL;
+
+	cache->next = NULL;
+	cache->prev = NULL;
+	cache->filled_head = NULL;
+	cache->filled_tail = NULL;
+	cache->layout_head = NULL;
+	cache->layout_tail = NULL;
+	cache->offset = offset;
+	cache->size = size;
+	cache->ext_rom = NULL;
+
+	return cache;
+}
+
+
+/* This function ensures that a keyval contains data when referencing a keyval
+ * created by parsing a Configuration ROM. */
+static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr,
+							struct csr1212_keyval *kv)
+{
+	if (!kv)
+		return NULL;
+	if (!kv->valid)
+		if (_csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
+			return NULL;
+	return kv;
+}
+
+
+/* This function increments the reference count for a keyval should there be a
+ * need for code to retain a keyval that has been parsed. */
+static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
+{
+	kv->refcnt++;
+}
+
+
+/* This function decrements a keyval's reference count and will destroy the
+ * keyval when there are no more users of the keyval.  This should be called by
+ * any code that calls csr1212_keep_keyval() or any of the keyval creation
+ * routines csr1212_new_*(). */
+static inline void csr1212_release_keyval(struct csr1212_keyval *kv)
+{
+	if (kv->refcnt > 1)
+		kv->refcnt--;
+	else
+		_csr1212_destroy_keyval(kv);
+}
+
+
+/*
+ * This macro allows for looping over the keyval entries in a directory and it
+ * ensures that keyvals from remote ConfigROMs are parsed properly.
+ *
+ * _csr is a struct csr1212_csr * that points to CSR associated with dir.
+ * _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index).
+ * _dir is a struct csr1212_keyval * that points to the directory to be looped.
+ * _pos is a struct csr1212_dentry * that is used internally for indexing.
+ * 
+ * kv will be NULL upon exit of the loop.
+ */
+#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos)			\
+	for (csr1212_get_keyval((_csr), (_dir)),				\
+	     _pos = (_dir)->value.directory.dentries_head,			\
+	     _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;	\
+	     (_kv) && (_pos);							\
+	     (_kv->associate == NULL) ?						\
+		     ((_pos = _pos->next), 					\
+		      (_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) :	\
+                          NULL)) :						\
+		     (_kv = csr1212_get_keyval((_csr), _kv->associate)))
+
+
+
+#endif /* __CSR1212_H__ */
--- diff/drivers/input/serio/gscps2.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/input/serio/gscps2.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,470 @@
+/*
+ * drivers/input/serio/gscps2.c
+ *
+ * Copyright (c) 2004 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
+ * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
+ *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
+ *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
+ *
+ * HP GSC PS/2 port driver, found in PA/RISC Workstations
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ * 
+ * TODO:
+ * - Dino testing (did HP ever shipped a machine on which this port
+ *                 was usable/enabled ?)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci_ids.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/parisc-device.h>
+
+MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>, Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP GSC PS/2 port driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
+
+#define PFX "gscps2.c: "
+
+/* 
+ * Driver constants
+ */
+
+/* various constants */
+#define ENABLE			1
+#define DISABLE			0
+
+#define GSC_DINO_OFFSET		0x0800	/* offset for DINO controller versus LASI one */
+
+/* PS/2 IO port offsets */
+#define GSC_ID			0x00	/* device ID offset (see: GSC_ID_XXX) */
+#define GSC_RESET		0x00	/* reset port offset */
+#define GSC_RCVDATA		0x04	/* receive port offset */
+#define GSC_XMTDATA		0x04	/* transmit port offset */
+#define GSC_CONTROL		0x08	/* see: Control register bits */
+#define GSC_STATUS		0x0C	/* see: Status register bits */
+
+/* Control register bits */
+#define GSC_CTRL_ENBL		0x01	/* enable interface */
+#define GSC_CTRL_LPBXR		0x02	/* loopback operation */
+#define GSC_CTRL_DIAG		0x20	/* directly control clock/data line */
+#define GSC_CTRL_DATDIR		0x40	/* data line direct control */
+#define GSC_CTRL_CLKDIR		0x80	/* clock line direct control */
+
+/* Status register bits */
+#define GSC_STAT_RBNE		0x01	/* Receive Buffer Not Empty */
+#define GSC_STAT_TBNE		0x02	/* Transmit Buffer Not Empty */
+#define GSC_STAT_TERR		0x04	/* Timeout Error */
+#define GSC_STAT_PERR		0x08	/* Parity Error */
+#define GSC_STAT_CMPINTR	0x10	/* Composite Interrupt = irq on any port */
+#define GSC_STAT_DATSHD		0x40	/* Data Line Shadow */
+#define GSC_STAT_CLKSHD		0x80	/* Clock Line Shadow */
+
+/* IDs returned by GSC_ID port register */
+#define GSC_ID_KEYBOARD		0	/* device ID values */
+#define GSC_ID_MOUSE		1
+
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
+
+#define BUFFER_SIZE 0x0f
+
+/* GSC PS/2 port device struct */
+struct gscps2port {
+	struct list_head node;
+	struct parisc_device *padev;
+	struct serio port;
+	spinlock_t lock;
+	char *addr;
+	u8 act, append; /* position in buffer[] */
+	struct {
+		u8 data;
+		u8 str;
+	} buffer[BUFFER_SIZE+1];
+	int id;
+	char name[32];
+};
+
+/*
+ * Various HW level routines
+ */
+
+#define gscps2_readb_input(x)		readb((x)+GSC_RCVDATA)
+#define gscps2_readb_control(x)		readb((x)+GSC_CONTROL)
+#define gscps2_readb_status(x)		readb((x)+GSC_STATUS)
+#define gscps2_writeb_control(x, y)	writeb((x), (y)+GSC_CONTROL)
+
+
+/*
+ * wait_TBE() - wait for Transmit Buffer Empty
+ */
+
+static int wait_TBE(char *addr)
+{
+	int timeout = 25000; /* device is expected to react within 250 msec */
+	while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
+		if (!--timeout)
+			return 0;	/* This should not happen */
+		udelay(10);
+	}
+	return 1;
+}
+
+
+/*
+ * gscps2_flush() - flush the receive buffer
+ */
+
+static void gscps2_flush(struct gscps2port *ps2port)
+{
+	while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+		gscps2_readb_input(ps2port->addr);
+	ps2port->act = ps2port->append = 0;
+}
+
+/*
+ * gscps2_writeb_output() - write a byte to the port
+ *
+ * returns 1 on sucess, 0 on error
+ */
+
+static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
+{
+	unsigned long flags;
+	char *addr = ps2port->addr;
+
+	if (!wait_TBE(addr)) {
+		printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data);
+		return 0;
+	}
+
+	while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+		/* wait */;
+
+	spin_lock_irqsave(&ps2port->lock, flags);
+	writeb(data, addr+GSC_XMTDATA);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	/* this is ugly, but due to timing of the port it seems to be necessary. */
+	mdelay(6);
+
+	/* make sure any received data is returned as fast as possible */
+	/* this is important e.g. when we set the LEDs on the keyboard */
+	gscps2_interrupt(0, NULL, NULL);
+
+	return 1;
+}
+
+
+/*
+ * gscps2_enable() - enables or disables the port
+ */
+
+static void gscps2_enable(struct gscps2port *ps2port, int enable)
+{
+	unsigned long flags;
+	u8 data;
+
+	/* now enable/disable the port */
+	spin_lock_irqsave(&ps2port->lock, flags);
+	gscps2_flush(ps2port);
+	data = gscps2_readb_control(ps2port->addr);
+	if (enable)
+		data |= GSC_CTRL_ENBL;
+	else
+		data &= ~GSC_CTRL_ENBL;
+	gscps2_writeb_control(data, ps2port->addr);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+	wait_TBE(ps2port->addr);
+	gscps2_flush(ps2port);
+}
+
+/*
+ * gscps2_reset() - resets the PS/2 port
+ */
+
+static void gscps2_reset(struct gscps2port *ps2port)
+{
+	char *addr = ps2port->addr;
+	unsigned long flags;
+
+	/* reset the interface */
+	spin_lock_irqsave(&ps2port->lock, flags);
+	gscps2_flush(ps2port);
+	writeb(0xff, addr+GSC_RESET);
+	gscps2_flush(ps2port);
+	spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	/* enable it */
+	gscps2_enable(ps2port, ENABLE);
+}
+
+static LIST_HEAD(ps2port_list);
+
+/**
+ * gscps2_interrupt() - Interruption service routine
+ *
+ * This function reads received PS/2 bytes and processes them on 
+ * all interfaces.
+ * The problematic part here is, that the keyboard and mouse PS/2 port
+ * share the same interrupt and it's not possible to send data if any
+ * one of them holds input data. To solve this problem we try to receive
+ * the data as fast as possible and handle the reporting to the upper layer
+ * later.
+ */
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	struct gscps2port *ps2port;
+
+	list_for_each_entry(ps2port, &ps2port_list, node) {
+
+	  unsigned long flags;
+	  spin_lock_irqsave(&ps2port->lock, flags);
+
+	  while ( (ps2port->buffer[ps2port->append].str = 
+		   gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) {
+		ps2port->buffer[ps2port->append].data = 
+				gscps2_readb_input(ps2port->addr);
+		ps2port->append = ((ps2port->append+1) & BUFFER_SIZE);
+	  }
+
+	  spin_unlock_irqrestore(&ps2port->lock, flags);
+
+	} /* list_for_each_entry */
+
+	/* all data was read from the ports - now report the data to upper layer */
+
+	list_for_each_entry(ps2port, &ps2port_list, node) {
+
+	  while (ps2port->act != ps2port->append) {
+
+	    unsigned int rxflags;
+	    u8 data, status;
+
+	    /* Did new data arrived while we read existing data ?
+	       If yes, exit now and let the new irq handler start over again */
+	    if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR)
+		return IRQ_HANDLED;
+
+	    status = ps2port->buffer[ps2port->act].str;
+	    data   = ps2port->buffer[ps2port->act].data;
+
+	    ps2port->act = ((ps2port->act+1) & BUFFER_SIZE);
+	    rxflags =	((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
+			((status & GSC_STAT_PERR) ? SERIO_PARITY  : 0 );
+
+	    serio_interrupt(&ps2port->port, data, rxflags, regs);
+
+	  } /* while() */
+
+	} /* list_for_each_entry */
+
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * gscps2_write() - send a byte out through the aux interface.
+ */
+
+static int gscps2_write(struct serio *port, unsigned char data)
+{
+	struct gscps2port *ps2port = port->driver;
+
+	if (!gscps2_writeb_output(ps2port, data)) {
+		printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * gscps2_open() is called when a port is opened by the higher layer.
+ * It resets and enables the port.
+ */
+
+static int gscps2_open(struct serio *port)
+{
+	struct gscps2port *ps2port = port->driver;
+
+	gscps2_reset(ps2port);
+
+	gscps2_interrupt(0, NULL, NULL);
+
+	return 0;
+}
+
+/*
+ * gscps2_close() disables the port
+ */
+
+static void gscps2_close(struct serio *port)
+{
+	struct gscps2port *ps2port = port->driver;
+	gscps2_enable(ps2port, DISABLE);
+}
+
+static struct serio gscps2_serio_port =
+{
+	.name =		"GSC PS/2",
+	.idbus =	BUS_GSC,
+	.idvendor =	PCI_VENDOR_ID_HP,
+	.idproduct =	0x0001,
+	.idversion =	0x0010,
+	.type =		SERIO_8042,
+	.write =	gscps2_write,
+	.open =		gscps2_open,
+	.close =	gscps2_close,
+};
+
+/**
+ * gscps2_probe() - Probes PS2 devices
+ * @return: success/error report
+ */
+
+static int __init gscps2_probe(struct parisc_device *dev)
+{
+        struct gscps2port *ps2port;
+	unsigned long hpa = dev->hpa;
+	int ret;
+
+	if (!dev->irq)
+		return -ENODEV;
+	
+	/* Offset for DINO PS/2. Works with LASI even */
+	if (dev->id.sversion == 0x96)
+		hpa += GSC_DINO_OFFSET;
+
+	ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL);
+	if (!ps2port)
+		return -ENOMEM;
+
+	dev_set_drvdata(&dev->dev, ps2port);
+
+	memset(ps2port, 0, sizeof(struct gscps2port));
+	ps2port->padev = dev;
+	ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
+	spin_lock_init(&ps2port->lock);
+
+	gscps2_reset(ps2port);
+	ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f;
+	snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s",
+		gscps2_serio_port.name, 
+		(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" );
+
+	memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port));
+	ps2port->port.driver = ps2port;
+	ps2port->port.name = ps2port->name;
+	ps2port->port.phys = dev->dev.bus_id;
+
+	list_add_tail(&ps2port->node, &ps2port_list);
+
+	ret = -EBUSY;
+	if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port))
+		goto fail_miserably;
+
+	if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) {
+		printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n",
+				hpa, ps2port->id);
+		ret = -ENODEV;
+		goto fail;
+	}
+
+#if 0
+	if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name))
+		goto fail;
+#endif
+
+	printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n",
+		ps2port->name,
+		ps2port->addr,
+		ps2port->padev->irq,
+		ps2port->port.phys);
+
+	serio_register_port(&ps2port->port);
+	
+	return 0;
+	
+fail:
+	free_irq(dev->irq, ps2port);
+
+fail_miserably:
+	list_del(&ps2port->node);
+	iounmap(ps2port->addr);
+	release_mem_region(dev->hpa, GSC_STATUS + 4);
+	kfree(ps2port);
+	return ret;
+}
+
+/**
+ * gscps2_remove() - Removes PS2 devices
+ * @return: success/error report
+ */
+
+static int __devexit gscps2_remove(struct parisc_device *dev)
+{
+	struct gscps2port *ps2port = dev_get_drvdata(&dev->dev);
+
+	serio_unregister_port(&ps2port->port);
+	free_irq(dev->irq, ps2port);
+	gscps2_flush(ps2port);
+	list_del(&ps2port->node);
+	iounmap(ps2port->addr);
+#if 0
+	release_mem_region(dev->hpa, GSC_STATUS + 4); 
+#endif
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(ps2port);
+	return 0;
+}
+
+
+static struct parisc_device_id gscps2_device_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */
+#ifdef DINO_TESTED
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ 
+#endif
+	{ 0, }	/* 0 terminated list */
+};
+
+static struct parisc_driver parisc_ps2_driver = {
+	.name		= "GSC PS/2",
+	.id_table	= gscps2_device_tbl,
+	.probe		= gscps2_probe,
+	.remove		= gscps2_remove,
+};
+
+static int __init gscps2_init(void)
+{
+	register_parisc_driver(&parisc_ps2_driver);
+	return 0;
+}
+
+static void __exit gscps2_exit(void)
+{
+	unregister_parisc_driver(&parisc_ps2_driver);
+}
+
+
+module_init(gscps2_init);
+module_exit(gscps2_exit);
+
--- diff/drivers/isdn/hisax/hfc_usb.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/isdn/hisax/hfc_usb.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,1667 @@
+/*
+ * hfc_usb.c
+ *
+ * modular HiSax ISDN driver for Colognechip HFC-USB chip
+ *
+ * Authors : Peter Sprenger  (sprenger@moving-byters.de)
+ *           Martin Bachem   (info@colognechip.com)
+ *           based on the first hfc_usb driver of Werner Cornelius (werner@isdn-development.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax.h"
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include "hisax_if.h"
+
+static const char *hfcusb_revision = "4.0";
+
+/*
+	to enable much mire debug messages in this driver, define
+			VERBOSE_USB_DEBUG and VERBOSE_ISDN_DEBUG
+	below
+*/
+
+#define VERBOSE_USB_DEBUG
+#define VERBOSE_ISDN_DEBUG
+
+#define INCLUDE_INLINE_FUNCS
+
+#define TRUE  1
+#define FALSE 0
+
+
+/***********/
+/* defines */
+/***********/
+#define HFC_CTRL_TIMEOUT	20  //(HZ * USB_CTRL_GET_TIMEOUT)
+/* 5ms timeout writing/reading regs */
+#define HFC_TIMER_T3     8000      /* timeout for l1 activation timer */
+#define HFC_TIMER_T4     500       /* time for state change interval */
+
+#define HFCUSB_L1_STATECHANGE   0  /* L1 state changed */
+#define HFCUSB_L1_DRX           1  /* D-frame received */
+#define HFCUSB_L1_ERX           2  /* E-frame received */
+#define HFCUSB_L1_DTX           4  /* D-frames completed */
+
+#define MAX_BCH_SIZE        2048   /* allowed B-channel packet size */
+
+#define HFCUSB_RX_THRESHOLD 64     /* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD 64     /* threshold for fifo report bit tx */
+
+#define HFCUSB_CHIP_ID    0x16     /* Chip ID register index */
+#define HFCUSB_CIRM       0x00     /* cirm register index */
+#define HFCUSB_USB_SIZE   0x07     /* int length register */
+#define HFCUSB_USB_SIZE_I 0x06     /* iso length register */
+#define HFCUSB_F_CROSS    0x0b     /* bit order register */
+#define HFCUSB_CLKDEL     0x37     /* bit delay register */
+#define HFCUSB_CON_HDLC   0xfa     /* channel connect register */
+#define HFCUSB_HDLC_PAR   0xfb
+#define HFCUSB_SCTRL      0x31     /* S-bus control register (tx) */
+#define HFCUSB_SCTRL_E    0x32     /* same for E and special funcs */
+#define HFCUSB_SCTRL_R    0x33     /* S-bus control register (rx) */
+#define HFCUSB_F_THRES    0x0c     /* threshold register */
+#define HFCUSB_FIFO       0x0f     /* fifo select register */
+#define HFCUSB_F_USAGE    0x1a     /* fifo usage register */
+#define HFCUSB_MST_MODE0  0x14
+#define HFCUSB_MST_MODE1  0x15
+#define HFCUSB_P_DATA     0x1f
+#define HFCUSB_INC_RES_F  0x0e
+#define HFCUSB_STATES     0x30
+
+#define HFCUSB_CHIPID 0x40         /* ID value of HFC-USB */
+
+/******************/
+/* fifo registers */
+/******************/
+#define HFCUSB_NUM_FIFOS   8       /* maximum number of fifos */
+#define HFCUSB_B1_TX       0       /* index for B1 transmit bulk/int */
+#define HFCUSB_B1_RX       1       /* index for B1 receive bulk/int */
+#define HFCUSB_B2_TX       2
+#define HFCUSB_B2_RX       3
+#define HFCUSB_D_TX        4
+#define HFCUSB_D_RX        5
+#define HFCUSB_PCM_TX      6
+#define HFCUSB_PCM_RX      7
+
+/*
+* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
+* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+*/
+#define USB_INT		0
+#define USB_BULK	1
+#define USB_ISOC	2
+
+#define ISOC_PACKETS_D	8
+#define ISOC_PACKETS_B	8
+#define ISO_BUFFER_SIZE	128
+
+// ISO send definitions
+#define SINK_MAX	68
+#define SINK_MIN	48
+#define SINK_DMIN	12
+#define SINK_DMAX	18
+#define BITLINE_INF	(-64*8)
+
+
+
+
+/**********/
+/* macros */
+/**********/
+#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
+#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
+
+/*************************************************/
+/* entry and size of output/input control buffer */
+/*************************************************/
+#define HFC_CTRL_BUFSIZE 32
+typedef struct
+{
+	__u8 hfc_reg;		/* register number */
+	__u8 reg_val;		/* value to be written (or read) */
+	int action;         /* data for action handler */
+
+} ctrl_buft;
+
+typedef struct
+{
+	int vendor;         // vendor id
+	int prod_id;	    // product id
+	char *vend_name;    // vendor string
+	__u8 led_scheme;    // led display scheme
+	__u8 led_invert;    // invert led aux port settings
+	__u8 led_bits[8];   // array of 8 possible LED bitmask settings
+
+} vendor_data;
+
+/***************************************************************/
+/* structure defining input+output fifos (interrupt/bulk mode) */
+/***************************************************************/
+
+struct usb_fifo;			/* forward definition */
+typedef struct iso_urb_struct
+{
+	struct urb *purb;
+	__u8 buffer[ISO_BUFFER_SIZE];	/* buffer incoming/outgoing data */
+	struct usb_fifo *owner_fifo;	// pointer to owner fifo
+} iso_urb_struct;
+
+
+struct hfcusb_data;			/* forward definition */
+typedef struct usb_fifo
+{
+	int fifonum;			/* fifo index attached to this structure */
+	int active;			/* fifo is currently active */
+	struct hfcusb_data *hfc;	/* pointer to main structure */
+	int pipe;			/* address of endpoint */
+	__u8 usb_packet_maxlen;		/* maximum length for usb transfer */
+	unsigned int max_size;		/* maximum size of receive/send packet */
+	__u8 intervall;			/* interrupt interval */
+	struct sk_buff *skbuff; 	/* actual used buffer */
+	struct urb *urb;		/* transfer structure for usb routines */
+	__u8 buffer[128];		/* buffer incoming/outgoing data */
+	int bit_line;			/* how much bits are in the fifo? */
+
+	volatile __u8 usb_transfer_mode;/* switched between ISO and INT */
+	iso_urb_struct iso[2];		/* need two urbs to have one always for pending */
+	struct hisax_if *hif;		/* hisax interface */
+	int delete_flg;			/* only delete skbuff once */
+	int last_urblen;		/* remember length of last packet */
+
+} usb_fifo;
+
+
+/*********************************************/
+/* structure holding all data for one device */
+/*********************************************/
+typedef struct hfcusb_data
+{
+	// HiSax Interface for loadable Layer1 drivers
+	struct hisax_d_if d_if;			/* see hisax_if.h */
+	struct hisax_b_if b_if[2];		/* see hisax_if.h */
+	int protocol;
+	
+	struct usb_device *dev;			/* our device */
+	int if_used;				/* used interface number */
+	int alt_used;				/* used alternate config */
+	int ctrl_paksize;			/* control pipe packet size */
+	int ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */
+	int cfg_used;				/* configuration index used */
+	int vend_idx;				// vendor found
+
+	int b_mode[2];				// B-channel mode
+
+	int l1_activated;			// layer 1 activated
+
+	int packet_size,iso_packet_size;	
+
+	/* control pipe background handling */
+	ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE];	/* buffer holding queued data */
+	volatile int ctrl_in_idx, ctrl_out_idx,
+		ctrl_cnt;			/* input/output pointer + count */
+	struct urb *ctrl_urb;			/* transfer structure for control channel */
+
+	struct usb_ctrlrequest ctrl_write;	/* buffer for control write request */
+	struct usb_ctrlrequest ctrl_read;	/* same for read request */
+
+	__u8 led_state,led_new_data,led_b_active;
+
+	volatile __u8 threshold_mask;		/* threshold actually reported */
+	volatile __u8 bch_enables;		/* or mask for sctrl_r and sctrl register values */
+
+	usb_fifo fifos[HFCUSB_NUM_FIFOS];	/* structure holding all fifo data */
+
+	volatile __u8 l1_state;			/* actual l1 state */
+	struct timer_list t3_timer;		/* timer 3 for activation/deactivation */
+	struct timer_list t4_timer;		/* timer 4 for activation/deactivation */
+	struct timer_list led_timer;		/* timer flashing leds */
+
+} hfcusb_data;
+
+
+static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish);
+
+
+
+/******************************************************/
+/* start next background transfer for control channel */
+/******************************************************/
+static void ctrl_start_transfer(hfcusb_data * hfc)
+{
+	int err;
+	if(hfc->ctrl_cnt)
+	{
+		hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
+		hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write;
+		hfc->ctrl_urb->transfer_buffer = NULL;
+		hfc->ctrl_urb->transfer_buffer_length = 0;
+		hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
+		hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
+		err = usb_submit_urb(hfc->ctrl_urb, GFP_KERNEL);	/* start transfer */
+		printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err);
+	}
+}				/* ctrl_start_transfer */
+
+/************************************/
+/* queue a control transfer request */
+/* return 0 on success.             */
+/************************************/
+static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action)
+{
+	ctrl_buft *buf;
+
+#ifdef VERBOSE_USB_DEBUG
+	printk ("HFC_USB: queue_control_request reg: %x, val: %x\n", reg, val);
+#endif
+
+	if(hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)  return(1);	   /* no space left */
+	buf = &hfc->ctrl_buff[hfc->ctrl_in_idx];	/* pointer to new index */
+	buf->hfc_reg = reg;
+	buf->reg_val = val;
+	buf->action=action;
+	if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
+		hfc->ctrl_in_idx = 0;	/* pointer wrap */
+	if (++hfc->ctrl_cnt == 1)
+		ctrl_start_transfer(hfc);
+	return(0);
+}		/* queue_control_request */
+
+
+static int control_action_handler(hfcusb_data *hfc,int reg,int val,int action)
+{
+	if(!action) return(1);  // no action defined
+
+	return(0);
+}
+
+
+/***************************************************************/
+/* control completion routine handling background control cmds */
+/***************************************************************/
+static void ctrl_complete(struct urb *urb, struct pt_regs *regs)
+{
+	hfcusb_data *hfc = (hfcusb_data *) urb->context;
+	ctrl_buft *buf;
+
+	printk(KERN_DEBUG "ctrl_complete cnt %d\n", hfc->ctrl_cnt);
+	urb->dev = hfc->dev;
+	if(hfc->ctrl_cnt)
+	{
+		buf=&hfc->ctrl_buff[hfc->ctrl_out_idx];
+		control_action_handler(hfc,buf->hfc_reg,buf->reg_val,buf->action);
+
+		hfc->ctrl_cnt--;	/* decrement actual count */
+		if(++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0;	/* pointer wrap */
+
+		ctrl_start_transfer(hfc);	/* start next transfer */
+	}
+}				/* ctrl_complete */
+
+
+
+#define LED_OFF      0   // no LED support
+#define LED_SCHEME1  1	 // LED standard scheme
+#define LED_SCHEME2  2	 // not used yet...
+
+#define LED_POWER_ON	1
+#define LED_POWER_OFF	2
+#define LED_S0_ON		3
+#define LED_S0_OFF		4
+#define LED_B1_ON		5
+#define LED_B1_OFF		6
+#define LED_B1_DATA		7
+#define LED_B2_ON		8
+#define LED_B2_OFF		9
+#define LED_B2_DATA	   10
+
+#define LED_NORMAL   0	 // LEDs are normal
+#define LED_INVERTED 1   // LEDs are inverted
+
+// time for LED flashing
+#define LED_TIME      250
+
+vendor_data vdata[]=
+{
+    {0x959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF,LED_NORMAL,{4,0,2,1}},     /* CologneChip Eval TA */
+	{0x7b0, 0x0007, "Billion tiny USB ISDN TA 128", LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Billion TA */
+	{0x742, 0x2008, "Stollmann USB TA",             LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Stollmann TA */
+	{0x8e3, 0x0301, "Olitec USB RNIS",              LED_SCHEME1,  LED_NORMAL,   {2,0,1,4}},           /* Olitec TA  */
+	{0x675, 0x1688, "DrayTec USB ISDN TA",          LED_SCHEME1,  LED_NORMAL,   {4,0,2,1}},           /* Draytec TA */
+	{0x7fa, 0x0846, "Bewan Modem RNIS USB",         LED_SCHEME1,  LED_INVERTED, {8,0x40,0x20,0x10}},  /* Bewan TA   */
+	{0,0,0}			   // EOL element
+};
+										
+/***************************************************/
+/* write led data to auxport & invert if necessary */
+/***************************************************/
+static void write_led(hfcusb_data * hfc,__u8 led_state)
+{
+	if(led_state!=hfc->led_state)
+	{
+		hfc->led_state=led_state;
+		queue_control_request(hfc, HFCUSB_P_DATA,(vdata[hfc->vend_idx].led_invert) ? ~led_state : led_state,1);
+	}
+}
+
+/******************************************/
+/* invert B-channel LEDs if data is sent  */
+/******************************************/
+static void led_timer(hfcusb_data * hfc)
+{
+   	static int cnt=0;
+	__u8 led_state=hfc->led_state;
+
+	if(cnt)
+	{
+		if(hfc->led_b_active&1) led_state|=vdata[hfc->vend_idx].led_bits[2];
+		if(hfc->led_b_active&2) led_state|=vdata[hfc->vend_idx].led_bits[3];
+	}
+	else
+	{
+		if(!(hfc->led_b_active&1) || hfc->led_new_data&1) led_state&=~vdata[hfc->vend_idx].led_bits[2];
+		if(!(hfc->led_b_active&2) || hfc->led_new_data&2) led_state&=~vdata[hfc->vend_idx].led_bits[3];
+	}
+
+	write_led(hfc,led_state);
+	hfc->led_new_data=0;
+
+	cnt=!cnt;
+	// restart 4 hz timer
+	hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
+	if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
+}
+
+/**************************/
+/* handle LED requests    */
+/**************************/
+static void handle_led(hfcusb_data * hfc,int event)
+{
+	__u8 led_state=hfc->led_state;
+
+	// if no scheme -> no LED action
+   	if(vdata[hfc->vend_idx].led_scheme==LED_OFF) return;
+
+	switch(event)
+	{
+		case LED_POWER_ON:
+				   led_state|=vdata[hfc->vend_idx].led_bits[0];
+				break;
+		case LED_POWER_OFF: // no Power off handling
+				break;
+		case LED_S0_ON:
+				   led_state|=vdata[hfc->vend_idx].led_bits[1];
+				break;
+		case LED_S0_OFF:
+				   led_state&=~vdata[hfc->vend_idx].led_bits[1];
+				break;
+		case LED_B1_ON:
+					hfc->led_b_active|=1;
+				break;
+		case LED_B1_OFF:
+					hfc->led_b_active&=~1;
+				break;
+		case LED_B1_DATA:
+				   hfc->led_new_data|=1;
+				break;
+		case LED_B2_ON:
+				   hfc->led_b_active|=2;
+				break;
+		case LED_B2_OFF:
+					hfc->led_b_active&=~2;
+				break;
+		case LED_B2_DATA:
+				   hfc->led_new_data|=2;
+				break;
+	}
+	
+	write_led(hfc,led_state);
+}
+
+/********************************/
+/* called when timer t3 expires */
+/********************************/
+static void l1_timer_expire_t3(hfcusb_data * hfc)
+{
+    //printk (KERN_INFO "HFC-USB: l1_timer_expire_t3\n");
+
+	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
+#ifdef VERBOSE_USB_DEBUG
+	printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
+#endif
+	hfc->l1_activated=FALSE;
+	handle_led(hfc,LED_S0_OFF);
+}
+
+/********************************/
+/* called when timer t4 expires */
+/********************************/
+static void l1_timer_expire_t4(hfcusb_data * hfc)
+{
+    //printk (KERN_INFO "HFC-USB: l1_timer_expire_t4\n");
+
+	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
+#ifdef VERBOSE_USB_DEBUG
+	printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
+#endif
+	hfc->l1_activated=FALSE;
+	handle_led(hfc,LED_S0_OFF);
+}
+
+/*****************************/
+/* handle S0 state changes   */
+/*****************************/
+static void state_handler(hfcusb_data * hfc,__u8 state)
+{
+	__u8 old_state;
+
+	old_state=hfc->l1_state;
+
+	// range check
+	if(state==old_state || state<1 || state>8) return;
+
+#ifdef VERBOSE_ISDN_DEBUG
+	printk(KERN_INFO "HFC-USB: new S0 state:%d old_state:%d\n",state,old_state);
+#endif
+
+	if(state<4 || state==7 || state==8)
+	{
+        if(timer_pending(&hfc->t3_timer)) del_timer(&hfc->t3_timer);
+		//printk(KERN_INFO "HFC-USB: T3 deactivated\n");
+	}
+
+	if(state>=7)
+	{
+        if(timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer);
+		//printk(KERN_INFO "HFC-USB: T4 deactivated\n");
+	}
+
+	if(state==7 && !hfc->l1_activated)
+	{
+		hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_ACTIVATE | INDICATION,NULL);
+		//printk(KERN_INFO "HFC-USB: PH_ACTIVATE | INDICATION sent\n");
+		hfc->l1_activated=TRUE;
+		handle_led(hfc,LED_S0_ON);
+	}
+	else
+	if(state<=3 /* && activated*/)
+	{
+		if(old_state==7 || old_state==8)
+		{
+			//printk(KERN_INFO "HFC-USB: T4 activated\n");
+			hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000;
+			if(!timer_pending(&hfc->t4_timer)) add_timer(&hfc->t4_timer);
+		}
+		else
+		{
+			hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
+			//printk(KERN_INFO "HFC-USB: PH_DEACTIVATE | INDICATION sent\n");
+			hfc->l1_activated=FALSE;
+			handle_led(hfc,LED_S0_OFF);
+		}
+	}
+
+	hfc->l1_state=state;
+}
+
+
+/* prepare iso urb */
+static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf,
+	int num_packets, int packet_size, int interval, usb_complete_t complete, void *context)
+{
+	int k;
+
+	spin_lock_init(&urb->lock);	// do we really need spin_lock_init ?
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->complete = complete;
+	urb->number_of_packets = num_packets;
+	urb->transfer_buffer_length = packet_size * num_packets;
+	urb->context = context;
+	urb->transfer_buffer = buf;
+	urb->transfer_flags = 0;
+	urb->transfer_flags = URB_ISO_ASAP;
+	urb->actual_length = 0;
+	urb->interval = interval;
+	for (k = 0; k < num_packets; k++) {
+		urb->iso_frame_desc[k].offset = packet_size * k;
+		urb->iso_frame_desc[k].length = packet_size;
+		urb->iso_frame_desc[k].actual_length = 0;
+	}
+}
+
+/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */
+static int start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,usb_complete_t complete,int packet_size)
+{
+	int i, k, errcode;
+
+#ifdef VERBOSE_USB_DEBUG
+	printk(KERN_INFO "HFC-USB: starting ISO-chain for Fifo %i\n",  fifo->fifonum);
+#endif
+
+
+	// allocate Memory for Iso out Urbs
+	for (i = 0; i < 2; i++) {
+		if (!(fifo->iso[i].purb)) {
+			fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
+			fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
+
+			// Init the first iso
+			if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb))
+			{
+
+				fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer,
+					num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall,
+					complete, &fifo->iso[i]);
+
+				memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer));
+
+				// defining packet delimeters in fifo->buffer
+				for(k = 0; k < num_packets_per_urb; k++)
+				{
+					fifo->iso[i].purb->iso_frame_desc[k].offset = k*packet_size;
+					fifo->iso[i].purb->iso_frame_desc[k].length = packet_size;
+				}
+			}
+		}
+
+		fifo->bit_line = BITLINE_INF;
+
+		errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
+		fifo->active = (errcode >= 0) ? 1 : 0;
+		if(errcode < 0)
+		{
+			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i.%i \n",  errcode, i);
+		};
+
+	}
+
+	// errcode = (usb_submit_urb(fifo->iso[0].purb, GFP_KERNEL));
+	return(fifo->active);
+}
+
+/* stops running iso chain and frees their pending urbs */
+static void stop_isoc_chain(usb_fifo * fifo)
+{
+	int i;
+
+	for(i = 0; i < 2; i++)
+	{
+		if(fifo->iso[i].purb)
+		{
+#ifdef VERBOSE_USB_DEBUG
+			printk(KERN_INFO "HFC-USB: Stopping iso chain for fifo %i.%i\n", fifo->fifonum, i);
+#endif
+			usb_unlink_urb(fifo->iso[i].purb);
+			usb_free_urb(fifo->iso[i].purb);
+			fifo->iso[i].purb = NULL;
+		}
+	}
+	if (fifo->urb) {
+		usb_unlink_urb(fifo->urb);
+		usb_free_urb(fifo->urb);
+		fifo->urb = NULL;
+	}
+	fifo->active = 0;
+}
+
+// defines how much ISO packets are handled in one URB
+static int iso_packets[8]={ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,
+	                       ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D};
+
+/*****************************************************/
+/* transmit completion routine for all ISO tx fifos */
+/*****************************************************/
+static void tx_iso_complete(struct urb *urb, struct pt_regs *regs)
+{
+	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+	usb_fifo *fifo = context_iso_urb->owner_fifo;
+	hfcusb_data *hfc = fifo->hfc;
+	int k, tx_offset, num_isoc_packets, sink, len, current_len,errcode,frame_complete,transp_mode,fifon;
+	__u8 threshbit;
+	__u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+
+	fifon=fifo->fifonum;
+	tx_offset=0;
+	// very weird error code when using ohci drivers, for now : ignore this error ...  (MB)
+	if(urb->status == -EOVERFLOW)
+	{
+		urb->status = 0;
+#ifdef VERBOSE_USB_DEBUG
+		printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",fifon);
+#endif
+	}
+
+	if(fifo->active && !urb->status)
+	{
+		transp_mode=0;
+		if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
+
+		threshbit = threshtable[fifon] & hfc->threshold_mask;	// is threshold set for our channel?
+		num_isoc_packets=iso_packets[fifon];
+
+		if(fifon >= HFCUSB_D_TX)
+		{
+			sink = (threshbit) ? SINK_DMIN : SINK_DMAX;	// how much bit go to the sink for D-channel?
+		}
+		else
+		{
+			sink = (threshbit) ? SINK_MIN : SINK_MAX;	// how much bit go to the sink for B-channel?
+		}
+
+		// prepare ISO Urb
+		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
+			fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context);
+		memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer));
+
+		frame_complete=FALSE;
+
+		// Generate Iso Packets
+		for(k = 0; k < num_isoc_packets; ++k)
+		{
+			if(fifo->skbuff)
+			{
+				len = fifo->skbuff->len;	// remaining length
+
+				fifo->bit_line -= sink;	// we lower data margin every msec
+				current_len = (0 - fifo->bit_line) / 8;
+				if(current_len > 14) current_len = 14;	// maximum 15 byte for every ISO packet makes our life easier
+				current_len = (len <= current_len) ? len : current_len;
+				fifo->bit_line += current_len * 8;	// how much bit do we put on the line?
+
+				context_iso_urb->buffer[tx_offset] = 0;
+				if(current_len == len)
+				{
+					if(!transp_mode)
+					{
+						context_iso_urb->buffer[tx_offset] = 1;	// here frame completion
+						fifo->bit_line += 32;	// add 2 byte flags and 16bit CRC at end of ISDN frame
+					}
+					frame_complete = TRUE;
+				}
+
+				// copy bytes from buffer into ISO_URB
+				memcpy(context_iso_urb->buffer+tx_offset+1,fifo->skbuff->data,current_len);
+				skb_pull(fifo->skbuff,current_len);
+
+				// define packet delimeters within the URB buffer
+				urb->iso_frame_desc[k].offset = tx_offset;
+				urb->iso_frame_desc[k].length = current_len + 1;
+
+				tx_offset += (current_len + 1);
+				// printk(KERN_INFO "HFC-USB: fifonum:%d,%d bytes to send, %d bytes ISO packet,bitline:%d,sink:%d,threshbit:%d,threshmask:%x\n",fifon,len,current_len,fifo->bit_line,sink,threshbit,hfc->threshold_mask);
+				if(!transp_mode)
+				{
+					if(fifon==HFCUSB_B1_TX) handle_led(hfc,LED_B1_DATA);
+					if(fifon==HFCUSB_B2_TX) handle_led(hfc,LED_B2_DATA);
+				}
+			}
+			else
+			{
+				// we have no more data - generate 1 byte ISO packets
+				urb->iso_frame_desc[k].offset = tx_offset++;
+
+				urb->iso_frame_desc[k].length = 1;
+				fifo->bit_line -= sink;	// we lower data margin every msec
+
+				if(fifo->bit_line < BITLINE_INF)
+				{
+					fifo->bit_line = BITLINE_INF;
+					//printk (KERN_INFO "HFC-USB: BITLINE_INF underrun\n");
+				}
+			}
+
+			if(frame_complete)
+			{
+				// delete the buffer only once, here or in hfc_usb_l2l1() in a PH_DATA|REQUEST
+				fifo->delete_flg=TRUE;
+
+				fifo->hif->l1l2(fifo->hif,PH_DATA|CONFIRM,(void*)fifo->skbuff->truesize);
+
+				if(fifo->skbuff && fifo->delete_flg)
+				{
+					dev_kfree_skb_any(fifo->skbuff);
+					//printk(KERN_INFO "HFC-USB: skbuff=NULL on fifo:%d\n",fifo->fifonum);
+					fifo->skbuff = NULL;
+					fifo->delete_flg=FALSE;
+				}
+
+				frame_complete=FALSE;
+			}
+        }
+
+		errcode = usb_submit_urb(urb, GFP_KERNEL);
+		if(errcode < 0)
+		{
+			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
+		}
+	}
+	else
+	{
+		if(urb->status)
+		{
+			printk(KERN_INFO "HFC-USB: tx_iso_complete : urb->status %i, fifonum %i\n",  urb->status,fifon);
+		}
+	}
+
+}				/* tx_iso_complete */
+
+/*****************************************************/
+/* receive completion routine for all ISO tx fifos   */
+/*****************************************************/
+static void rx_iso_complete(struct urb *urb, struct pt_regs *regs)
+{
+	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+	usb_fifo *fifo = context_iso_urb->owner_fifo;
+	hfcusb_data *hfc = fifo->hfc;
+	int k, len, errcode, offset, num_isoc_packets,fifon;
+	__u8 *buf;
+
+	fifon=fifo->fifonum;
+	// very weird error code when using ohci drivers, for now : ignore this error ...  (MB)
+	if(urb->status == -EOVERFLOW)
+	{
+		urb->status = 0;
+#ifdef VERBOSE_USB_DEBUG
+		printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",fifon);
+#endif
+	}
+
+	if(fifo->active && !urb->status)
+	{
+		num_isoc_packets=iso_packets[fifon];
+
+		// Generate D-Channel Iso Packets
+		for(k = 0; k < num_isoc_packets; ++k)
+		{
+			len=urb->iso_frame_desc[k].actual_length;
+			offset=urb->iso_frame_desc[k].offset;
+			buf=context_iso_urb->buffer+offset;
+
+			if(fifo->last_urblen!=fifo->usb_packet_maxlen)
+			{
+				// the threshold mask is in the 2nd status byte
+				hfc->threshold_mask=buf[1];
+				// the S0 state is in the upper half of the 1st status byte
+				state_handler(hfc,buf[0] >> 4);
+				// if we have more than the 2 status bytes -> collect data
+				if(len>2) collect_rx_frame(fifo,buf+2,len-2,buf[0]&1);
+			}
+			else collect_rx_frame(fifo,buf,len,0);
+
+			fifo->last_urblen=len;
+
+        }
+
+		// prepare ISO Urb
+		fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
+			fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context);
+
+		errcode = usb_submit_urb(urb, GFP_KERNEL);
+		if(errcode < 0)
+		{
+			printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n",  errcode);
+		}
+	}
+	else
+	{
+		if(urb->status)
+		{
+			printk(KERN_INFO "HFC-USB: rx_iso_complete : urb->status %i, fifonum %i\n",  urb->status,fifon);
+		}
+	}
+}				/* rx_iso_complete */
+
+
+/*****************************************************/
+/* collect data from interrupt or isochron in        */
+/*****************************************************/
+static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish)
+{
+	hfcusb_data *hfc = fifo->hfc;
+	int transp_mode,fifon;
+
+	fifon=fifo->fifonum;
+	transp_mode=0;
+	if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
+
+	//printk(KERN_INFO "HFC-USB: got %d bytes finish:%d max_size:%d fifo:%d\n",len,finish,fifo->max_size,fifon);
+	if(!fifo->skbuff)
+	{
+		// allocate sk buffer
+		fifo->skbuff=dev_alloc_skb(fifo->max_size + 3);
+		if(!fifo->skbuff)
+		{
+			printk(KERN_INFO "HFC-USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",fifon);
+			return;
+		}
+		
+	}
+
+	if(len && fifo->skbuff->len+len<fifo->max_size)
+	{
+		memcpy(skb_put(fifo->skbuff,len),data,len);
+	}
+	else printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d\n",fifo->max_size);
+
+	// give transparent data up, when 128 byte are available
+	if(transp_mode && fifo->skbuff->len>=128)
+	{
+		fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
+		fifo->skbuff = NULL;  // buffer was freed from upper layer
+		return;
+	}
+
+	// we have a complete hdlc packet
+	if(finish)
+	{
+		if(!fifo->skbuff->data[fifo->skbuff->len-1])
+		{
+			skb_trim(fifo->skbuff,fifo->skbuff->len-3);  // remove CRC & status
+
+			//printk(KERN_INFO "HFC-USB: got frame %d bytes on fifo:%d\n",fifo->skbuff->len,fifon);
+
+			if(fifon==HFCUSB_PCM_RX) fifo->hif->l1l2(fifo->hif,PH_DATA_E | INDICATION,fifo->skbuff);
+			else fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
+
+			fifo->skbuff = NULL;  // buffer was freed from upper layer
+		}
+		else
+		{
+			printk(KERN_INFO "HFC-USB: got frame %d bytes but CRC ERROR!!!\n",fifo->skbuff->len);
+
+			skb_trim(fifo->skbuff,0);  // clear whole buffer
+		}
+	}
+
+	// LED flashing only in HDLC mode
+	if(!transp_mode)
+	{
+		if(fifon==HFCUSB_B1_RX) handle_led(hfc,LED_B1_DATA);
+		if(fifon==HFCUSB_B2_RX) handle_led(hfc,LED_B2_DATA);
+	}
+}
+
+/***********************************************/
+/* receive completion routine for all rx fifos */
+/***********************************************/
+static void rx_complete(struct urb *urb, struct pt_regs *regs)
+{
+	int len;
+	__u8 *buf;
+	usb_fifo *fifo = (usb_fifo *) urb->context;	/* pointer to our fifo */
+	hfcusb_data *hfc = fifo->hfc;
+
+	urb->dev = hfc->dev;	/* security init */
+
+	if((!fifo->active) || (urb->status)) {
+#ifdef VERBOSE_USB_DEBUG
+		printk(KERN_INFO "HFC-USB: RX-Fifo %i is going down (%i)\n", fifo->fifonum, urb->status);
+#endif
+		fifo->urb->interval = 0;	/* cancel automatic rescheduling */
+		if(fifo->skbuff) {
+			dev_kfree_skb_any(fifo->skbuff);
+			fifo->skbuff = NULL;
+		}
+		return;
+	}
+
+	len=urb->actual_length;
+	buf=fifo->buffer;
+
+	if(fifo->last_urblen!=fifo->usb_packet_maxlen) {
+		// the threshold mask is in the 2nd status byte
+		hfc->threshold_mask=buf[1];
+		// the S0 state is in the upper half of the 1st status byte
+		state_handler(hfc,buf[0] >> 4);
+		// if we have more than the 2 status bytes -> collect data
+		if(len>2) collect_rx_frame(fifo,buf+2,urb->actual_length-2,buf[0]&1);
+	} else
+		collect_rx_frame(fifo,buf,urb->actual_length,0);
+
+	fifo->last_urblen=urb->actual_length;
+
+
+}	/* rx_complete */
+
+
+
+/***************************************************/
+/* start the interrupt transfer for the given fifo */
+/***************************************************/
+static void start_int_fifo(usb_fifo * fifo)
+{
+	int errcode;
+
+#ifdef VERBOSE_USB_DEBUG
+	printk(KERN_INFO "HFC-USB: starting intr IN fifo:%d\n", fifo->fifonum);
+#endif
+	if (!fifo->urb) {
+		fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!fifo->urb)
+			return;
+	}
+	usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer,
+				 fifo->usb_packet_maxlen, rx_complete, fifo, fifo->intervall);
+	fifo->active = 1;		/* must be marked active */
+	errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
+
+	if(errcode)
+	{
+		printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n",   errcode);
+		fifo->active = 0;
+		fifo->skbuff = NULL;
+	}
+} /* start_int_fifo */
+
+/*****************************/
+/* set the B-channel mode    */
+/*****************************/
+static void set_hfcmode(hfcusb_data *hfc,int channel,int mode)
+{
+	__u8 val,idx_table[2]={0,2};
+
+#ifdef VERBOSE_ISDN_DEBUG
+  printk (KERN_INFO "HFC-USB: setting channel %d to mode %d\n",channel,mode);
+#endif
+
+	hfc->b_mode[channel]=mode;
+
+	// setup CON_HDLC
+	val=0;
+	if(mode!=L1_MODE_NULL) val=8;    // enable fifo?
+	if(mode==L1_MODE_TRANS) val|=2;  // set transparent bit
+
+	queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel],1); // set FIFO to transmit register
+	queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
+	queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo
+
+	queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel]+1,1); // set FIFO to receive register
+	queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
+	queue_control_request(hfc,HFCUSB_INC_RES_F,2,1);  // reset fifo
+
+	val=0x40;
+	if(hfc->b_mode[0]) val|=1;
+	if(hfc->b_mode[1]) val|=2;
+	queue_control_request(hfc,HFCUSB_SCTRL,val,1);
+
+	val=0;
+	if(hfc->b_mode[0]) val|=1;
+	if(hfc->b_mode[1]) val|=2;
+	queue_control_request(hfc,HFCUSB_SCTRL_R,val,1);
+
+	if(mode==L1_MODE_NULL)
+	{
+		if(channel) handle_led(hfc,LED_B2_OFF);
+		else handle_led(hfc,LED_B1_OFF);
+	}
+	else
+	{
+		if(channel) handle_led(hfc,LED_B2_ON);
+		else handle_led(hfc,LED_B1_ON);
+	}
+}
+
+/*
+   --------------------------------------------------------------------------------------
+   from here : hisax_if callback routines :
+     - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) {
+
+   l1 to l2 routines :
+     - static void hfc_usb_l1l2(hfcusb_data * hfc)
+
+*/
+
+void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
+{
+    usb_fifo *fifo = my_hisax_if->priv;
+	hfcusb_data *hfc = fifo->hfc;
+
+    switch (pr) {
+		case PH_ACTIVATE | REQUEST:
+				if(fifo->fifonum==HFCUSB_D_TX)
+				{
+#ifdef VERBOSE_ISDN_DEBUG
+					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST\n");
+#endif
+					queue_control_request(hfc, HFCUSB_STATES,0x60,1);	/* make activation */
+					hfc->t3_timer.expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000;
+					if(!timer_pending(&hfc->t3_timer)) add_timer(&hfc->t3_timer);
+				}
+				else
+				{
+#ifdef VERBOSE_ISDN_DEBUG
+					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST\n");
+#endif
+					set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)arg);
+					fifo->hif->l1l2(fifo->hif,PH_ACTIVATE | INDICATION, NULL);
+				}
+                break;
+        case PH_DEACTIVATE | REQUEST:
+				if(fifo->fifonum==HFCUSB_D_TX)
+				{
+#ifdef VERBOSE_ISDN_DEBUG
+					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST\n");
+#endif
+					printk (KERN_INFO "HFC-USB: ISDN TE device should not deativate...\n");
+				}
+				else
+				{
+#ifdef VERBOSE_ISDN_DEBUG
+					printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST\n");
+#endif
+					set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)L1_MODE_NULL);
+					fifo->hif->l1l2(fifo->hif,PH_DEACTIVATE | INDICATION, NULL);
+				}
+                break;
+		case PH_DATA | REQUEST:
+				if(fifo->skbuff && fifo->delete_flg)
+				{
+					dev_kfree_skb_any(fifo->skbuff);
+					//printk(KERN_INFO "skbuff=NULL on fifo:%d\n",fifo->fifonum);
+					fifo->skbuff = NULL;
+					fifo->delete_flg=FALSE;
+				}
+
+				fifo->skbuff=arg; // we have a new buffer
+
+				//if(fifo->fifonum==HFCUSB_D_TX) printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DATA | REQUEST\n");
+				//else printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DATA | REQUEST\n");
+                break;
+        default:
+                printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n", pr);
+                break;
+    }
+}
+
+// valid configurations
+#define CNF_4INT3ISO  1      // 4 INT IN, 3 ISO OUT
+#define CNF_3INT3ISO  2      // 3 INT IN, 3 ISO OUT
+#define CNF_4ISO3ISO  3      // 4 ISO IN, 3 ISO OUT
+#define CNF_3ISO3ISO  4 	 // 3 ISO IN, 3 ISO OUT
+
+
+/*
+   --------------------------------------------------------------------------------------
+   From here on USB initialization and deactivation related routines are implemented :
+
+   - hfc_usb_init :
+      is the main Entry Point for the USB Subsystem when the device get plugged
+      in. This function calls usb_register with usb_driver as parameter.
+      Here, further entry points for probing (hfc_usb_probe) and disconnecting
+      the device (hfc_usb_disconnect) are published, as the id_table
+
+   - hfc_usb_probe
+      this function is called by the usb subsystem, and steps through the alternate
+      settings of the currently plugged in device to detect all Endpoints needed to
+      run an ISDN TA.
+      Needed EndPoints are
+      3 (+1) IntIn EndPoints   (D-in,  E-in, B1-in, B2-in, (E-in)) or
+      3 (+1) Isochron In Endpoints (D-out, B1-out, B2-out) and 3 IsoOut Endpoints
+      The currently used transfer mode of on the Out-Endpoints will be stored in
+      hfc->usb_transfer_mode and is either USB_INT or USB_ISO
+      When a valid alternate setting could be found, the usb_init (see blow)
+      function is called
+
+   - usb_init
+      Here, the HFC_USB Chip itself gets initialized and the USB framework to send/receive
+      Data to/from the several EndPoints are initialized:
+       The E- and D-Channel Int-In chain gets started
+       The IsoChain for the Iso-Out traffic get started
+
+   - hfc_usb_disconnect
+      this function is called by the usb subsystem and has to free all resources
+      and stop all usb traffic to allow a proper hotplugging disconnect.
+
+*/
+
+/***************************************************************************/
+/* usb_init is called once when a new matching device is detected to setup */
+/* main parameters. It registers the driver at the main hisax module.       */
+/* on success 0 is returned.                                               */
+/***************************************************************************/
+static int usb_init(hfcusb_data * hfc)
+{
+	usb_fifo *fifo;
+	int i, err;
+	u_char b;
+	struct hisax_b_if *p_b_if[2];
+	
+	/* check the chip id */
+	printk(KERN_INFO "HFCUSB_CHIP_ID begin\n");
+	if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
+		printk(KERN_INFO "HFC-USB: cannot read chip id\n");
+		return(1); 
+	}
+	printk(KERN_INFO "HFCUSB_CHIP_ID %x\n", b);
+	if (b != HFCUSB_CHIPID) {
+		printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b);
+		return(1);
+	}
+
+	/* first set the needed config, interface and alternate */
+	printk(KERN_INFO "usb_init 1\n");
+//	usb_set_configuration(hfc->dev, 1);
+	printk(KERN_INFO "usb_init 2\n");
+	err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
+	printk(KERN_INFO "usb_init usb_set_interface return %d\n", err);
+	/* now we initialize the chip */
+	write_usb(hfc, HFCUSB_CIRM, 8);	    // do reset
+	write_usb(hfc, HFCUSB_CIRM, 0x10);	// aux = output, reset off
+
+	// set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers
+	write_usb(hfc, HFCUSB_USB_SIZE,(hfc->packet_size/8) | ((hfc->packet_size/8) << 4));
+
+	// set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers
+	write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
+
+	/* enable PCM/GCI master mode */
+	write_usb(hfc, HFCUSB_MST_MODE1, 0);	/* set default values */
+	write_usb(hfc, HFCUSB_MST_MODE0, 1);	/* enable master mode */
+
+	/* init the fifos */
+	write_usb(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD/8) |((HFCUSB_RX_THRESHOLD/8) << 4));
+
+	fifo = hfc->fifos;
+	for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
+	{
+		write_usb(hfc, HFCUSB_FIFO, i);	/* select the desired fifo */
+		fifo[i].skbuff = NULL;	/* init buffer pointer */
+		fifo[i].max_size = (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
+		fifo[i].last_urblen=0;
+		write_usb(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2));	    // set 2 bit for D- & E-channel
+		write_usb(hfc, HFCUSB_CON_HDLC, ((i==HFCUSB_D_TX) ? 0x09 : 0x08));	// rx hdlc, enable IFF for D-channel
+		write_usb(hfc, HFCUSB_INC_RES_F, 2);	/* reset the fifo */
+	}
+
+	write_usb(hfc, HFCUSB_CLKDEL, 0x0f);	 /* clock delay value */
+	write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
+	write_usb(hfc, HFCUSB_STATES, 3);	     /* enable state machine */
+
+	write_usb(hfc, HFCUSB_SCTRL_R, 0);	     /* disable both B receivers */
+	write_usb(hfc, HFCUSB_SCTRL, 0x40);	     /* disable B transmitters + capacitive mode */
+
+	// set both B-channel to not connected
+	hfc->b_mode[0]=L1_MODE_NULL;
+	hfc->b_mode[1]=L1_MODE_NULL;
+
+	hfc->l1_activated=FALSE;
+	hfc->led_state=0;
+	hfc->led_new_data=0;
+
+	/* init the t3 timer */
+	init_timer(&hfc->t3_timer);
+	hfc->t3_timer.data = (long) hfc;
+	hfc->t3_timer.function = (void *) l1_timer_expire_t3;
+	/* init the t4 timer */
+	init_timer(&hfc->t4_timer);
+	hfc->t4_timer.data = (long) hfc;
+	hfc->t4_timer.function = (void *) l1_timer_expire_t4;
+	/* init the led timer */
+	init_timer(&hfc->led_timer);
+	hfc->led_timer.data = (long) hfc;
+	hfc->led_timer.function = (void *) led_timer;
+	// trigger 4 hz led timer
+	hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
+	if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
+
+	// init the background machinery for control requests
+	hfc->ctrl_read.bRequestType = 0xc0;
+	hfc->ctrl_read.bRequest = 1;
+	hfc->ctrl_read.wLength = 1;
+	hfc->ctrl_write.bRequestType = 0x40;
+	hfc->ctrl_write.bRequest = 0;
+	hfc->ctrl_write.wLength = 0;
+	usb_fill_control_urb(hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,(u_char *) & hfc->ctrl_write, NULL, 0, ctrl_complete, hfc);
+					
+	/* Init All Fifos */
+	for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
+	{
+		hfc->fifos[i].iso[0].purb = NULL;
+		hfc->fifos[i].iso[1].purb = NULL;
+		hfc->fifos[i].active = 0;
+	}
+
+	// register like Germaschewski :
+	hfc->d_if.owner = THIS_MODULE;
+	hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
+	hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
+
+	for (i=0; i<2; i++)
+	{
+		hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX+i*2];
+		hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
+		p_b_if[i] = &hfc->b_if[i];
+	}
+	
+	hfc->protocol = 2;  /* default EURO ISDN, should be a module_param */
+	hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
+	
+	for (i=0; i<4; i++)
+		hfc->fifos[i].hif=&p_b_if[i/2]->ifc;
+	for (i=4; i<8; i++)
+		hfc->fifos[i].hif=&hfc->d_if.ifc;
+
+	// 3 (+1) INT IN + 3 ISO OUT
+	if(hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO)
+	{
+		start_int_fifo(hfc->fifos + HFCUSB_D_RX);	// Int IN D-fifo
+		if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);	// E-fifo
+		start_int_fifo(hfc->fifos + HFCUSB_B1_RX);	// Int IN B1-fifo
+		start_int_fifo(hfc->fifos + HFCUSB_B2_RX);	// Int IN B2-fifo
+	}
+
+	// 3 (+1) ISO IN + 3 ISO OUT
+	if(hfc->cfg_used==CNF_3ISO3ISO || hfc->cfg_used==CNF_4ISO3ISO)
+	{
+		start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, rx_iso_complete,16);
+		if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, ISOC_PACKETS_D, rx_iso_complete,16);
+		start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, rx_iso_complete,16);
+		start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, rx_iso_complete,16);
+	}
+
+	start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, tx_iso_complete,1);
+	start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, tx_iso_complete,1);
+	start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, tx_iso_complete,1);
+
+	handle_led(hfc,LED_POWER_ON);
+
+	return(0);
+}	/* usb_init */
+
+
+/****************************************/
+/* data defining the devices to be used */
+/****************************************/
+// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {
+static struct usb_device_id hfc_usb_idtab[] = {
+	{USB_DEVICE(0x7b0, 0x0007)},	/* Billion USB TA 2 */
+	{USB_DEVICE(0x742, 0x2008)},	/* Stollmann USB TA */
+	{USB_DEVICE(0x959, 0x2bd0)},	/* Colognechip USB eval TA */
+	{USB_DEVICE(0x8e3, 0x0301)},	/* OliTec ISDN USB */
+	{USB_DEVICE(0x675, 0x1688)},	/* DrayTec ISDN USB */
+	{USB_DEVICE(0x7fa, 0x0846)},    /* Bewan ISDN USB TA */
+	{}				/* end with an all-zeroes entry */
+};
+
+MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)");
+MODULE_DESCRIPTION("HFC I4L USB driver");
+MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);
+MODULE_LICENSE("GPL");
+
+#define EP_NUL 1    // Endpoint at this position not allowed
+#define EP_NOP 2	// all type of endpoints allowed at this position
+#define EP_ISO 3	// Isochron endpoint mandatory at this position
+#define EP_BLK 4	// Bulk endpoint mandatory at this position
+#define EP_INT 5	// Interrupt endpoint mandatory at this position
+
+// this array represents all endpoints possible in the HCF-USB
+// the last 2 entries are the configuration number and the minimum interval for Interrupt endpoints
+int validconf[][18]=
+{
+	// INT in, ISO out config
+	{EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2},
+	{EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2},
+	// ISO in, ISO out config
+	{EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2},
+	{EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2},
+	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}       // EOL element
+};
+
+// string description of chosen config
+char *conf_str[]=
+{
+	"4 Interrupt IN + 3 Isochron OUT",
+	"3 Interrupt IN + 3 Isochron OUT",
+	"4 Isochron IN + 3 Isochron OUT",
+	"3 Isochron IN + 3 Isochron OUT"
+};
+
+
+/*************************************************/
+/* function called to probe a new plugged device */
+/*************************************************/
+static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev= interface_to_usbdev(intf);
+	hfcusb_data *context;
+	struct usb_host_interface *iface = intf->altsetting + intf->act_altsetting;
+	struct usb_host_endpoint *ep;
+	int i, idx, probe_alt_setting,vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
+	int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0;
+
+//        usb_show_device(dev);
+//	usb_show_device_descriptor(&dev->descriptor);
+//	usb_show_interface_descriptor(&iface->desc);
+	vend_idx=0xffff;
+	for(i=0;vdata[i].vendor;i++)
+	{
+		if(dev->descriptor.idVendor==vdata[i].vendor && dev->descriptor.idProduct==vdata[i].prod_id) vend_idx=i;
+	}
+	
+
+#ifdef VERBOSE_USB_DEBUG	
+	printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n",
+		intf->altsetting->desc.bInterfaceNumber, intf->act_altsetting, intf->minor);
+#endif
+
+	if (vend_idx != 0xffff) {
+#ifdef VERBOSE_USB_DEBUG
+		printk(KERN_INFO "HFC-USB: found vendor idx:%d  name:%s\n",vend_idx,vdata[vend_idx].vend_name);
+#endif
+		/* if vendor and product ID is OK, start probing a matching alternate setting ... */
+		probe_alt_setting = 0;
+		small_match=0xffff;
+		// default settings
+		iso_packet_size=16;
+		packet_size=64;
+
+		while(probe_alt_setting < intf->num_altsetting) {
+			iface = intf->altsetting + probe_alt_setting;
+			cfg_used=0;
+
+#ifdef VERBOSE_USB_DEBUG
+			printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting);
+#endif
+			// check for config EOL element
+			while (validconf[cfg_used][0]) {
+				cfg_found=TRUE;
+				vcf=validconf[cfg_used];
+				ep = iface->endpoint;	/* first endpoint descriptor */
+
+#ifdef VERBOSE_USB_DEBUG
+				printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n",
+					probe_alt_setting, intf->act_altsetting,cfg_used);
+#endif
+				// copy table
+				memcpy(cmptbl,vcf,16*sizeof(int));
+
+				// check for all endpoints in this alternate setting
+				for (i=0; i < iface->desc.bNumEndpoints; i++) {
+					ep_addr = ep->desc.bEndpointAddress;
+					idx = ((ep_addr & 0x7f)-1)*2;	/* get endpoint base */
+					if (ep_addr & 0x80)
+						idx++;
+					attr = ep->desc.bmAttributes;
+
+					if (cmptbl[idx] == EP_NUL) {
+						printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d  attr:%d  cmptbl[%d]:%d\n",
+							idx, attr, idx, cmptbl[idx]);
+						cfg_found = FALSE;
+					}
+
+					if (attr == USB_ENDPOINT_XFER_INT && cmptbl[idx] == EP_INT)
+						cmptbl[idx] = EP_NUL;
+					if (attr == USB_ENDPOINT_XFER_BULK && cmptbl[idx] == EP_BLK)
+						cmptbl[idx] = EP_NUL;
+					if (attr == USB_ENDPOINT_XFER_ISOC && cmptbl[idx] == EP_ISO)
+						cmptbl[idx] = EP_NUL;
+
+					// check if all INT endpoints match minimum interval
+					if (attr == USB_ENDPOINT_XFER_INT && ep->desc.bInterval < vcf[17]) {
+#ifdef VERBOSE_USB_DEBUG
+						if (cfg_found)
+							printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n",
+								vcf[17]);
+#endif
+						cfg_found = FALSE;
+					}
+
+					ep++;
+				}
+
+				for (i = 0; i < 16; i++) {
+					// printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[i]);
+
+					// all entries must be EP_NOP or EP_NUL for a valid config
+					if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
+						cfg_found = FALSE;
+				}
+
+				// we check for smallest match, to provide configuration priority
+				// configurations with smaller index have higher priority
+				if (cfg_found) {
+					if (cfg_used < small_match) {
+						small_match = cfg_used;
+						alt_used = probe_alt_setting;
+					}
+#ifdef VERBOSE_USB_DEBUG
+					printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);
+#endif
+				}
+
+				cfg_used++;
+			}
+
+			probe_alt_setting++;
+		}		/* (probe_alt_setting < intf->num_altsetting) */
+#ifdef VERBOSE_USB_DEBUG
+		printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);
+#endif
+		// yiipiee, we found a valid config
+		if (small_match != 0xffff) {
+			intf->act_altsetting = alt_used;
+			iface = intf->altsetting + intf->act_altsetting;
+
+			if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+				return(-ENOMEM);  /* got no mem */
+			memset(context, 0, sizeof(hfcusb_data));	/* clear the structure */
+
+			ep = iface->endpoint;	/* first endpoint descriptor */
+			vcf = validconf[small_match];
+
+			for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+				ep_addr = ep->desc.bEndpointAddress;
+				idx = ((ep_addr & 0x7f)-1)*2;	/* get endpoint base */
+				if (ep_addr & 0x80)
+					idx++;
+				cidx = idx & 7;
+				attr = ep->desc.bmAttributes;
+
+				// only initialize used endpoints
+				if (vcf[idx] != EP_NOP && vcf[idx] != EP_NUL) {
+					switch (attr) {
+						case USB_ENDPOINT_XFER_INT:
+							context->fifos[cidx].pipe = usb_rcvintpipe(dev, ep->desc.bEndpointAddress);
+							context->fifos[cidx].usb_transfer_mode = USB_INT;
+							packet_size = ep->desc.wMaxPacketSize; // remember max packet size
+#ifdef VERBOSE_USB_DEBUG
+							printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n",
+								ep->desc.bInterval, idx, cidx);
+#endif
+							break;
+						case USB_ENDPOINT_XFER_BULK:
+							if (ep_addr & 0x80)
+								context->fifos[cidx].pipe = usb_rcvbulkpipe(dev, ep->desc.bEndpointAddress);
+							else
+								context->fifos[cidx].pipe = usb_sndbulkpipe(dev, ep->desc.bEndpointAddress);
+							context->fifos[cidx].usb_transfer_mode = USB_BULK;
+							packet_size = ep->desc.wMaxPacketSize; // remember max packet size
+#ifdef VERBOSE_USB_DEBUG
+							printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n",
+								idx, cidx);
+#endif
+							break;
+						case USB_ENDPOINT_XFER_ISOC:
+							if (ep_addr & 0x80)
+								context->fifos[cidx].pipe = usb_rcvisocpipe(dev, ep->desc.bEndpointAddress);
+							else
+								context->fifos[cidx].pipe = usb_sndisocpipe(dev, ep->desc.bEndpointAddress);
+							context->fifos[cidx].usb_transfer_mode = USB_ISOC;
+							iso_packet_size = ep->desc.wMaxPacketSize; // remember max packet size
+#ifdef VERBOSE_USB_DEBUG
+							printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n",
+								idx, cidx);
+#endif
+							break;
+						default:
+							context->fifos[cidx].pipe = 0;	/* reset data */
+					}	/* switch attribute */
+
+					if (context->fifos[cidx].pipe) {
+						context->fifos[cidx].fifonum = cidx;
+						context->fifos[cidx].hfc = context;
+						context->fifos[cidx].usb_packet_maxlen = ep->desc.wMaxPacketSize;
+						context->fifos[cidx].intervall = ep->desc.bInterval;
+						context->fifos[cidx].skbuff = NULL;
+#ifdef VERBOSE_USB_DEBUG
+						printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n",
+							context->fifos[cidx].fifonum,
+							context->fifos[cidx].usb_packet_maxlen,
+							context->fifos[cidx].intervall);
+#endif
+					}
+				}
+
+				ep++;
+			}
+
+			// now share our luck
+			context->dev = dev;						/* save device */
+			context->if_used = intf->altsetting->desc.bInterfaceNumber;	/* save used interface */
+			context->alt_used = intf->act_altsetting;			/* and alternate config */
+			context->ctrl_paksize = dev->descriptor.bMaxPacketSize0;	/* control size */
+			context->cfg_used=vcf[16];					// store used config
+			context->vend_idx=vend_idx;					// store found vendor
+			context->packet_size=packet_size;
+			context->iso_packet_size=iso_packet_size;
+
+			/* create the control pipes needed for register access */
+			context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0);
+			context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0);
+			context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+			printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n",
+				vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used);
+
+			/* init the chip and register the driver */
+			if (usb_init(context))
+			{
+				if (context->ctrl_urb) {
+					usb_unlink_urb(context->ctrl_urb);
+					usb_free_urb(context->ctrl_urb);
+					context->ctrl_urb = NULL;
+				}
+				kfree(context);
+				return(-EIO);
+			}
+			usb_set_intfdata(intf, context);
+			return(0);
+		} 
+	}
+	return(-EIO);
+}
+
+/****************************************************/
+/* function called when an active device is removed */
+/****************************************************/
+static void hfc_usb_disconnect(struct usb_interface *intf)
+{
+	hfcusb_data *context = usb_get_intfdata(intf);
+	int i;
+
+	printk(KERN_INFO "HFC-USB: device disconnect\n");
+	
+	usb_set_intfdata(intf, NULL);
+	if (!context)
+		return;
+	if (timer_pending(&context->t3_timer))
+		del_timer(&context->t3_timer);
+	if (timer_pending(&context->t4_timer))
+		del_timer(&context->t4_timer);
+	if (timer_pending(&context->led_timer))
+		del_timer(&context->led_timer);
+
+	hisax_unregister(&context->d_if);
+
+	/* tell all fifos to terminate */
+	for(i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+		if(context->fifos[i].usb_transfer_mode == USB_ISOC) {
+			if(context->fifos[i].active > 0) {
+	    			stop_isoc_chain(&context->fifos[i]);
+#ifdef VERBOSE_USB_DEBUG
+		    		printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i);
+#endif
+ 			}
+		} else {
+			if(context->fifos[i].active > 0) {
+				context->fifos[i].active = 0;
+#ifdef VERBOSE_USB_DEBUG
+				printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i);
+#endif
+			}
+			if (context->fifos[i].urb) {
+				usb_unlink_urb(context->fifos[i].urb);
+				usb_free_urb(context->fifos[i].urb);
+				context->fifos[i].urb = NULL;
+			}
+		}
+		context->fifos[i].active = 0;
+	}
+	if (context->ctrl_urb) {
+		usb_unlink_urb(context->ctrl_urb);
+		usb_free_urb(context->ctrl_urb);
+		context->ctrl_urb = NULL;
+	}
+	kfree(context);		/* free our structure again */
+}				/* hfc_usb_disconnect */
+
+
+/************************************/
+/* our driver information structure */
+/************************************/
+static struct usb_driver hfc_drv = {
+	.owner =	THIS_MODULE,
+	.name =		"hfc_usb",
+	.id_table = 	hfc_usb_idtab,
+	.probe =	hfc_usb_probe,
+	.disconnect =	hfc_usb_disconnect,
+};
+
+static void __exit hfc_usb_exit(void)
+{
+#ifdef VERBOSE_USB_DEBUG
+	printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n");
+#endif
+	usb_deregister(&hfc_drv);	/* release our driver */
+	printk(KERN_INFO "HFC-USB module removed\n");
+}
+
+static int __init hfc_usb_init(void)
+{
+	printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision);
+
+	if(usb_register(&hfc_drv))
+	{
+		printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n");
+		return(-1);		   /* unable to register */
+	}
+	return(0);
+}
+
+module_init(hfc_usb_init);
+module_exit(hfc_usb_exit);
--- diff/drivers/isdn/hisax/hisax_cfg.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_cfg.h	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,64 @@
+/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $
+ * define of the basic HiSax configuration structures
+ * and pcmcia interface
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#define ISDN_CTYPE_16_0			1
+#define ISDN_CTYPE_8_0			2
+#define ISDN_CTYPE_16_3			3
+#define ISDN_CTYPE_PNP			4
+#define ISDN_CTYPE_A1			5
+#define ISDN_CTYPE_ELSA			6
+#define ISDN_CTYPE_ELSA_PNP		7
+#define ISDN_CTYPE_TELESPCMCIA		8
+#define ISDN_CTYPE_IX1MICROR2		9
+#define ISDN_CTYPE_ELSA_PCMCIA		10
+#define ISDN_CTYPE_DIEHLDIVA		11
+#define ISDN_CTYPE_ASUSCOM		12
+#define ISDN_CTYPE_TELEINT		13
+#define ISDN_CTYPE_TELES3C		14
+#define ISDN_CTYPE_SEDLBAUER		15
+#define ISDN_CTYPE_SPORTSTER		16
+#define ISDN_CTYPE_MIC			17
+#define ISDN_CTYPE_ELSA_PCI		18
+#define ISDN_CTYPE_COMPAQ_ISA		19
+#define ISDN_CTYPE_NETJET_S		20
+#define ISDN_CTYPE_TELESPCI		21
+#define ISDN_CTYPE_SEDLBAUER_PCMCIA	22
+#define ISDN_CTYPE_AMD7930		23
+#define ISDN_CTYPE_NICCY		24
+#define ISDN_CTYPE_S0BOX		25
+#define ISDN_CTYPE_A1_PCMCIA		26
+#define ISDN_CTYPE_FRITZPCI		27
+#define ISDN_CTYPE_SEDLBAUER_FAX	28
+#define ISDN_CTYPE_ISURF		29
+#define ISDN_CTYPE_ACERP10		30
+#define ISDN_CTYPE_HSTSAPHIR		31
+#define	ISDN_CTYPE_BKM_A4T		32
+#define	ISDN_CTYPE_SCT_QUADRO		33
+#define ISDN_CTYPE_GAZEL		34
+#define ISDN_CTYPE_HFC_PCI		35
+#define ISDN_CTYPE_W6692		36
+#define ISDN_CTYPE_HFC_SX		37
+#define ISDN_CTYPE_NETJET_U		38
+#define ISDN_CTYPE_HFC_SP_PCMCIA	39
+#define ISDN_CTYPE_DYNAMIC		40
+#define ISDN_CTYPE_ENTERNOW		41
+#define ISDN_CTYPE_COUNT		41
+
+typedef struct IsdnCardState	IsdnCardState_t;
+typedef struct IsdnCard		IsdnCard_t;
+
+struct IsdnCard {
+	int		typ;
+	int 		protocol;	/* EDSS1, 1TR6 or NI1 */
+	unsigned long	para[4];
+	IsdnCardState_t	*cs;
+};
+
+extern void	HiSax_closecard(int);
+extern int	hisax_init_pcmcia(void *, int *, IsdnCard_t *);
--- diff/drivers/isdn/hisax/isdnhdlc.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/isdn/hisax/isdnhdlc.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,669 @@
+/*
+ * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
+ *
+ *Copyright (C) 2002	Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include "isdnhdlc.h"
+
+/*-------------------------------------------------------------------*/
+
+MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
+	      "Frode Isaksen <fisaksen@bewan.com>, "
+	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
+MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------*/
+
+/* bit swap table.
+ * Very handy for devices with different bit order,
+ * and neccessary for each transparent B-channel access for all
+ * devices which works with this HDLC decoder without bit reversal.
+ */
+const unsigned char isdnhdlc_bit_rev_tab[256] = {
+	0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+	0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+	0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+	0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+	0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+	0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+	0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+	0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+	0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+	0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+	0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+	0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+	0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+	0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+	0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+	0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+};
+
+/* Table for CRC16. Internal used only. */
+static const unsigned short int crc16_tab[] = {
+	0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
+	0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
+	0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
+	0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
+	0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
+	0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
+	0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
+	0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
+	0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
+	0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
+	0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
+	0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
+	0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
+	0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
+	0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
+	0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
+	0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
+	0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
+	0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
+	0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
+	0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
+	0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
+	0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
+	0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
+	0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
+	0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
+	0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
+	0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
+	0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
+	0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
+	0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
+	0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
+};
+
+
+enum {
+	HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
+	HDLC_GET_DATA,HDLC_FAST_FLAG
+};
+
+enum {
+	HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
+	HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
+	HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
+	HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+};
+
+void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->state = HDLC_GET_DATA;
+	hdlc->do_adapt56 = do_adapt56;
+	hdlc->dchannel = 0;
+	hdlc->crc = 0;
+	hdlc->cbin = 0;
+	hdlc->shift_reg = 0;
+	hdlc->ffvalue = 0;
+	hdlc->dstpos = 0;
+}
+
+void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->do_closing = 0;
+	hdlc->ffvalue = 0;
+	if (is_d_channel) {
+		hdlc->dchannel = 1;
+		hdlc->state = HDLC_SEND_FIRST_FLAG;
+	} else {
+		hdlc->dchannel = 0;
+		hdlc->state = HDLC_SEND_FAST_FLAG;
+		hdlc->ffvalue = 0x7e;
+	}
+	hdlc->cbin = 0x7e;
+	hdlc->bit_shift = 0;
+	if(do_adapt56){
+		hdlc->do_adapt56 = 1;
+		hdlc->data_bits = 0;
+		hdlc->state = HDLC_SENDFLAG_B0;
+	} else {
+		hdlc->do_adapt56 = 0;
+		hdlc->data_bits = 8;
+	}
+	hdlc->shift_reg = 0;
+}
+
+/*
+  isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
+
+  The source buffer is scanned for valid HDLC frames looking for
+  flags (01111110) to indicate the start of a frame. If the start of
+  the frame is found, the bit stuffing is removed (0 after 5 1's).
+  When a new flag is found, the complete frame has been received
+  and the CRC is checked.
+  If a valid frame is found, the function returns the frame length
+  excluding the CRC with the bit HDLC_END_OF_FRAME set.
+  If the beginning of a valid frame is found, the function returns
+  the length.
+  If a framing error is found (too many 1s and not a flag) the function
+  returns the length with the bit HDLC_FRAMING_ERROR set.
+  If a CRC error is found the function returns the length with the
+  bit HDLC_CRC_ERROR set.
+  If the frame length exceeds the destination buffer size, the function
+  returns the length with the bit HDLC_LENGTH_ERROR set.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (decoded) from the source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of decoded bytes in the destination buffer and status
+  flag.
+ */
+int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		     int slen, int *count, unsigned char *dst, int dsize)
+{
+	int status=0;
+
+	static const unsigned char fast_flag[]={
+		0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+	};
+
+	static const unsigned char fast_flag_value[]={
+		0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+	};
+
+	static const unsigned char fast_abort[]={
+		0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+	};
+
+	*count = slen;
+
+	while(slen > 0){
+		if(hdlc->bit_shift==0){
+			hdlc->cbin = *src++;
+			slen--;
+			hdlc->bit_shift = 8;
+			if(hdlc->do_adapt56){
+				hdlc->bit_shift --;
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			return 0;
+		case HDLC_FAST_IDLE:
+			if(hdlc->cbin == 0xff){
+				hdlc->bit_shift = 0;
+				break;
+			}
+			hdlc->state = HDLC_GET_FLAG_B0;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->bit_shift = 8;
+			break;
+		case HDLC_GET_FLAG_B0:
+			if(!(hdlc->cbin & 0x80)) {
+				hdlc->state = HDLC_GETFLAG_B1A6;
+				hdlc->hdlc_bits1 = 0;
+			} else {
+				if(!hdlc->do_adapt56){
+					if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+						hdlc->state = HDLC_FAST_IDLE;
+				}
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B1A6:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				if(hdlc->hdlc_bits1==6){
+					hdlc->state = HDLC_GETFLAG_B7;
+				}
+			} else {
+				hdlc->hdlc_bits1 = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B7:
+			if(hdlc->cbin & 0x80) {
+				hdlc->state = HDLC_GET_FLAG_B0;
+			} else {
+				hdlc->state = HDLC_GET_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->shift_reg = 0;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_bits = 0;
+				hdlc->data_received = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GET_DATA:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				switch(hdlc->hdlc_bits1){
+				case 6:
+					break;
+				case 7:
+					if(hdlc->data_received) {
+						// bad frame
+						status = -HDLC_FRAMING_ERROR;
+					}
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
+							hdlc->state = HDLC_FAST_IDLE;
+							hdlc->bit_shift=1;
+							break;
+						}
+					} else {
+						hdlc->state = HDLC_GET_FLAG_B0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->shift_reg |= 0x80;
+					hdlc->data_bits++;
+					break;
+				}
+			} else {
+				switch(hdlc->hdlc_bits1){
+				case 5:
+					break;
+				case 6:
+					if(hdlc->data_received){
+						if (hdlc->dstpos < 2) {
+							status = -HDLC_FRAMING_ERROR;
+						} else if (hdlc->crc != 0xf0b8){
+							// crc error
+							status = -HDLC_CRC_ERROR;
+						} else {
+							// remove CRC
+							hdlc->dstpos -= 2;
+							// good frame
+							status = hdlc->dstpos;
+						}
+					}
+					hdlc->crc = 0xffff;
+					hdlc->shift_reg = 0;
+					hdlc->data_bits = 0;
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
+							hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
+							hdlc->state = HDLC_FAST_FLAG;
+							hdlc->ffbit_shift = hdlc->bit_shift;
+							hdlc->bit_shift = 1;
+						} else {
+							hdlc->state = HDLC_GET_DATA;
+							hdlc->data_received = 0;
+						}
+					} else {
+						hdlc->state = HDLC_GET_DATA;
+						hdlc->data_received = 0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->data_bits++;
+					break;
+				}
+				hdlc->hdlc_bits1 = 0;
+			}
+			if (status) {
+				hdlc->dstpos = 0;
+				*count -= slen;
+				hdlc->cbin <<= 1;
+				hdlc->bit_shift--;
+				return status;
+			}
+			if(hdlc->data_bits==8){
+				unsigned cval;
+
+				hdlc->data_bits = 0;
+				hdlc->data_received = 1;
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+				// good byte received
+				if (dsize--) {
+					dst[hdlc->dstpos++] = hdlc->shift_reg;
+				} else {
+					// frame too long
+					status = -HDLC_LENGTH_ERROR;
+					hdlc->dstpos = 0;
+				}
+			}
+			hdlc->cbin <<= 1;
+			hdlc->bit_shift--;
+			break;
+		case HDLC_FAST_FLAG:
+			if(hdlc->cbin==hdlc->ffvalue){
+				hdlc->bit_shift = 0;
+				break;
+			} else {
+				if(hdlc->cbin == 0xff){
+					hdlc->state = HDLC_FAST_IDLE;
+					hdlc->bit_shift=0;
+				} else if(hdlc->ffbit_shift==8){
+					hdlc->state = HDLC_GETFLAG_B7;
+					break;
+				} else {
+					hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
+					hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
+					if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
+					hdlc->data_bits = hdlc->ffbit_shift-1;
+					hdlc->state = HDLC_GET_DATA;
+					hdlc->data_received = 0;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	*count -= slen;
+	return 0;
+}
+
+/*
+  isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
+
+  The bit stream starts with a beginning flag (01111110). After
+  that each byte is added to the bit stream with bit stuffing added
+  (0 after 5 1's).
+  When the last byte has been removed from the source buffer, the
+  CRC (2 bytes is added) and the frame terminates with the ending flag.
+  For the dchannel, the idle character (all 1's) is also added at the end.
+  If this function is called with empty source buffer (slen=0), flags or
+  idle character will be generated.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (encoded) from source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of encoded bytes in the destination buffer
+*/
+int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		unsigned short slen, int *count,
+		unsigned char *dst, int dsize)
+{
+	static const unsigned char xfast_flag_value[] = {
+		0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+	};
+
+	int len = 0;
+
+	*count = slen;
+
+	while (dsize > 0) {
+		if(hdlc->bit_shift==0){
+			if(slen && !hdlc->do_closing){
+				hdlc->shift_reg = *src++;
+				slen--;
+				if (slen == 0)
+					hdlc->do_closing = 1;  /* closing sequence, CRC + flag(s) */
+				hdlc->bit_shift = 8;
+			} else {
+				if(hdlc->state == HDLC_SEND_DATA){
+					if(hdlc->data_received){
+						hdlc->state = HDLC_SEND_CRC1;
+						hdlc->crc ^= 0xffff;
+						hdlc->bit_shift = 8;
+						hdlc->shift_reg = hdlc->crc & 0xff;
+					} else if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+					}
+				}
+
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			while (dsize--)
+				*dst++ = 0xff;
+
+			return dsize;
+		case HDLC_SEND_FAST_FLAG:
+			hdlc->do_closing = 0;
+			if(slen == 0){
+				*dst++ = hdlc->ffvalue;
+				len++;
+				dsize--;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SENDFLAG_B0:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->state = HDLC_SENDFLAG_B1A6;
+			break;
+		case HDLC_SENDFLAG_B1A6:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->cbin++;
+			if(++hdlc->hdlc_bits1 == 6)
+				hdlc->state = HDLC_SENDFLAG_B7;
+			break;
+		case HDLC_SENDFLAG_B7:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(slen == 0){
+				hdlc->state = HDLC_SENDFLAG_B0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SEND_FIRST_FLAG:
+			hdlc->data_received = 1;
+			if(hdlc->data_bits==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->shift_reg & 0x01)
+				hdlc->cbin++;
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+			}
+			break;
+		case HDLC_SEND_DATA:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				unsigned cval;
+
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			break;
+		case HDLC_SEND_CRC1:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = (hdlc->crc >> 8);
+				hdlc->state = HDLC_SEND_CRC2;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CRC2:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = 0x7e;
+				hdlc->state = HDLC_SEND_CLOSING_FLAG;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CLOSING_FLAG:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->cbin++;
+			}
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
+				if(hdlc->dchannel){
+					hdlc->ffvalue = 0x7e;
+					hdlc->state = HDLC_SEND_IDLE1;
+					hdlc->bit_shift = 8-hdlc->data_bits;
+					if(hdlc->bit_shift==0)
+						hdlc->state = HDLC_SEND_FAST_IDLE;
+				} else {
+					if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+						hdlc->data_received = 0;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+						hdlc->data_received = 0;
+					}
+					// Finished with this frame, send flags
+					if (dsize > 1) dsize = 1;
+				}
+			}
+			break;
+		case HDLC_SEND_IDLE1:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->cbin++;
+			hdlc->data_bits++;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_FAST_IDLE;
+				hdlc->bit_shift = 0;
+			}
+			break;
+		case HDLC_SEND_FAST_IDLE:
+			hdlc->do_closing = 0;
+			hdlc->cbin = 0xff;
+			hdlc->data_bits = 8;
+			if(hdlc->bit_shift == 8){
+				hdlc->cbin = 0x7e;
+				hdlc->state = HDLC_SEND_FIRST_FLAG;
+			} else {
+				*dst++ = hdlc->cbin;
+				hdlc->bit_shift = hdlc->data_bits = 0;
+				len++;
+				dsize = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		if(hdlc->do_adapt56){
+			if(hdlc->data_bits==7){
+				hdlc->cbin <<= 1;
+				hdlc->cbin++;
+				hdlc->data_bits++;
+			}
+		}
+		if(hdlc->data_bits==8){
+			*dst++ = hdlc->cbin;
+			hdlc->data_bits = 0;
+			len++;
+			dsize--;
+		}
+	}
+	*count -= slen;
+
+	return len;
+}
+
+EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
+EXPORT_SYMBOL(isdnhdlc_rcv_init);
+EXPORT_SYMBOL(isdnhdlc_decode);
+EXPORT_SYMBOL(isdnhdlc_out_init);
+EXPORT_SYMBOL(isdnhdlc_encode);
--- diff/drivers/isdn/hisax/isdnhdlc.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/isdn/hisax/isdnhdlc.h	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+ * isdnhdlc.h  --  General purpose ISDN HDLC decoder.
+ *
+ * Implementation of a HDLC decoder/encoder in software.
+ * Neccessary because some ISDN devices don't have HDLC
+ * controllers. Also included: a bit reversal table.
+ *
+ *Copyright (C) 2002    Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ISDNHDLC_H__
+#define __ISDNHDLC_H__
+
+struct isdnhdlc_vars {
+	int bit_shift;
+	int hdlc_bits1;
+	int data_bits;
+	int ffbit_shift; 	// encoding only
+	int state;
+	int dstpos;
+
+	unsigned short crc;
+
+	unsigned char cbin;
+	unsigned char shift_reg;
+	unsigned char ffvalue;
+
+	int data_received:1; 	// set if transferring data
+	int dchannel:1; 	// set if D channel (send idle instead of flags)
+	int do_adapt56:1; 	// set if 56K adaptation
+        int do_closing:1; 	// set if in closing phase (need to send CRC + flag
+};
+
+
+/*
+  The return value from isdnhdlc_decode is
+  the frame length, 0 if no complete frame was decoded,
+  or a negative error number
+*/
+#define HDLC_FRAMING_ERROR     1
+#define HDLC_CRC_ERROR         2
+#define HDLC_LENGTH_ERROR      3
+
+extern const unsigned char isdnhdlc_bit_rev_tab[256];
+
+extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
+
+extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
+	                    unsigned char *dst, int dsize);
+
+extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
+
+extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
+	                    unsigned char *dst,int dsize);
+
+#endif /* __ISDNHDLC_H__ */
--- diff/drivers/isdn/hisax/teles_cs.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/isdn/hisax/teles_cs.c	2004-02-18 09:03:59.000000000 +0000
@@ -0,0 +1,549 @@
+/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
+/*======================================================================
+
+    A teles S0 PCMCIA client driver
+
+    Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
+    Written by Christof Petig, christof.petig@wtal.de
+    
+    Also inspired by ELSA PCMCIA driver 
+    by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
+    
+    Extentions to new hisax_pcmcia by Karsten Keil
+
+    minor changes to be compatible with kernel 2.4.x
+    by Jan.Schubert@GMX.li
+
+======================================================================*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include "hisax_cfg.h"
+
+MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
+MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
+MODULE_LICENSE("GPL");
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
+static char *version =
+"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from, the old way */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, 3 */
+static u_long irq_mask = 0xdeb8;
+
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+static int protocol = 2;        /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card insertion
+   and ejection events.  They are invoked from the teles_cs event
+   handler.
+*/
+
+static void teles_cs_config(dev_link_t *link);
+static void teles_cs_release(dev_link_t *link);
+static int teles_cs_event(event_t event, int priority,
+                          event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *teles_attach(void);
+static void teles_detach(dev_link_t *);
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "teles_cs";
+
+/*
+   A linked list of "instances" of the teles_cs device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   To simplify the data structure handling, we actually include the
+   dev_link_t structure in the device's private data structure.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+*/
+
+typedef struct local_info_t {
+    dev_link_t          link;
+    dev_node_t          node;
+    int                 busy;
+    int			cardnr;
+} local_info_t;
+
+/*======================================================================
+
+    teles_attach() creates an "instance" of the driver, allocatingx
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+
+======================================================================*/
+
+static dev_link_t *teles_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    local_info_t *local;
+    int ret, i;
+
+    DEBUG(0, "teles_attach()\n");
+
+    /* Allocate space for private device-specific data */
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local) return NULL;
+    memset(local, 0, sizeof(local_info_t));
+    local->cardnr = -1;
+    link = &local->link; link->priv = local;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID|IRQ_SHARE_ID;
+    if (irq_list[0] == -1)
+        link->irq.IRQInfo2 = irq_mask;
+    else
+        for (i = 0; i < 4; i++)
+            link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = NULL;
+
+    /*
+      General socket configuration defaults can go here.  In this
+      client, we assume very little, and rely on the CIS for almost
+      everything.  In most clients, many details (i.e., number, sizes,
+      and attributes of IO windows) are fixed by the nature of the
+      device, and can be hard-wired here.
+    */
+    link->io.NumPorts1 = 96;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 5;
+
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &teles_cs_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = pcmcia_register_client(&link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+        cs_error(link->handle, RegisterClient, ret);
+        teles_detach(link);
+        return NULL;
+    }
+
+    return link;
+} /* teles_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void teles_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    local_info_t *info = link->priv;
+    int ret;
+
+    DEBUG(0, "teles_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    if (link->state & DEV_CONFIG)
+        teles_cs_release(link);
+
+    /*
+       If the device is currently configured and active, we won't
+       actually delete it yet.  Instead, it is marked so that when
+       the release() function is called, that will trigger a proper
+       detach().
+    */
+    if (link->state & DEV_CONFIG) {
+      DEBUG(0, "teles_cs: detach postponed, '%s' "
+               "still locked\n", link->dev->dev_name);
+        link->state |= DEV_STALE_LINK;
+        return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle) {
+        ret = pcmcia_deregister_client(link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+
+    /* Unlink device structure and free it */
+    *linkp = link->next;
+    kfree(info);
+
+} /* teles_detach */
+
+/*======================================================================
+
+    teles_cs_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    device available to the system.
+
+======================================================================*/
+static int get_tuple(client_handle_t handle, tuple_t *tuple,
+                     cisparse_t *parse)
+{
+    int i = pcmcia_get_tuple_data(handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return pcmcia_parse_tuple(handle, tuple, parse);
+}
+
+static int first_tuple(client_handle_t handle, tuple_t *tuple,
+                     cisparse_t *parse)
+{
+    int i = pcmcia_get_first_tuple(handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return get_tuple(handle, tuple, parse);
+}
+
+static int next_tuple(client_handle_t handle, tuple_t *tuple,
+                     cisparse_t *parse)
+{
+    int i = pcmcia_get_next_tuple(handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return get_tuple(handle, tuple, parse);
+}
+
+static void teles_cs_config(dev_link_t *link)
+{
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    local_info_t *dev;
+    int i, j, last_fn;
+    u_short buf[128];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    IsdnCard_t icard;
+
+    DEBUG(0, "teles_config(0x%p)\n", link);
+    handle = link->handle;
+    dev = link->priv;
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = 255;
+    tuple.TupleOffset = 0;
+    tuple.Attributes = 0;
+    i = first_tuple(handle, &tuple, &parse);
+    if (i != CS_SUCCESS) {
+        last_fn = ParseTuple;
+	goto cs_failed;
+    }
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i == CS_SUCCESS) {
+        if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
+            printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
+            link->conf.ConfigIndex = cf->index;
+            link->io.BasePort1 = cf->io.win[0].base;
+            i = pcmcia_request_io(link->handle, &link->io);
+            if (i == CS_SUCCESS) break;
+        } else {
+          printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
+          link->conf.ConfigIndex = cf->index;
+          for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
+            link->io.BasePort1 = j;
+            i = pcmcia_request_io(link->handle, &link->io);
+            if (i == CS_SUCCESS) break;
+          }
+          break;
+        }
+        i = next_tuple(handle, &tuple, &parse);
+    }
+
+    if (i != CS_SUCCESS) {
+	last_fn = RequestIO;
+	goto cs_failed;
+    }
+
+    i = pcmcia_request_irq(link->handle, &link->irq);
+    if (i != CS_SUCCESS) {
+        link->irq.AssignedIRQ = 0;
+	last_fn = RequestIRQ;
+        goto cs_failed;
+    }
+
+    i = pcmcia_request_configuration(link->handle, &link->conf);
+    if (i != CS_SUCCESS) {
+      last_fn = RequestConfiguration;
+      goto cs_failed;
+    }
+
+    /* At this point, the dev_node_t structure(s) should be
+       initialized and arranged in a linked list at link->dev. *//*  */
+    sprintf(dev->node.dev_name, "teles");
+    dev->node.major = dev->node.minor = 0x0;
+
+    link->dev = &dev->node;
+
+    /* Finally, report what we've done */
+    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+           dev->node.dev_name, link->conf.ConfigIndex,
+           link->conf.Vcc/10, link->conf.Vcc%10);
+    if (link->conf.Vpp1)
+        printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+        printk(", irq %d", link->irq.AssignedIRQ);
+    if (link->io.NumPorts1)
+        printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+               link->io.BasePort1+link->io.NumPorts1-1);
+    if (link->io.NumPorts2)
+        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+               link->io.BasePort2+link->io.NumPorts2-1);
+    printk("\n");
+
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    icard.para[0] = link->irq.AssignedIRQ;
+    icard.para[1] = link->io.BasePort1;
+    icard.protocol = protocol;
+    icard.typ = ISDN_CTYPE_TELESPCMCIA;
+    
+    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
+    if (i < 0) {
+    	printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
+    		i, link->io.BasePort1);
+    	teles_cs_release(link);
+    } else
+    	((local_info_t*)link->priv)->cardnr = i;
+
+    return;
+cs_failed:
+    cs_error(link->handle, last_fn, i);
+    teles_cs_release(link);
+} /* teles_cs_config */
+
+/*======================================================================
+
+    After a card is removed, teles_cs_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void teles_cs_release(dev_link_t *link)
+{
+    local_info_t *local = link->priv;
+
+    DEBUG(0, "teles_cs_release(0x%p)\n", link);
+
+    if (local) {
+    	if (local->cardnr >= 0) {
+    	    /* no unregister function with hisax */
+	    HiSax_closecard(local->cardnr);
+	}
+    }
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win)
+        pcmcia_release_window(link->win);
+    pcmcia_release_configuration(link->handle);
+    pcmcia_release_io(link->handle, &link->io);
+    pcmcia_release_irq(link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
+
+    if (link->state & DEV_STALE_LINK)
+        teles_detach(link);
+
+} /* teles_cs_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+
+======================================================================*/
+
+static int teles_cs_event(event_t event, int priority,
+                          event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *dev = link->priv;
+
+    DEBUG(1, "teles_cs_event(%d)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        if (link->state & DEV_CONFIG) {
+            ((local_info_t*)link->priv)->busy = 1;
+	    teles_cs_release(link);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+        teles_cs_config(link);
+        break;
+    case CS_EVENT_PM_SUSPEND:
+        link->state |= DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+        /* Mark the device as stopped, to block IO until later */
+        dev->busy = 1;
+        if (link->state & DEV_CONFIG)
+            pcmcia_release_configuration(link->handle);
+        break;
+    case CS_EVENT_PM_RESUME:
+        link->state &= ~DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+        if (link->state & DEV_CONFIG)
+            pcmcia_request_configuration(link->handle, &link->conf);
+        dev->busy = 0;
+        break;
+    }
+    return 0;
+} /* teles_cs_event */
+
+static struct pcmcia_driver teles_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "teles_cs",
+	},
+	.attach		= teles_attach,
+	.detach		= teles_detach,
+};
+
+static int __init init_teles_cs(void)
+{
+	return pcmcia_register_driver(&teles_cs_driver);
+}
+
+static void __exit exit_teles_cs(void)
+{
+	pcmcia_unregister_driver(&teles_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL)
+		teles_detach(dev_list);
+}
+
+module_init(init_teles_cs);
+module_exit(exit_teles_cs);
--- diff/drivers/md/dm-bio-list.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-bio-list.h	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2004 Red Hat UK Ltd.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_BIO_LIST_H
+#define DM_BIO_LIST_H
+
+#include <linux/bio.h>
+
+struct bio_list {
+	struct bio *head;
+	struct bio *tail;
+};
+
+static inline void bio_list_init(struct bio_list *bl)
+{
+	bl->head = bl->tail = NULL;
+}
+
+static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
+{
+	bio->bi_next = NULL;
+
+	if (bl->tail)
+		bl->tail->bi_next = bio;
+	else
+		bl->head = bio;
+
+	bl->tail = bio;
+}
+
+static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2)
+{
+	if (bl->tail)
+		bl->tail->bi_next = bl2->head;
+	else
+		bl->head = bl2->head;
+
+	bl->tail = bl2->tail;
+}
+
+static inline struct bio *bio_list_pop(struct bio_list *bl)
+{
+	struct bio *bio = bl->head;
+
+	if (bio) {
+		bl->head = bl->head->bi_next;
+		if (!bl->head)
+			bl->tail = NULL;
+
+		bio->bi_next = NULL;
+	}
+
+	return bio;
+}
+
+static inline struct bio *bio_list_get(struct bio_list *bl)
+{
+	struct bio *bio = bl->head;
+
+	bl->head = bl->tail = NULL;
+
+	return bio;
+}
+
+#endif
--- diff/drivers/md/dm-crypt.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-crypt.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) 2003 Christophe Saout <christophe@saout.de>
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <asm/scatterlist.h>
+
+#include "dm.h"
+
+/*
+ * per bio private data
+ */
+struct crypt_io {
+	struct dm_target *target;
+	struct bio *bio;
+	struct bio *first_clone;
+	struct work_struct work;
+	atomic_t pending;
+	int error;
+};
+
+/*
+ * context holding the current state of a multi-part conversion
+ */
+struct convert_context {
+	struct bio *bio_in;
+	struct bio *bio_out;
+	unsigned int offset_in;
+	unsigned int offset_out;
+	int idx_in;
+	int idx_out;
+	sector_t sector;
+	int write;
+};
+
+/*
+ * Crypt: maps a linear range of a block device
+ * and encrypts / decrypts at the same time.
+ */
+struct crypt_config {
+	struct dm_dev *dev;
+	sector_t start;
+
+	/*
+	 * pool for per bio private data and
+	 * for encryption buffer pages
+	 */
+	mempool_t *io_pool;
+	mempool_t *page_pool;
+
+	/*
+	 * crypto related data
+	 */
+	struct crypto_tfm *tfm;
+	sector_t iv_offset;
+	int (*iv_generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
+	int iv_size;
+	int key_size;
+	u8 key[0];
+};
+
+#define MIN_IOS        256
+#define MIN_POOL_PAGES 32
+#define MIN_BIO_PAGES  8
+
+static kmem_cache_t *_crypt_io_pool;
+
+/*
+ * Mempool alloc and free functions for the page
+ */
+static void *mempool_alloc_page(int gfp_mask, void *data)
+{
+	return alloc_page(gfp_mask);
+}
+
+static void mempool_free_page(void *page, void *data)
+{
+	__free_page(page);
+}
+
+
+/*
+ * Different IV generation algorithms
+ */
+static int crypt_iv_plain(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+	*(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
+	if (cc->iv_size > sizeof(u32) / sizeof(u8))
+		memset(iv + (sizeof(u32) / sizeof(u8)), 0,
+		       cc->iv_size - (sizeof(u32) / sizeof(u8)));
+
+	return 0;
+}
+
+static inline int
+crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
+                          struct scatterlist *in, unsigned int length,
+                          int write, sector_t sector)
+{
+	u8 iv[cc->iv_size];
+	int r;
+
+	if (cc->iv_generator) {
+		r = cc->iv_generator(cc, iv, sector);
+		if (r < 0)
+			return r;
+
+		if (write)
+			r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv);
+		else
+			r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length, iv);
+	} else {
+		if (write)
+			r = crypto_cipher_encrypt(cc->tfm, out, in, length);
+		else
+			r = crypto_cipher_decrypt(cc->tfm, out, in, length);
+	}
+
+	return r;
+}
+
+static void
+crypt_convert_init(struct crypt_config *cc, struct convert_context *ctx,
+                   struct bio *bio_out, struct bio *bio_in,
+                   sector_t sector, int write)
+{
+	ctx->bio_in = bio_in;
+	ctx->bio_out = bio_out;
+	ctx->offset_in = 0;
+	ctx->offset_out = 0;
+	ctx->idx_in = bio_in ? bio_in->bi_idx : 0;
+	ctx->idx_out = bio_out ? bio_out->bi_idx : 0;
+	ctx->sector = sector + cc->iv_offset;
+	ctx->write = write;
+}
+
+/*
+ * Encrypt / decrypt data from one bio to another one (can be the same one)
+ */
+static int crypt_convert(struct crypt_config *cc,
+                         struct convert_context *ctx)
+{
+	int r = 0;
+
+	while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
+	      ctx->idx_out < ctx->bio_out->bi_vcnt) {
+		struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
+		struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
+		struct scatterlist sg_in = {
+			.page = bv_in->bv_page,
+			.offset = bv_in->bv_offset + ctx->offset_in,
+			.length = 1 << SECTOR_SHIFT
+		};
+		struct scatterlist sg_out = {
+			.page = bv_out->bv_page,
+			.offset = bv_out->bv_offset + ctx->offset_out,
+			.length = 1 << SECTOR_SHIFT
+		};
+
+		ctx->offset_in += sg_in.length;
+		if (ctx->offset_in >= bv_in->bv_len) {
+			ctx->offset_in = 0;
+			ctx->idx_in++;
+		}
+
+		ctx->offset_out += sg_out.length;
+		if (ctx->offset_out >= bv_out->bv_len) {
+			ctx->offset_out = 0;
+			ctx->idx_out++;
+		}
+
+		r = crypt_convert_scatterlist(cc, &sg_out, &sg_in, sg_in.length,
+		                              ctx->write, ctx->sector);
+		if (r < 0)
+			break;
+
+		ctx->sector++;
+	}
+
+	return r;
+}
+
+/*
+ * Generate a new unfragmented bio with the given size
+ * This should never violate the device limitations
+ * May return a smaller bio when running out of pages
+ */
+static struct bio *
+crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
+                   struct bio *base_bio, int *bio_vec_idx)
+{
+	struct bio *bio;
+	int nr_iovecs = dm_div_up(size, PAGE_SIZE);
+	int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+	int flags = current->flags;
+	int i;
+
+	/*
+	 * Tell VM to act less aggressively and fail earlier.
+	 * This is not necessary but increases throughput.
+	 * FIXME: Is this really intelligent?
+	 */
+	current->flags &= ~PF_MEMALLOC;
+
+	if (base_bio)
+		bio = bio_clone(base_bio, GFP_NOIO);
+	else
+		bio = bio_alloc(GFP_NOIO, nr_iovecs);
+	if (!bio) {
+		if (flags & PF_MEMALLOC)
+			current->flags |= PF_MEMALLOC;
+		return NULL;
+	}
+
+	/* if the last bio was not complete, continue where that one ended */
+	bio->bi_idx = *bio_vec_idx;
+	bio->bi_vcnt = *bio_vec_idx;
+	bio->bi_size = 0;
+	bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+
+	/* bio->bi_idx pages have already been allocated */
+	size -= bio->bi_idx * PAGE_SIZE;
+
+	for(i = bio->bi_idx; i < nr_iovecs; i++) {
+		struct bio_vec *bv = bio_iovec_idx(bio, i);
+
+		bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
+		if (!bv->bv_page)
+			break;
+
+		/*
+		 * if additional pages cannot be allocated without waiting,
+		 * return a partially allocated bio, the caller will then try
+		 * to allocate additional bios while submitting this partial bio
+		 */
+		if ((i - bio->bi_idx) == (MIN_BIO_PAGES - 1))
+			gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+
+		bv->bv_offset = 0;
+		if (size > PAGE_SIZE)
+			bv->bv_len = PAGE_SIZE;
+		else
+			bv->bv_len = size;
+
+		bio->bi_size += bv->bv_len;
+		bio->bi_vcnt++;
+		size -= bv->bv_len;
+	}
+
+	if (flags & PF_MEMALLOC)
+		current->flags |= PF_MEMALLOC;
+
+	if (!bio->bi_size) {
+		bio_put(bio);
+		return NULL;
+	}
+
+	/*
+	 * Remember the last bio_vec allocated to be able
+	 * to correctly continue after the splitting.
+	 */
+	*bio_vec_idx = bio->bi_vcnt;
+
+	return bio;
+}
+
+static void crypt_free_buffer_pages(struct crypt_config *cc,
+                                    struct bio *bio, unsigned int bytes)
+{
+	unsigned int start, end;
+	struct bio_vec *bv;
+	int i;
+
+	/*
+	 * This is ugly, but Jens Axboe thinks that using bi_idx in the
+	 * endio function is too dangerous at the moment, so I calculate the
+	 * correct position using bi_vcnt and bi_size.
+	 * The bv_offset and bv_len fields might already be modified but we
+	 * know that we always allocated whole pages.
+	 * A fix to the bi_idx issue in the kernel is in the works, so
+	 * we will hopefully be able to revert to the cleaner solution soon.
+	 */
+	i = bio->bi_vcnt - 1;
+	bv = bio_iovec_idx(bio, i);
+	end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - bio->bi_size;
+	start = end - bytes;
+
+	start >>= PAGE_SHIFT;
+	if (!bio->bi_size)
+		end = bio->bi_vcnt;
+	else
+		end >>= PAGE_SHIFT;
+
+	for(i = start; i < end; i++) {
+		bv = bio_iovec_idx(bio, i);
+		BUG_ON(!bv->bv_page);
+		mempool_free(bv->bv_page, cc->page_pool);
+		bv->bv_page = NULL;
+	}
+}
+
+/*
+ * One of the bios was finished. Check for completion of
+ * the whole request and correctly clean up the buffer.
+ */
+static void dec_pending(struct crypt_io *io, int error)
+{
+	struct crypt_config *cc = (struct crypt_config *) io->target->private;
+
+	if (error < 0)
+		io->error = error;
+
+	if (!atomic_dec_and_test(&io->pending))
+		return;
+
+	if (io->first_clone)
+		bio_put(io->first_clone);
+
+	bio_endio(io->bio, io->bio->bi_size, io->error);
+
+	mempool_free(io, cc->io_pool);
+}
+
+/*
+ * kcryptd:
+ *
+ * Needed because it would be very unwise to do decryption in an
+ * interrupt context, so bios returning from read requests get
+ * queued here.
+ */
+static struct workqueue_struct *_kcryptd_workqueue;
+
+static void kcryptd_do_work(void *data)
+{
+	struct crypt_io *io = (struct crypt_io *) data;
+	struct crypt_config *cc = (struct crypt_config *) io->target->private;
+	struct convert_context ctx;
+	int r;
+
+	crypt_convert_init(cc, &ctx, io->bio, io->bio,
+	                   io->bio->bi_sector - io->target->begin, 0);
+	r = crypt_convert(cc, &ctx);
+
+	dec_pending(io, r);
+}
+
+static void kcryptd_queue_io(struct crypt_io *io)
+{
+	INIT_WORK(&io->work, kcryptd_do_work, io);
+	queue_work(_kcryptd_workqueue, &io->work);
+}
+
+/*
+ * Decode key from its hex representation
+ */
+static int crypt_decode_key(u8 *key, char *hex, int size)
+{
+	char buffer[3];
+	char *endp;
+	int i;
+
+	buffer[2] = '\0';
+
+	for(i = 0; i < size; i++) {
+		buffer[0] = *hex++;
+		buffer[1] = *hex++;
+
+		key[i] = (u8)simple_strtoul(buffer, &endp, 16);
+
+		if (endp != &buffer[2])
+			return -EINVAL;
+	}
+
+	if (*hex != '\0')
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Encode key into its hex representation
+ */
+static void crypt_encode_key(char *hex, u8 *key, int size)
+{
+	int i;
+
+	for(i = 0; i < size; i++) {
+		sprintf(hex, "%02x", *key);
+		hex += 2;
+		key++;
+	}
+}
+
+/*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+ */
+static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	struct crypt_config *cc;
+	struct crypto_tfm *tfm;
+	char *tmp;
+	char *cipher;
+	char *mode;
+	int crypto_flags;
+	int key_size;
+
+	if (argc != 5) {
+		ti->error = "dm-crypt: Not enough arguments";
+		return -EINVAL;
+	}
+
+	tmp = argv[0];
+	cipher = strsep(&tmp, "-");
+	mode = strsep(&tmp, "-");
+
+	if (tmp)
+		DMWARN("dm-crypt: Unexpected additional cipher options");
+
+	key_size = strlen(argv[1]) >> 1;
+
+	cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+	if (cc == NULL) {
+		ti->error =
+			"dm-crypt: Cannot allocate transparent encryption context";
+		return -ENOMEM;
+	}
+
+	if (!mode || strcmp(mode, "plain") == 0)
+		cc->iv_generator = crypt_iv_plain;
+	else if (strcmp(mode, "ecb") == 0)
+		cc->iv_generator = NULL;
+	else {
+		ti->error = "dm-crypt: Invalid chaining mode";
+		goto bad1;
+	}
+
+	if (cc->iv_generator)
+		crypto_flags = CRYPTO_TFM_MODE_CBC;
+	else
+		crypto_flags = CRYPTO_TFM_MODE_ECB;
+
+	tfm = crypto_alloc_tfm(cipher, crypto_flags);
+	if (!tfm) {
+		ti->error = "dm-crypt: Error allocating crypto tfm";
+		goto bad1;
+	}
+
+	if (tfm->crt_u.cipher.cit_decrypt_iv && tfm->crt_u.cipher.cit_encrypt_iv)
+		/* at least a 32 bit sector number should fit in our buffer */
+		cc->iv_size = max(crypto_tfm_alg_ivsize(tfm),
+		                  (unsigned int)(sizeof(u32) / sizeof(u8)));
+	else {
+		cc->iv_size = 0;
+		if (cc->iv_generator) {
+			DMWARN("dm-crypt: Selected cipher does not support IVs");
+			cc->iv_generator = NULL;
+		}
+	}
+
+	cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
+				     mempool_free_slab, _crypt_io_pool);
+	if (!cc->io_pool) {
+		ti->error = "dm-crypt: Cannot allocate crypt io mempool";
+		goto bad2;
+	}
+
+	cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
+				       mempool_free_page, NULL);
+	if (!cc->page_pool) {
+		ti->error = "dm-crypt: Cannot allocate page mempool";
+		goto bad3;
+	}
+
+	cc->tfm = tfm;
+	cc->key_size = key_size;
+	if ((key_size == 0 && strcmp(argv[1], "-") != 0)
+	    || crypt_decode_key(cc->key, argv[1], key_size) < 0) {
+		ti->error = "dm-crypt: Error decoding key";
+		goto bad4;
+	}
+
+	if (tfm->crt_u.cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
+		ti->error = "dm-crypt: Error setting key";
+		goto bad4;
+	}
+
+	if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
+		ti->error = "dm-crypt: Invalid iv_offset sector";
+		goto bad4;
+	}
+
+	if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
+		ti->error = "dm-crypt: Invalid device sector";
+		goto bad4;
+	}
+
+	if (dm_get_device(ti, argv[3], cc->start, ti->len,
+	                  dm_table_get_mode(ti->table), &cc->dev)) {
+		ti->error = "dm-crypt: Device lookup failed";
+		goto bad4;
+	}
+
+	ti->private = cc;
+	return 0;
+
+bad4:
+	mempool_destroy(cc->page_pool);
+bad3:
+	mempool_destroy(cc->io_pool);
+bad2:
+	crypto_free_tfm(tfm);
+bad1:
+	kfree(cc);
+	return -EINVAL;
+}
+
+static void crypt_dtr(struct dm_target *ti)
+{
+	struct crypt_config *cc = (struct crypt_config *) ti->private;
+
+	mempool_destroy(cc->page_pool);
+	mempool_destroy(cc->io_pool);
+
+	crypto_free_tfm(cc->tfm);
+	dm_put_device(ti, cc->dev);
+	kfree(cc);
+}
+
+static int crypt_endio(struct bio *bio, unsigned int done, int error)
+{
+	struct crypt_io *io = (struct crypt_io *) bio->bi_private;
+	struct crypt_config *cc = (struct crypt_config *) io->target->private;
+
+	if (bio_data_dir(bio) == WRITE) {
+		/*
+		 * free the processed pages, even if
+		 * it's only a partially completed write
+		 */
+		crypt_free_buffer_pages(cc, bio, done);
+	}
+
+	if (bio->bi_size)
+		return 1;
+
+	bio_put(bio);
+
+	/*
+	 * successful reads are decrypted by the worker thread
+	 */
+	if ((bio_data_dir(bio) == READ)
+	    && bio_flagged(bio, BIO_UPTODATE)) {
+		kcryptd_queue_io(io);
+		return 0;
+	}
+
+	dec_pending(io, error);
+	return error;
+}
+
+static inline struct bio *
+crypt_clone(struct crypt_config *cc, struct crypt_io *io, struct bio *bio,
+            sector_t sector, int *bvec_idx, struct convert_context *ctx)
+{
+	struct bio *clone;
+
+	if (bio_data_dir(bio) == WRITE) {
+		clone = crypt_alloc_buffer(cc, bio->bi_size,
+                                 io->first_clone, bvec_idx);
+		if (clone) {
+			ctx->bio_out = clone;
+			if (crypt_convert(cc, ctx) < 0) {
+				crypt_free_buffer_pages(cc, clone,
+				                        clone->bi_size);
+				bio_put(clone);
+				return NULL;
+			}
+		}
+	} else
+		clone = bio_clone(bio, GFP_NOIO);
+
+	if (!clone)
+		return NULL;
+
+	clone->bi_private = io;
+	clone->bi_end_io = crypt_endio;
+	clone->bi_bdev = cc->dev->bdev;
+	clone->bi_sector = cc->start + sector;
+	clone->bi_rw = bio->bi_rw;
+
+	return clone;
+}
+
+static int crypt_map(struct dm_target *ti, struct bio *bio)
+{
+	struct crypt_config *cc = (struct crypt_config *) ti->private;
+	struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
+	struct convert_context ctx;
+	struct bio *clone;
+	unsigned int remaining = bio->bi_size;
+	sector_t sector = bio->bi_sector - ti->begin;
+	int bvec_idx = 0;
+
+	io->target = ti;
+	io->bio = bio;
+	io->first_clone = NULL;
+	io->error = 0;
+	atomic_set(&io->pending, 1); /* hold a reference */
+
+	if (bio_data_dir(bio) == WRITE)
+		crypt_convert_init(cc, &ctx, NULL, bio, sector, 1);
+
+	/*
+	 * The allocated buffers can be smaller than the whole bio,
+	 * so repeat the whole process until all the data can be handled.
+	 */
+	while (remaining) {
+		clone = crypt_clone(cc, io, bio, sector, &bvec_idx, &ctx);
+		if (!clone)
+			goto cleanup;
+
+		if (!io->first_clone) {
+			/*
+			 * hold a reference to the first clone, because it
+			 * holds the bio_vec array and that can't be freed
+			 * before all other clones are released
+			 */
+			bio_get(clone);
+			io->first_clone = clone;
+		}
+		atomic_inc(&io->pending);
+
+		remaining -= clone->bi_size;
+		sector += bio_sectors(clone);
+
+		generic_make_request(clone);
+
+		/* out of memory -> run queues */
+		if (remaining)
+			blk_run_queues();
+	}
+
+	/* drop reference, clones could have returned before we reach this */
+	dec_pending(io, 0);
+	return 0;
+
+cleanup:
+	if (io->first_clone) {
+		dec_pending(io, -ENOMEM);
+		return 0;
+	}
+
+	/* if no bio has been dispatched yet, we can directly return the error */
+	mempool_free(io, cc->io_pool);
+	return -ENOMEM;
+}
+
+static int crypt_status(struct dm_target *ti, status_type_t type,
+			char *result, unsigned int maxlen)
+{
+	struct crypt_config *cc = (struct crypt_config *) ti->private;
+	char buffer[32];
+	const char *cipher;
+	const char *mode = NULL;
+	int offset;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		result[0] = '\0';
+		break;
+
+	case STATUSTYPE_TABLE:
+		cipher = crypto_tfm_alg_name(cc->tfm);
+
+		switch(cc->tfm->crt_u.cipher.cit_mode) {
+		case CRYPTO_TFM_MODE_CBC:
+			mode = "plain";
+			break;
+		case CRYPTO_TFM_MODE_ECB:
+			mode = "ecb";
+			break;
+		default:
+			BUG();
+		}
+
+		snprintf(result, maxlen, "%s-%s ", cipher, mode);
+		offset = strlen(result);
+
+		if (cc->key_size > 0) {
+			if ((maxlen - offset) < ((cc->key_size << 1) + 1))
+				return -ENOMEM;
+
+			crypt_encode_key(result + offset, cc->key, cc->key_size);
+			offset += cc->key_size << 1;
+		} else {
+			if (offset >= maxlen)
+				return -ENOMEM;
+			result[offset++] = '-';
+		}
+
+		format_dev_t(buffer, cc->dev->bdev->bd_dev);
+		snprintf(result + offset, maxlen - offset, " " SECTOR_FORMAT
+		         " %s " SECTOR_FORMAT, cc->iv_offset,
+		         buffer, cc->start);
+		break;
+	}
+	return 0;
+}
+
+static struct target_type crypt_target = {
+	.name   = "crypt",
+	.module = THIS_MODULE,
+	.ctr    = crypt_ctr,
+	.dtr    = crypt_dtr,
+	.map    = crypt_map,
+	.status = crypt_status,
+};
+
+static int __init dm_crypt_init(void)
+{
+	int r;
+
+	_crypt_io_pool = kmem_cache_create("dm-crypt_io",
+	                                   sizeof(struct crypt_io),
+	                                   0, 0, NULL, NULL);
+	if (!_crypt_io_pool)
+		return -ENOMEM;
+
+	_kcryptd_workqueue = create_workqueue("kcryptd");
+	if (!_kcryptd_workqueue) {
+		r = -ENOMEM;
+		DMERR("couldn't create kcryptd");
+		goto bad1;
+	}
+
+	r = dm_register_target(&crypt_target);
+	if (r < 0) {
+		DMERR("crypt: register failed %d", r);
+		goto bad2;
+	}
+
+	return 0;
+
+bad2:
+	destroy_workqueue(_kcryptd_workqueue);
+bad1:
+	kmem_cache_destroy(_crypt_io_pool);
+	return r;
+}
+
+static void __exit dm_crypt_exit(void)
+{
+	int r = dm_unregister_target(&crypt_target);
+
+	if (r < 0)
+		DMERR("crypt: unregister failed %d", r);
+
+	destroy_workqueue(_kcryptd_workqueue);
+	kmem_cache_destroy(_crypt_io_pool);
+}
+
+module_init(dm_crypt_init);
+module_exit(dm_crypt_exit);
+
+MODULE_AUTHOR("Christophe Saout <christophe@saout.de>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption");
+MODULE_LICENSE("GPL");
--- diff/drivers/media/radio/radio-sf16fmr2.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/media/radio/radio-sf16fmr2.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,447 @@
+/* SF16FMR2 radio driver for Linux radio support
+ * heavily based on fmi driver...
+ * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ *
+ * Notes on the hardware
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  No volume control - only mute/unmute - you have to use line volume
+ *
+ *  For read stereo/mono you must wait 0.1 sec after set frequency and
+ *  card unmuted so I set frequency on unmute
+ *  Signal handling seem to work only on autoscanning (not implemented)
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <asm/semaphore.h>
+
+static struct semaphore lock;
+
+#undef DEBUG
+//#define DEBUG 1
+
+#ifdef DEBUG
+# define  debug_print(s) printk s
+#else
+# define  debug_print(s)
+#endif
+
+/* this should be static vars for module size */
+struct fmr2_device
+{
+	int port;
+	int curvol; /* 0-65535, if not volume 0 or 65535 */
+	int mute;
+	int stereo; /* card is producing stereo audio */
+	unsigned long curfreq; /* freq in kHz */
+	int card_type;
+	__u32 flags;
+};
+
+static int io = 0x384;
+static int radio_nr = -1;
+
+/* hw precision is 12.5 kHz
+ * It is only usefull to give freq in intervall of 200 (=0.0125Mhz),
+ * other bits will be truncated
+ */
+#define RSF16_ENCODE(x)	((x)/200+856)
+#define RSF16_MINFREQ 87*16000
+#define RSF16_MAXFREQ 108*16000
+
+/* from radio-aimslab */
+static void sleep_delay(unsigned long n)
+{
+	unsigned d=n/(1000000U/HZ);
+	if (!d)
+		udelay(n);
+	else
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(d);
+	}
+}
+
+static inline void wait(int n,int port)
+{
+	for (;n;--n) inb(port);
+}
+
+static void outbits(int bits, unsigned int data, int nWait, int port)
+{
+	int bit;
+	for(;--bits>=0;) {
+		bit = (data>>bits) & 1;
+		outb(bit,port);
+		wait(nWait,port);
+		outb(bit|2,port);
+		wait(nWait,port);
+		outb(bit,port);
+		wait(nWait,port);
+	}
+}
+
+static inline void fmr2_mute(int port)
+{
+	outb(0x00, port);
+	wait(4,port);
+}
+
+static inline void fmr2_unmute(int port)
+{
+	outb(0x04, port);
+	wait(4,port);
+}
+
+static inline int fmr2_stereo_mode(int port)
+{
+	int n = inb(port);
+	outb(6,port);
+	inb(port);
+	n = ((n>>3)&1)^1;
+	debug_print((KERN_DEBUG "stereo: %d\n", n));
+	return n;
+}
+
+static int fmr2_product_info(struct fmr2_device *dev)
+{
+	int n = inb(dev->port);
+	n &= 0xC1;
+	if (n == 0)
+	{
+		/* this should support volume set */
+		dev->card_type = 12;
+		return 0;
+	}
+	/* not volume (mine is 11) */
+	dev->card_type = (n==128)?11:0;
+	return n;
+}
+
+static inline int fmr2_getsigstr(struct fmr2_device *dev)
+{
+	/* !!! work only if scanning freq */
+	int port = dev->port, res = 0xffff;
+	outb(5,port);
+	wait(4,port);
+	if (!(inb(port)&1)) res = 0;
+	debug_print((KERN_DEBUG "signal: %d\n", res));
+	return res;
+}
+
+/* set frequency and unmute card */
+static int fmr2_setfreq(struct fmr2_device *dev)
+{
+	int port = dev->port;
+	unsigned long freq = dev->curfreq;
+
+	fmr2_mute(port);
+
+	/* 0x42 for mono output
+	 * 0x102 forward scanning
+	 * 0x182 scansione avanti
+	 */
+	outbits(9,0x2,3,port);
+	outbits(16,RSF16_ENCODE(freq),2,port);
+
+	fmr2_unmute(port);
+
+	/* wait 0.11 sec */
+	sleep_delay(110000LU);
+
+	/* NOTE if mute this stop radio
+	   you must set freq on unmute */
+	dev->stereo = fmr2_stereo_mode(port);
+	return 0;
+}
+
+/* !!! not tested, in my card this does't work !!! */
+static int fmr2_setvolume(struct fmr2_device *dev)
+{
+	int i,a,n, port = dev->port;
+
+	if (dev->card_type != 11) return 1;
+
+	switch( (dev->curvol+(1<<11)) >> 12 )
+	{
+	case 0: case 1: n = 0x21; break;
+	case 2: n = 0x84; break;
+	case 3: n = 0x90; break;
+	case 4: n = 0x104; break;
+	case 5: n = 0x110; break;
+	case 6: n = 0x204; break;
+	case 7: n = 0x210; break;
+	case 8: n = 0x402; break;
+	case 9: n = 0x404; break;
+	default:
+	case 10: n = 0x408; break;
+	case 11: n = 0x410; break;
+	case 12: n = 0x801; break;
+	case 13: n = 0x802; break;
+	case 14: n = 0x804; break;
+	case 15: n = 0x808; break;
+	case 16: n = 0x810; break;
+	}
+	for(i=12;--i>=0;)
+	{
+		a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	for(i=6;--i>=0;)
+	{
+		a = ((0x18 >> i) & 1) << 6;
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	wait(4,port);
+	outb(0x14, port);
+
+	return 0;
+}
+
+static int fmr2_do_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, void *arg)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
+	debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
+		"stereo %d type %d\n",
+		fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute,
+		fmr2->stereo, fmr2->card_type));
+
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability *v = arg;
+			memset(v,0,sizeof(*v));
+			strcpy(v->name, "SF16-FMR2 radio");
+			v->type=VID_TYPE_TUNER;
+			v->channels=1;
+			v->audios=1;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner *v = arg;
+			int mult;
+
+			if(v->tuner)     /* Only 1 tuner */
+				return -EINVAL;
+			strcpy(v->name, "FM");
+			mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v->rangelow = RSF16_MINFREQ/mult;
+			v->rangehigh = RSF16_MAXFREQ/mult;
+			v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
+			if (fmr2->mute)
+				v->flags |= VIDEO_AUDIO_MUTE;
+			v->mode=VIDEO_MODE_AUTO;
+			down(&lock);
+			v->signal = fmr2_getsigstr(fmr2);
+			up(&lock);
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner *v = arg;
+			if (v->tuner!=0)
+				return -EINVAL;
+			fmr2->flags = v->flags & VIDEO_TUNER_LOW;
+			return 0;
+		}
+		case VIDIOCGFREQ:
+		{
+			unsigned long *freq = arg;
+			*freq = fmr2->curfreq;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				*freq /= 1000;
+			return 0;
+		}
+		case VIDIOCSFREQ:
+		{
+			unsigned long *freq = arg;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				*freq *= 1000;
+			if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
+				return -EINVAL;
+			/* rounding in steps of 200 to match th freq
+			 * that will be used
+			 */
+			fmr2->curfreq = (*freq/200)*200;
+
+			/* set card freq (if not muted) */
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				down(&lock);
+				fmr2_setfreq(fmr2);
+				up(&lock);
+			}
+			return 0;
+		}
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio *v = arg;
+			memset(v,0,sizeof(*v));
+			/* !!! do not return VIDEO_AUDIO_MUTE */
+			v->flags = VIDEO_AUDIO_MUTABLE;
+			strcpy(v->name, "Radio");
+			/* get current stereo mode */
+			v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
+			/* volume supported ? */
+			if (fmr2->card_type == 11)
+			{
+				v->flags |= VIDEO_AUDIO_VOLUME;
+				v->step = 1 << 12;
+				v->volume = fmr2->curvol;
+			}
+			debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume));
+			return 0;
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio *v = arg;
+			if(v->audio)
+				return -EINVAL;
+			debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume));
+			/* set volume */
+			if (v->flags & VIDEO_AUDIO_VOLUME)
+				fmr2->curvol = v->volume; /* !!! set with precision */
+			if (fmr2->card_type != 11) fmr2->curvol = 65535;
+			fmr2->mute = 0;
+			if (v->flags & VIDEO_AUDIO_MUTE)
+				fmr2->mute = 1;
+#ifdef DEBUG
+			if (fmr2->curvol && !fmr2->mute)
+				printk(KERN_DEBUG "unmute\n");
+			else
+				printk(KERN_DEBUG "mute\n");
+#endif
+			down(&lock);
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				fmr2_setvolume(fmr2);
+				fmr2_setfreq(fmr2);
+			}
+			else fmr2_mute(fmr2->port);
+			up(&lock);
+			return 0;
+		}
+		case VIDIOCGUNIT:
+		{
+			struct video_unit *v = arg;
+			v->video=VIDEO_NO_UNIT;
+			v->vbi=VIDEO_NO_UNIT;
+			v->radio=dev->minor;
+			v->audio=0; /* How do we find out this??? */
+			v->teletext=VIDEO_NO_UNIT;
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int fmr2_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+ {
+	return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
+}
+
+static struct fmr2_device fmr2_unit;
+
+static struct file_operations fmr2_fops = {
+	.owner          = THIS_MODULE,
+	.open           = video_exclusive_open,
+	.release        = video_exclusive_release,
+	.ioctl          = fmr2_ioctl,
+	.llseek         = no_llseek,
+};
+
+static struct video_device fmr2_radio=
+{
+	.owner		= THIS_MODULE,
+	.name		= "SF16FMR2 radio",
+	. type		= VID_TYPE_TUNER,
+	.hardware	= VID_HARDWARE_SF16FMR2,
+	.fops		= &fmr2_fops,
+};
+
+static int __init fmr2_init(void)
+{
+	fmr2_unit.port = io;
+	fmr2_unit.curvol = 0;
+	fmr2_unit.mute = 0;
+	fmr2_unit.curfreq = 0;
+	fmr2_unit.stereo = 1;
+	fmr2_unit.flags = VIDEO_TUNER_LOW;
+	fmr2_unit.card_type = 0;
+	fmr2_radio.priv = &fmr2_unit;
+
+	init_MUTEX(&lock);
+
+	if (request_region(io, 2, "sf16fmr2"))
+	{
+		printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+	{
+		release_region(io, 2);
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
+	/* mute card - prevents noisy bootups */
+	down(&lock);
+	fmr2_mute(io);
+	fmr2_product_info(&fmr2_unit);
+	up(&lock);
+	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+	return 0;
+}
+
+MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+MODULE_PARM(radio_nr, "i");
+
+static void __exit fmr2_cleanup_module(void)
+{
+	video_unregister_device(&fmr2_radio);
+	release_region(io,2);
+}
+
+module_init(fmr2_init);
+module_exit(fmr2_cleanup_module);
+
+#ifndef MODULE
+
+static int __init fmr2_setup_io(char *str)
+{
+	get_option(&str, &io);
+	return 1;
+}
+
+__setup("sf16fmr2=", fmr2_setup_io);
+
+#endif
--- diff/drivers/net/e100.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/e100.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,2297 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2004 Intel Corporation. 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.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ *	e100.c: Intel(R) PRO/100 ethernet driver
+ *
+ *	(Re)written 2003 by scott.feldman@intel.com.  Based loosely on
+ *	original e100 driver, but better described as a munging of
+ *	e100, e1000, eepro100, tg3, 8139cp, and other drivers.
+ *
+ *	References:
+ *		Intel 8255x 10/100 Mbps Ethernet Controller Family,
+ *		Open Source Software Developers Manual,
+ *		http://sourceforge.net/projects/e1000
+ *
+ *
+ *	                      Theory of Operation
+ *
+ *	I.   General
+ *
+ *	The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet
+ *	controller family, which includes the 82557, 82558, 82559, 82550,
+ *	82551, and 82562 devices.  82558 and greater controllers
+ *	integrate the Intel 82555 PHY.  The controllers are used in
+ *	server and client network interface cards, as well as in
+ *	LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx
+ *	configurations.  8255x supports a 32-bit linear addressing
+ *	mode and operates at 33Mhz PCI clock rate.
+ *
+ *	II.  Driver Operation
+ *
+ *	Memory-mapped mode is used exclusively to access the device's
+ *	shared-memory structure, the Control/Status Registers (CSR). All
+ *	setup, configuration, and control of the device, including queuing
+ *	of Tx, Rx, and configuration commands is through the CSR.
+ *	cmd_lock serializes accesses to the CSR command register.  cb_lock
+ *	protects the shared Command Block List (CBL).
+ *
+ *	8255x is highly MII-compliant and all access to the PHY go
+ *	through the Management Data Interface (MDI).  Consequently, the
+ *	driver leverages the mii.c library shared with other MII-compliant
+ *	devices.
+ *
+ *	Big- and Little-Endian byte order as well as 32- and 64-bit
+ *	archs are supported.  Weak-ordered memory and non-cache-coherent
+ *	archs are supported.
+ *
+ *	III. Transmit
+ *
+ *	A Tx skb is mapped and hangs off of a TCB.  TCBs are linked
+ *	together in a fixed-size ring (CBL) thus forming the flexible mode
+ *	memory structure.  A TCB marked with the suspend-bit indicates
+ *	the end of the ring.  The last TCB processed suspends the
+ *	controller, and the controller can be restarted by issue a CU
+ *	resume command to continue from the suspend point, or a CU start
+ *	command to start at a given position in the ring.
+ *
+ *	Non-Tx commands (config, multicast setup, etc) are linked
+ *	into the CBL ring along with Tx commands.  The common structure
+ *	used for both Tx and non-Tx commands is the Command Block (CB).
+ *
+ *	cb_to_use is the next CB to use for queuing a command; cb_to_clean
+ *	is the next CB to check for completion; cb_to_send is the first
+ *	CB to start on in case of a previous failure to resume.  CB clean
+ *	up happens in interrupt context in response to a CU interrupt, or
+ *	in dev->poll in the case where NAPI is enabled.  cbs_avail keeps
+ *	track of number of free CB resources available.
+ *
+ * 	Hardware padding of short packets to minimum packet size is
+ * 	enabled.  82557 pads with 7Eh, while the later controllers pad
+ * 	with 00h.
+ *
+ *	IV.  Recieve
+ *
+ *	The Receive Frame Area (RFA) comprises a ring of Receive Frame
+ *	Descriptors (RFD) + data buffer, thus forming the simplified mode
+ *	memory structure.  Rx skbs are allocated to contain both the RFD
+ *	and the data buffer, but the RFD is pulled off before the skb is
+ *	indicated.  The data buffer is aligned such that encapsulated
+ *	protocol headers are u32-aligned.  Since the RFD is part of the
+ *	mapped shared memory, and completion status is contained within
+ *	the RFD, the RFD must be dma_sync'ed to maintain a consistent
+ *	view from software and hardware.
+ *
+ *	Under typical operation, the  receive unit (RU) is start once,
+ *	and the controller happily fills RFDs as frames arrive.  If
+ *	replacement RFDs cannot be allocated, or the RU goes non-active,
+ *	the RU must be restarted.  Frame arrival generates an interrupt,
+ *	and Rx indication and re-allocation happen in the same context,
+ *	therefore no locking is required.  If NAPI is enabled, this work
+ *	happens in dev->poll.  A software-generated interrupt is gen-
+ *	erated from the watchdog to recover from a failed allocation
+ *	senario where all Rx resources have been indicated and none re-
+ *	placed.
+ *
+ *	V.   Miscellaneous
+ *
+ * 	VLAN offloading of tagging, stripping and filtering is not
+ * 	supported, but driver will accommodate the extra 4-byte VLAN tag
+ * 	for processing by upper layers.  Tx/Rx Checksum offloading is not
+ * 	supported.  Tx Scatter/Gather is not supported.  Jumbo Frames is
+ * 	not supported (hardware limitation).
+ *
+ * 	NAPI support is enabled with CONFIG_E100_NAPI.
+ *
+ * 	MagicPacket(tm) WoL support is enabled/disabled via ethtool.
+ *
+ * 	Thanks to JC (jchapman@katalix.com) for helping with
+ * 	testing/troubleshooting the development driver.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+
+
+#define DRV_NAME		"e100"
+#define DRV_VERSION		"3.0.13_dev"
+#define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
+#define DRV_COPYRIGHT		"Copyright(c) 1999-2004 Intel Corporation"
+#define PFX			DRV_NAME ": "
+
+#define E100_WATCHDOG_PERIOD	2 * HZ
+#define E100_NAPI_WEIGHT	16
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int debug = 3;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
+	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
+		__FUNCTION__ , ## args))
+
+#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
+	PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
+	PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
+static struct pci_device_id e100_id_table[] = {
+	INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1032, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1033, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1034, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1038, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1039, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103A, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103B, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103C, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103D, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103E, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x1050, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1051, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1052, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1067, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1068, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, e100_id_table);
+
+enum mac {
+	mac_82557_D100_A  = 0,
+	mac_82557_D100_B  = 1,
+	mac_82557_D100_C  = 2,
+	mac_82558_D101_A4 = 4,
+	mac_82558_D101_B0 = 5,
+	mac_82559_D101M   = 8,
+	mac_82559_D101S   = 9,
+	mac_82550_D102    = 12,
+	mac_82550_D102_C  = 13,
+	mac_82551_E       = 14,
+	mac_82551_F       = 15,
+	mac_82551_10      = 16,
+	mac_unknown       = 0xFF,
+};
+
+enum phy {
+	phy_100a     = 0x000003E0,
+	phy_100c     = 0x035002A8,
+	phy_82555_tx = 0x015002A8,
+	phy_nsc_tx   = 0x5C002000,
+	phy_82562_et = 0x033002A8,
+	phy_82562_em = 0x032002A8,
+	phy_82562_eh = 0x017002A8,
+	phy_unknown  = 0xFFFFFFFF,
+};
+
+/* CSR (Control/Status Registers) */
+struct csr {
+	struct {
+		u8 status;
+		u8 stat_ack;
+		u8 cmd_lo;
+		u8 cmd_hi;
+		u32 gen_ptr;
+	} scb;
+	u32 port;
+	u16 flash_ctrl;
+	u8 eeprom_ctrl_lo;
+	u8 eeprom_ctrl_hi;
+	u32 mdi_ctrl;
+	u32 rx_dma_count;
+};
+
+enum scb_status {
+	rus_ready        = 0x10,
+	rus_mask         = 0x3C,
+};
+
+enum scb_stat_ack {
+	stat_ack_not_ours    = 0x00,
+	stat_ack_sw_gen      = 0x04,
+	stat_ack_rnr         = 0x10,
+	stat_ack_cu_idle     = 0x20,
+	stat_ack_frame_rx    = 0x40,
+	stat_ack_cu_cmd_done = 0x80,
+	stat_ack_not_present = 0xFF,
+	stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+	stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+enum scb_cmd_hi {
+	irq_mask_none = 0x00,
+	irq_mask_all  = 0x01,
+	irq_sw_gen    = 0x02,
+};
+
+enum scb_cmd_lo {
+	ruc_start      = 0x01,
+	ruc_load_base  = 0x06,
+	cuc_start      = 0x10,
+	cuc_resume     = 0x20,
+	cuc_dump_addr  = 0x40,
+	cuc_dump_stats = 0x50,
+	cuc_load_base  = 0x60,
+	cuc_dump_reset = 0x70,
+};
+
+enum port {
+	software_reset  = 0x0000,
+	selftest        = 0x0001,
+	selective_reset = 0x0002,
+};
+
+enum eeprom_ctrl_lo {
+	eesk = 0x01,
+	eecs = 0x02,
+	eedi = 0x04,
+	eedo = 0x08,
+};
+
+enum mdi_ctrl {
+	mdi_write = 0x04000000,
+	mdi_read  = 0x08000000,
+	mdi_ready = 0x10000000,
+};
+
+enum eeprom_op {
+	op_write = 0x05,
+	op_read  = 0x06,
+	op_ewds  = 0x10,
+	op_ewen  = 0x13,
+};
+
+enum eeprom_offsets {
+	eeprom_id         = 0x0A,
+	eeprom_config_asf = 0x0D,
+	eeprom_smbus_addr = 0x90,
+};
+
+enum eeprom_id {
+	eeprom_id_wol = 0x0020,
+};
+
+enum eeprom_config_asf {
+	eeprom_asf = 0x8000,
+	eeprom_gcl = 0x4000,
+};
+
+enum cb_status {
+	cb_complete = 0x8000,
+	cb_ok       = 0x2000,
+};
+
+enum cb_command {
+	cb_iaaddr = 0x0001,
+	cb_config = 0x0002,
+	cb_multi  = 0x0003,
+	cb_tx     = 0x0004,
+	cb_dump   = 0x0006,
+	cb_tx_sf  = 0x0008,
+	cb_cid    = 0x1f00,
+	cb_i      = 0x2000,
+	cb_s      = 0x4000,
+	cb_el     = 0x8000,
+};
+
+struct rfd {
+	u16 status;
+	u16 command;
+	u32 link;
+	u32 rbd;
+	u16 actual_size;
+	u16 size;
+};
+
+struct rx {
+	struct rx *next, *prev;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+};
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+#define X(a,b)	b,a
+#else
+#define X(a,b)	a,b
+#endif
+struct config {
+/*0*/	u8 X(byte_count:6, pad0:2);
+/*1*/	u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1);
+/*2*/	u8 adaptive_ifs;
+/*3*/	u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1),
+	   term_write_cache_line:1), pad3:4);
+/*4*/	u8 X(rx_dma_max_count:7, pad4:1);
+/*5*/	u8 X(tx_dma_max_count:7, dma_max_count_enable:1);
+/*6*/	u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1),
+	   tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1),
+	   rx_discard_overruns:1), rx_save_bad_frames:1);
+/*7*/	u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2),
+	   pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1),
+	   tx_dynamic_tbd:1);
+/*8*/	u8 X(X(mii_mode:1, pad8:6), csma_disabled:1);
+/*9*/	u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1),
+	   link_status_wake:1), arp_wake:1), mcmatch_wake:1);
+/*10*/	u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2),
+	   loopback:2);
+/*11*/	u8 X(linear_priority:3, pad11:5);
+/*12*/	u8 X(X(linear_priority_mode:1, pad12:3), ifs:4);
+/*13*/	u8 ip_addr_lo;
+/*14*/	u8 ip_addr_hi;
+/*15*/	u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1),
+	   wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1),
+	   pad15_2:1), crs_or_cdt:1);
+/*16*/	u8 fc_delay_lo;
+/*17*/	u8 fc_delay_hi;
+/*18*/	u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1),
+	   rx_long_ok:1), fc_priority_threshold:3), pad18:1);
+/*19*/	u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1),
+	   fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1),
+	   full_duplex_force:1), full_duplex_pin:1);
+/*20*/	u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1);
+/*21*/	u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4);
+/*22*/	u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6);
+	u8 pad_d102[9];
+};
+
+#define E100_MAX_MULTICAST_ADDRS	64
+struct multi {
+	u16 count;
+	u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/];
+};
+
+/* Important: keep total struct u32-aligned */
+struct cb {
+	u16 status;
+	u16 command;
+	u32 link;
+	union {
+		u8 iaaddr[ETH_ALEN];
+		struct config config;
+		struct multi multi;
+		struct {
+			u32 tbd_array;
+			u16 tcb_byte_count;
+			u8 threshold;
+			u8 tbd_count;
+			struct {
+				u32 buf_addr;
+				u16 size;
+				u16 eol;
+			} tbd;
+		} tcb;
+		u32 dump_buffer_addr;
+	} u;
+	struct cb *next, *prev;
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+};
+
+enum loopback {
+	lb_none = 0, lb_mac = 1, lb_phy = 3,
+};
+
+struct stats {
+	u32 tx_good_frames, tx_max_collisions, tx_late_collisions,
+		tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+		tx_multiple_collisions, tx_total_collisions;
+	u32 rx_good_frames, rx_crc_errors, rx_alignment_errors,
+		rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+		rx_short_frame_errors;
+	u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+	u16 xmt_tco_frames, rcv_tco_frames;
+	u32 complete;
+};
+
+struct mem {
+	struct {
+		u32 signature;
+		u32 result;
+	} selftest;
+	struct stats stats;
+	u8 dump_buf[596];
+};
+
+struct param_range {
+	u32 min;
+	u32 max;
+	u32 count;
+};
+
+struct params {
+	struct param_range rfds;
+	struct param_range cbs;
+};
+
+struct nic {
+	/* Begin: frequently used values: keep adjacent for cache effect */
+	u32 msg_enable				____cacheline_aligned;
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+
+	struct rx *rxs				____cacheline_aligned;
+	struct rx *rx_to_use;
+	struct rx *rx_to_clean;
+	struct rfd blank_rfd;
+	int ru_running;
+
+	spinlock_t cb_lock			____cacheline_aligned;
+	spinlock_t cmd_lock;
+	struct csr *csr;
+	enum scb_cmd_lo cuc_cmd;
+	unsigned int cbs_avail;
+	struct cb *cbs;
+	struct cb *cb_to_use;
+	struct cb *cb_to_send;
+	struct cb *cb_to_clean;
+	u16 tx_command;
+	/* End: frequently used values: keep adjacent for cache effect */
+
+	enum {
+		ich           = (1 << 0),
+		promiscuous   = (1 << 1),
+		multicast_all = (1 << 2),
+		wol_magic     = (1 << 3),
+	} flags					____cacheline_aligned;
+
+	enum mac mac;
+	enum phy phy;
+	struct params params;
+	struct net_device_stats net_stats;
+	struct timer_list watchdog;
+	struct timer_list blink_timer;
+	struct mii_if_info mii;
+	enum loopback loopback;
+
+	struct mem *mem;
+	dma_addr_t dma_addr;
+
+	dma_addr_t cbs_dma_addr;
+	u8 adaptive_ifs;
+	u8 tx_threshold;
+	u32 tx_frames;
+	u32 tx_collisions;
+	u32 tx_deferred;
+	u32 tx_single_collisions;
+	u32 tx_multiple_collisions;
+	u32 tx_fc_pause;
+	u32 tx_tco_frames;
+
+	u32 rx_fc_pause;
+	u32 rx_fc_unsupported;
+	u32 rx_tco_frames;
+
+	u8 rev_id;
+	u16 leds;
+	u16 eeprom_wc;
+	u16 eeprom[256];
+	u32 pm_state[16];
+};
+
+static inline void e100_write_flush(struct nic *nic)
+{
+	/* Flush previous PCI writes through intermediate bridges
+	 * by doing a benign read */
+	(void)readb(&nic->csr->scb.status);
+}
+
+static inline void e100_enable_irq(struct nic *nic)
+{
+	writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+}
+
+static inline void e100_disable_irq(struct nic *nic)
+{
+	writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+}
+
+static void e100_hw_reset(struct nic *nic)
+{
+	/* Put CU and RU into idle with a selective reset to get
+	 * device off of PCI bus */
+	writel(selective_reset, &nic->csr->port);
+	e100_write_flush(nic); udelay(20);
+
+	/* Now fully reset device */
+	writel(software_reset, &nic->csr->port);
+	e100_write_flush(nic); udelay(20);
+
+	/* TCO workaround - 82559 and greater */
+	if(nic->mac >= mac_82559_D101M) {
+		/* Issue a redundant CU load base without setting
+		 * general pointer, and without waiting for scb to
+		 * clear.  This gets us into post-driver.  Finally,
+		 * wait 20 msec for reset to take effect. */
+		writeb(cuc_load_base, &nic->csr->scb.cmd_lo);
+		mdelay(20);
+	}
+
+	/* Mask off our interrupt line - it's unmasked after reset */
+	e100_disable_irq(nic);
+}
+
+static int e100_self_test(struct nic *nic)
+{
+	u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest);
+
+	/* Passing the self-test is a pretty good indication
+	 * that the device can DMA to/from host memory */
+
+	nic->mem->selftest.signature = 0;
+	nic->mem->selftest.result = 0xFFFFFFFF;
+
+	writel(selftest | dma_addr, &nic->csr->port);
+	e100_write_flush(nic);
+	/* Wait 10 msec for self-test to complete */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 100 + 1);
+
+	/* Interrupts are enabled after self-test */
+	e100_disable_irq(nic);
+
+	/* Check results of self-test */
+	if(nic->mem->selftest.result != 0) {
+		DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",
+			nic->mem->selftest.result);
+		return -ETIMEDOUT;
+	}
+	if(nic->mem->selftest.signature == 0) {
+		DPRINTK(HW, ERR, "Self-test failed: timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
+{
+	u32 cmd_addr_data[3];
+	u8 ctrl;
+	int i, j;
+
+	/* Three cmds: write/erase enable, write data, write/erase disable */
+	cmd_addr_data[0] = op_ewen << (addr_len - 2);
+	cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data;
+	cmd_addr_data[2] = op_ewds << (addr_len - 2);
+
+	/* Bit-bang cmds to write word to eeprom */
+	for(j = 0; j < 3; j++) {
+
+		/* Chip select */
+		writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+
+		for(i = 31; i >= 0; i--) {
+			ctrl = (cmd_addr_data[j] & (1 << i)) ?
+				eecs | eedi : eecs;
+			writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+			e100_write_flush(nic); udelay(4);
+			writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+			e100_write_flush(nic); udelay(4);
+		}
+		/* Wait 10 msec for cmd to complete */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 100 + 1);
+
+		/* Chip deselect */
+		writeb(0, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+	}
+
+};
+
+/* General technique stolen from the eepro100 driver - very clever */
+static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
+{
+	u32 cmd_addr_data;
+	u16 data = 0;
+	u8 ctrl;
+	int i;
+
+	cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
+
+	/* Chip select */
+	writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+	e100_write_flush(nic); udelay(4);
+
+	/* Bit-bang to read word from eeprom */
+	for(i = 31; i >= 0; i--) {
+		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
+		writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+		writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+		/* Eeprom drives a dummy zero to EEDO after receiving
+		 * complete address.  Use this to adjust addr_len. */
+		ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+		if(!(ctrl & eedo) && i > 16) {
+			*addr_len -= (i - 16);
+			i = 17;
+		}
+		data = (data << 1) | (ctrl & eedo ? 1 : 0);
+	}
+
+	/* Chip deselect */
+	writeb(0, &nic->csr->eeprom_ctrl_lo);
+	e100_write_flush(nic); udelay(4);
+
+	return data;
+};
+
+/* Load entire EEPROM image into driver cache and validate checksum */
+static int e100_eeprom_load(struct nic *nic)
+{
+	u16 addr, addr_len = 8, checksum = 0;
+
+	/* Try reading with an 8-bit addr len to discover actual addr len */
+	e100_eeprom_read(nic, &addr_len, 0);
+	nic->eeprom_wc = 1 << addr_len;
+
+	for(addr = 0; addr < nic->eeprom_wc; addr++) {
+		nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
+		if(addr < nic->eeprom_wc - 1)
+			checksum += nic->eeprom[addr];
+	}
+
+	/* The checksum, stored in the last word, is calculated such that
+	 * the sum of words should be 0xBABA */
+	checksum = 0xBABA - checksum;
+	if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
+		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/* Save (portion of) driver EEPROM cache to device and update checksum */
+static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
+{
+	u16 addr, addr_len = 8, checksum = 0;
+
+	/* Try reading with an 8-bit addr len to discover actual addr len */
+	e100_eeprom_read(nic, &addr_len, 0);
+	nic->eeprom_wc = 1 << addr_len;
+
+	if(start + count >= nic->eeprom_wc)
+		return -EINVAL;
+
+	for(addr = start; addr < start + count; addr++)
+		e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]);
+
+	/* The checksum, stored in the last word, is calculated such that
+	 * the sum of words should be 0xBABA */
+	for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
+		checksum += nic->eeprom[addr];
+	nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum;
+	e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum);
+
+	return 0;
+}
+
+#define E100_WAIT_SCB_TIMEOUT 40
+static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
+{
+	unsigned long flags;
+	unsigned int i;
+	int err = 0;
+
+	spin_lock_irqsave(&nic->cmd_lock, flags);
+
+	/* Previous command is accepted when SCB clears */
+	for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
+		if(likely(!readb(&nic->csr->scb.cmd_lo)))
+			break;
+		cpu_relax();
+		if(unlikely(i > (E100_WAIT_SCB_TIMEOUT >> 1)))
+			udelay(5);
+	}
+	if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
+		err = -EAGAIN;
+		goto err_unlock;
+	}
+
+	if(unlikely(cmd != cuc_resume))
+		writel(dma_addr, &nic->csr->scb.gen_ptr);
+	writeb(cmd, &nic->csr->scb.cmd_lo);
+
+err_unlock:
+	spin_unlock_irqrestore(&nic->cmd_lock, flags);
+
+	return err;
+}
+
+static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
+	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
+{
+	struct cb *cb;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&nic->cb_lock, flags);
+
+	if(unlikely(!nic->cbs_avail)) {
+		err = -ENOMEM;
+		goto err_unlock;
+	}
+
+	cb = nic->cb_to_use;
+	nic->cb_to_use = cb->next;
+	nic->cbs_avail--;
+	cb->skb = skb;
+
+	if(unlikely(!nic->cbs_avail))
+		err = -ENOSPC;
+
+	cb_prepare(nic, cb, skb);
+
+	/* Order is important otherwise we'll be in a race with h/w:
+	 * set S-bit in current first, then clear S-bit in previous. */
+	cb->command |= cpu_to_le16(cb_s);
+	cb->prev->command &= cpu_to_le16(~cb_s);
+
+	while(nic->cb_to_send != nic->cb_to_use) {
+		if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd,
+			nic->cb_to_send->dma_addr)))) {
+			/* Ok, here's where things get sticky.  It's
+			 * possible that we can't schedule the command
+			 * because the controller is too busy, so
+			 * let's just queue the command and try again
+			 * when another command is scheduled. */
+			break;
+		} else {
+			nic->cuc_cmd = cuc_resume;
+			nic->cb_to_send = nic->cb_to_send->next;
+		}
+	}
+
+err_unlock:
+	spin_unlock_irqrestore(&nic->cb_lock, flags);
+
+	return err;
+}
+
+static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
+{
+	u32 data_out = 0;
+	unsigned int i;
+
+	writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+
+	for(i = 0; i < 100; i++) {
+		udelay(20);
+		if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+			break;
+	}
+
+	DPRINTK(HW, DEBUG,
+		"%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
+		dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
+	return (u16)data_out;
+}
+
+static int mdio_read(struct net_device *netdev, int addr, int reg)
+{
+	return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0);
+}
+
+static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
+{
+	mdio_ctrl(netdev->priv, addr, mdi_write, reg, data);
+}
+
+static void e100_get_defaults(struct nic *nic)
+{
+	struct param_range rfds = { .min = 64, .max = 256, .count = 64 };
+	struct param_range cbs  = { .min = 64, .max = 256, .count = 64 };
+
+	pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
+	/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
+	nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id;
+	if(nic->mac == mac_unknown)
+		nic->mac = mac_82557_D100_A;
+
+	nic->params.rfds = rfds;
+	nic->params.cbs = cbs;
+
+	/* Quadwords to DMA into FIFO before starting frame transmit */
+	nic->tx_threshold = 0xE0;
+
+	nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf |
+		((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0));
+
+	/* Template for a freshly allocated RFD */
+	nic->blank_rfd.command = cpu_to_le16(cb_el);
+	nic->blank_rfd.rbd = 0xFFFFFFFF;
+	nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
+
+	/* MII setup */
+	nic->mii.phy_id_mask = 0x1F;
+	nic->mii.reg_num_mask = 0x1F;
+	nic->mii.dev = nic->netdev;
+	nic->mii.mdio_read = mdio_read;
+	nic->mii.mdio_write = mdio_write;
+}
+
+static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	struct config *config = &cb->u.config;
+	u8 *c = (u8 *)config;
+
+	cb->command = cpu_to_le16(cb_config);
+
+	memset(config, 0, sizeof(struct config));
+
+	config->byte_count = 0x16;		/* bytes in this struct */
+	config->rx_fifo_limit = 0x8;		/* bytes in FIFO before DMA */
+	config->direct_rx_dma = 0x1;		/* reserved */
+	config->standard_tcb = 0x1;		/* 1=standard, 0=extended */
+	config->standard_stat_counter = 0x1;	/* 1=standard, 0=extended */
+	config->rx_discard_short_frames = 0x1;	/* 1=discard, 0=pass */
+	config->tx_underrun_retry = 0x3;	/* # of underrun retries */
+	config->mii_mode = 0x1;			/* 1=MII mode, 0=503 mode */
+	config->pad10 = 0x6;
+	config->no_source_addr_insertion = 0x1;	/* 1=no, 0=yes */
+	config->preamble_length = 0x2;		/* 0=1, 1=3, 2=7, 3=15 bytes */
+	config->ifs = 0x6;			/* x16 = inter frame spacing */
+	config->ip_addr_hi = 0xF2;		/* ARP IP filter - not used */
+	config->pad15_1 = 0x1;
+	config->pad15_2 = 0x1;
+	config->crs_or_cdt = 0x0;		/* 0=CRS only, 1=CRS or CDT */
+	config->fc_delay_hi = 0x40;		/* time delay for fc frame */
+	config->tx_padding = 0x1;		/* 1=pad short frames */
+	config->fc_priority_threshold = 0x7;	/* 7=priority fc disabled */
+	config->pad18 = 0x1;
+	config->full_duplex_pin = 0x1;		/* 1=examine FDX# pin */
+	config->pad20_1 = 0x1F;
+	config->fc_priority_location = 0x1;	/* 1=byte#31, 0=byte#19 */
+	config->pad21_1 = 0x5;
+
+	config->adaptive_ifs = nic->adaptive_ifs;
+	config->loopback = nic->loopback;
+
+	if(nic->mii.force_media && nic->mii.full_duplex)
+		config->full_duplex_force = 0x1;	/* 1=force, 0=auto */
+
+	if(nic->flags & promiscuous || nic->loopback) {
+		config->rx_save_bad_frames = 0x1;	/* 1=save, 0=discard */
+		config->rx_discard_short_frames = 0x0;	/* 1=discard, 0=save */
+		config->promiscuous_mode = 0x1;		/* 1=on, 0=off */
+	}
+
+	if(nic->flags & multicast_all)
+		config->multicast_all = 0x1;		/* 1=accept, 0=no */
+
+	if(!(nic->flags & wol_magic))
+		config->magic_packet_disable = 0x1;	/* 1=off, 0=on */
+
+	if(nic->mac >= mac_82558_D101_A4) {
+		config->fc_disable = 0x1;	/* 1=Tx fc off, 0=Tx fc on */
+		config->mwi_enable = 0x1;	/* 1=enable, 0=disable */
+		config->standard_tcb = 0x0;	/* 1=standard, 0=extended */
+		config->rx_long_ok = 0x1;	/* 1=VLANs ok, 0=standard */
+		if(nic->mac >= mac_82559_D101M)
+			config->tno_intr = 0x1;		/* TCO stats enable */
+		else
+			config->standard_stat_counter = 0x0;
+	}
+
+	DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+	DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
+	DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+}
+
+static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
+	struct sk_buff *skb)
+{
+	cb->command = cpu_to_le16(cb_iaaddr);
+	memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN);
+}
+
+static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	cb->command = cpu_to_le16(cb_dump);
+	cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr +
+		offsetof(struct mem, dump_buf));
+}
+
+#define NCONFIG_AUTO_SWITCH	0x0080
+#define MII_NSC_CONG		MII_RESV1
+#define NSC_CONG_ENABLE		0x0100
+#define NSC_CONG_TXREADY	0x0400
+#define ADVERTISE_FC_SUPPORTED	0x0400
+static int e100_phy_init(struct nic *nic)
+{
+	struct net_device *netdev = nic->netdev;
+	u32 addr;
+	u16 bmcr, stat, id_lo, id_hi, cong;
+
+	/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
+	for(addr = 0; addr < 32; addr++) {
+		nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
+		bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
+		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
+		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
+		if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
+			break;
+	}
+	DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
+	if(addr == 32)
+		return -EAGAIN;
+
+	/* Selected the phy and isolate the rest */
+	for(addr = 0; addr < 32; addr++) {
+		if(addr != nic->mii.phy_id) {
+			mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
+		} else {
+			bmcr = mdio_read(netdev, addr, MII_BMCR);
+			mdio_write(netdev, addr, MII_BMCR,
+				bmcr & ~BMCR_ISOLATE);
+		}
+	}
+
+	/* Get phy ID */
+	id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
+	id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);
+	nic->phy = (u32)id_hi << 16 | (u32)id_lo;
+	DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
+
+	/* Handle National tx phy */
+	if(nic->phy == phy_nsc_tx) {
+		/* Disable congestion control */
+		cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG);
+		cong |= NSC_CONG_TXREADY;
+		cong &= ~NSC_CONG_ENABLE;
+		mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
+	}
+
+	if(nic->mac >= mac_82550_D102)
+		/* enable/disable MDI/MDI-X auto-switching */
+		mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
+			nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+
+	return 0;
+}
+
+static int e100_hw_init(struct nic *nic)
+{
+	int err;
+
+	e100_hw_reset(nic);
+
+	DPRINTK(HW, ERR, "e100_hw_init\n");
+	if(!in_interrupt() && (err = e100_self_test(nic)))
+		return err;
+
+	if((err = e100_phy_init(nic)))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_load_base, 0)))
+		return err;
+	if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
+		return err;
+	if((err = e100_exec_cb(nic, NULL, e100_configure)))
+		return err;
+	if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_dump_addr,
+		nic->dma_addr + offsetof(struct mem, stats))))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_dump_reset, 0)))
+		return err;
+
+	e100_disable_irq(nic);
+
+	return 0;
+}
+
+static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	struct net_device *netdev = nic->netdev;
+	struct dev_mc_list *list = netdev->mc_list;
+	u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS);
+
+	cb->command = cpu_to_le16(cb_multi);
+	cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
+	for(i = 0; list && i < count; i++, list = list->next)
+		memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,
+			ETH_ALEN);
+}
+
+static void e100_set_multicast_list(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+
+	DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
+		netdev->mc_count, netdev->flags);
+
+	if(netdev->flags & IFF_PROMISC)
+		nic->flags |= promiscuous;
+	else
+		nic->flags &= ~promiscuous;
+
+	if(netdev->flags & IFF_ALLMULTI ||
+		netdev->mc_count > E100_MAX_MULTICAST_ADDRS)
+		nic->flags |= multicast_all;
+	else
+		nic->flags &= ~multicast_all;
+
+	e100_exec_cb(nic, NULL, e100_configure);
+	e100_exec_cb(nic, NULL, e100_multi);
+}
+
+static void e100_update_stats(struct nic *nic)
+{
+	struct net_device_stats *ns = &nic->net_stats;
+	struct stats *s = &nic->mem->stats;
+	u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
+		(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
+		&s->complete;
+
+	/* Device's stats reporting may take several microseconds to
+	 * complete, so where always waiting for results of the
+	 * previous command. */
+
+	if(*complete == le32_to_cpu(0x0000A007)) {
+		*complete = 0;
+		nic->tx_frames = le32_to_cpu(s->tx_good_frames);
+		nic->tx_collisions = le32_to_cpu(s->tx_total_collisions);
+		ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions);
+		ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions);
+		ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs);
+		ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns);
+		ns->collisions += nic->tx_collisions;
+		ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +
+			le32_to_cpu(s->tx_lost_crs);
+		ns->rx_dropped += le32_to_cpu(s->rx_resource_errors);
+		ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors);
+		ns->rx_over_errors += le32_to_cpu(s->rx_resource_errors);
+		ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);
+		ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);
+		ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);
+		ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +
+			le32_to_cpu(s->rx_alignment_errors) +
+			le32_to_cpu(s->rx_short_frame_errors) +
+			le32_to_cpu(s->rx_cdt_errors);
+		nic->tx_deferred += le32_to_cpu(s->tx_deferred);
+		nic->tx_single_collisions +=
+			le32_to_cpu(s->tx_single_collisions);
+		nic->tx_multiple_collisions +=
+			le32_to_cpu(s->tx_multiple_collisions);
+		if(nic->mac >= mac_82558_D101_A4) {
+			nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause);
+			nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause);
+			nic->rx_fc_unsupported +=
+				le32_to_cpu(s->fc_rcv_unsupported);
+			if(nic->mac >= mac_82559_D101M) {
+				nic->tx_tco_frames +=
+					le16_to_cpu(s->xmt_tco_frames);
+				nic->rx_tco_frames +=
+					le16_to_cpu(s->rcv_tco_frames);
+			}
+		}
+	}
+
+	e100_exec_cmd(nic, cuc_dump_reset, 0);
+}
+
+static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
+{
+	/* Adjust inter-frame-spacing (IFS) between two transmits if
+	 * we're getting collisions on a half-duplex connection. */
+
+	if(duplex == DUPLEX_HALF) {
+		u32 prev = nic->adaptive_ifs;
+		u32 min_frames = (speed == SPEED_100) ? 1000 : 100;
+
+		if((nic->tx_frames / 32 < nic->tx_collisions) &&
+		   (nic->tx_frames > min_frames)) {
+			if(nic->adaptive_ifs < 60)
+				nic->adaptive_ifs += 5;
+		} else if (nic->tx_frames < min_frames) {
+			if(nic->adaptive_ifs >= 5)
+				nic->adaptive_ifs -= 5;
+		}
+		if(nic->adaptive_ifs != prev)
+			e100_exec_cb(nic, NULL, e100_configure);
+	}
+}
+
+static void e100_watchdog(unsigned long data)
+{
+	struct nic *nic = (struct nic *)data;
+	struct ethtool_cmd cmd;
+
+	DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies);
+
+	/* mii library handles link maintenance tasks */
+
+	mii_ethtool_gset(&nic->mii, &cmd);
+
+	if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
+		DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n",
+			cmd.speed == SPEED_100 ? "100" : "10",
+			cmd.duplex == DUPLEX_FULL ? "full" : "half");
+	} else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
+		DPRINTK(LINK, INFO, "link down\n");
+	}
+
+	mii_check_link(&nic->mii);
+
+	/* Software generated interrupt to recover from (rare) Rx
+	 * allocation failure */
+	writeb(irq_sw_gen, &nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+
+	e100_update_stats(nic);
+	e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
+
+	if(nic->mac <= mac_82557_D100_C)
+		/* Issue a multicast command to workaround a 557 lock up */
+		e100_set_multicast_list(nic->netdev);
+
+	mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
+}
+
+static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+	struct sk_buff *skb)
+{
+	cb->command = nic->tx_command;
+	cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
+	cb->u.tcb.tcb_byte_count = 0;
+	cb->u.tcb.threshold = nic->tx_threshold;
+	cb->u.tcb.tbd_count = 1;
+	cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
+		skb->data, skb->len, PCI_DMA_TODEVICE));
+	cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
+}
+
+static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	int err = e100_exec_cb(nic, skb, e100_xmit_prepare);
+
+	switch(err) {
+	case -ENOSPC:
+		/* We queued the skb, but now we're out of space. */
+		netif_stop_queue(netdev);
+		break;
+	case -ENOMEM:
+		/* This is a hard error - log it. */
+		DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");
+		netif_stop_queue(netdev);
+		return 1;
+	}
+
+	netdev->trans_start = jiffies;
+	return 0;
+}
+
+static inline int e100_tx_clean(struct nic *nic)
+{
+	struct cb *cb;
+	int tx_cleaned = 0;
+
+	spin_lock(&nic->cb_lock);
+
+	DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n",
+		nic->cb_to_clean->status);
+
+	/* Clean CBs marked complete */
+	for(cb = nic->cb_to_clean;
+	    cb->status & cpu_to_le16(cb_complete);
+	    cb = nic->cb_to_clean = cb->next) {
+		if(likely(cb->skb)) {
+			nic->net_stats.tx_packets++;
+			nic->net_stats.tx_bytes += cb->skb->len;
+
+			pci_unmap_single(nic->pdev,
+				le32_to_cpu(cb->u.tcb.tbd.buf_addr),
+				le16_to_cpu(cb->u.tcb.tbd.size),
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb_any(cb->skb);
+			tx_cleaned = 1;
+		}
+		cb->status = 0;
+		nic->cbs_avail++;
+	}
+
+	spin_unlock(&nic->cb_lock);
+
+	/* Recover from running out of Tx resources in xmit_frame */
+	if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev)))
+		netif_wake_queue(nic->netdev);
+
+	return tx_cleaned;
+}
+
+static void e100_clean_cbs(struct nic *nic)
+{
+	if(nic->cbs) {
+		while(nic->cb_to_clean != nic->cb_to_use) {
+			struct cb *cb = nic->cb_to_clean;
+			if(cb->skb) {
+				pci_unmap_single(nic->pdev,
+					le32_to_cpu(cb->u.tcb.tbd.buf_addr),
+					le16_to_cpu(cb->u.tcb.tbd.size),
+					PCI_DMA_TODEVICE);
+				dev_kfree_skb(cb->skb);
+			}
+			nic->cb_to_clean = nic->cb_to_clean->next;
+		}
+		nic->cbs_avail = nic->params.cbs.count;
+		pci_free_consistent(nic->pdev,
+			sizeof(struct cb) * nic->params.cbs.count,
+			nic->cbs, nic->cbs_dma_addr);
+		nic->cbs = NULL;
+		nic->cbs_avail = 0;
+	}
+	nic->cuc_cmd = cuc_start;
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean =
+		nic->cbs;
+}
+
+static int e100_alloc_cbs(struct nic *nic)
+{
+	struct cb *cb;
+	unsigned int i, count = nic->params.cbs.count;
+
+	nic->cuc_cmd = cuc_start;
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;
+	nic->cbs_avail = 0;
+
+	nic->cbs = pci_alloc_consistent(nic->pdev,
+		sizeof(struct cb) * count, &nic->cbs_dma_addr);
+	if(!nic->cbs)
+		return -ENOMEM;
+
+	for(cb = nic->cbs, i = 0; i < count; cb++, i++) {
+		cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
+		cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1;
+
+		cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
+		cb->link = cpu_to_le32(nic->cbs_dma_addr +
+			((i+1) % count) * sizeof(struct cb));
+	}
+
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
+	nic->cbs_avail = count;
+
+	return 0;
+}
+
+static inline void e100_start_receiver(struct nic *nic)
+{
+	/* (Re)start RU if suspended or idle and RFA is non-NULL */
+	if(!nic->ru_running && nic->rx_to_clean->skb) {
+		e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
+		nic->ru_running = 1;
+	}
+}
+
+#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
+static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+{
+	unsigned int rx_offset = 2; /* u32 align protocol headers */
+
+	if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + rx_offset)))
+		return -ENOMEM;
+
+	/* Align, init, and map the RFA. */
+	rx->skb->dev = nic->netdev;
+	skb_reserve(rx->skb, rx_offset);
+	memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
+	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
+		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+	/* Link the RFD to end of RFA by linking previous RFD to
+	 * this one, and clearing EL bit of previous.  */
+	if(rx->prev->skb) {
+		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
+		put_unaligned(cpu_to_le32(rx->dma_addr),
+			(u32 *)&prev_rfd->link);
+		prev_rfd->command &= ~cpu_to_le16(cb_el);
+		pci_dma_sync_single(nic->pdev, rx->prev->dma_addr,
+			sizeof(struct rfd), PCI_DMA_TODEVICE);
+	}
+
+	return 0;
+}
+
+static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
+	unsigned int *work_done, unsigned int work_to_do)
+{
+	struct sk_buff *skb = rx->skb;
+	struct rfd *rfd = (struct rfd *)skb->data;
+	u16 rfd_status, actual_size;
+
+	if(unlikely(work_done && *work_done >= work_to_do))
+		return -EAGAIN;
+
+	/* Need to sync before taking a peek at cb_complete bit */
+	pci_dma_sync_single(nic->pdev, rx->dma_addr,
+		sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+	rfd_status = le16_to_cpu(rfd->status);
+
+	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
+
+	/* If data isn't ready, nothing to indicate */
+	if(unlikely(!(rfd_status & cb_complete)))
+       		return -EAGAIN;
+
+	/* Get actual data size */
+	actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
+	if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd)))
+		actual_size = RFD_BUF_LEN - sizeof(struct rfd);
+
+	/* Get data */
+	pci_dma_sync_single(nic->pdev, rx->dma_addr,
+		sizeof(struct rfd) + actual_size,
+		PCI_DMA_FROMDEVICE);
+	pci_unmap_single(nic->pdev, rx->dma_addr,
+		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+	/* Pull off the RFD and put the actual data (minus eth hdr) */
+	skb_reserve(skb, sizeof(struct rfd));
+	skb_put(skb, actual_size);
+	skb->protocol = eth_type_trans(skb, nic->netdev);
+
+	if(unlikely(!(rfd_status & cb_ok)) ||
+	   actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) {
+		/* Don't indicate if errors */
+		dev_kfree_skb_any(skb);
+	} else {
+		nic->net_stats.rx_packets++;
+		nic->net_stats.rx_bytes += actual_size;
+		nic->netdev->last_rx = jiffies;
+#ifdef CONFIG_E100_NAPI
+		netif_receive_skb(skb);
+#else
+		netif_rx(skb);
+#endif
+		if(work_done)
+			(*work_done)++;
+	}
+
+	rx->skb = NULL;
+
+	return 0;
+}
+
+static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
+	unsigned int work_to_do)
+{
+	struct rx *rx;
+
+	/* Indicate newly arrived packets */
+	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
+		if(e100_rx_indicate(nic, rx, work_done, work_to_do))
+			break; /* No more to clean */
+	}
+
+	/* Alloc new skbs to refill list */
+	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
+		if(unlikely(e100_rx_alloc_skb(nic, rx)))
+			break; /* Better luck next time (see watchdog) */
+	}
+
+	e100_start_receiver(nic);
+}
+
+static void e100_rx_clean_list(struct nic *nic)
+{
+	struct rx *rx;
+	unsigned int i, count = nic->params.rfds.count;
+
+	if(nic->rxs) {
+		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
+			if(rx->skb) {
+				pci_unmap_single(nic->pdev, rx->dma_addr,
+					RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(rx->skb);
+			}
+		}
+		kfree(nic->rxs);
+		nic->rxs = NULL;
+	}
+
+	nic->rx_to_use = nic->rx_to_clean = NULL;
+	nic->ru_running = 0;
+}
+
+static int e100_rx_alloc_list(struct nic *nic)
+{
+	struct rx *rx;
+	unsigned int i, count = nic->params.rfds.count;
+
+	nic->rx_to_use = nic->rx_to_clean = NULL;
+
+	if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
+		return -ENOMEM;
+	memset(nic->rxs, 0, sizeof(struct rx) * count);
+
+	for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
+		rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
+		rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;
+		if(e100_rx_alloc_skb(nic, rx)) {
+			e100_rx_clean_list(nic);
+			return -ENOMEM;
+		}
+	}
+
+	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
+
+	return 0;
+}
+
+static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *netdev = dev_id;
+	struct nic *nic = netdev->priv;
+	u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+
+	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
+
+	if(stat_ack == stat_ack_not_ours ||	/* Not our interrupt */
+	   stat_ack == stat_ack_not_present)	/* Hardware is ejected */
+		return IRQ_NONE;
+
+	/* Ack interrupt(s) */
+	writeb(stat_ack, &nic->csr->scb.stat_ack);
+
+	/* We hit Receive No Resource (RNR); restart RU after cleaning */
+	if(stat_ack & stat_ack_rnr)
+		nic->ru_running = 0;
+
+#ifdef CONFIG_E100_NAPI
+	e100_disable_irq(nic);
+	netif_rx_schedule(netdev);
+#else
+	if(stat_ack & stat_ack_rx)
+		e100_rx_clean(nic, NULL, 0);
+	if(stat_ack & stat_ack_tx)
+		e100_tx_clean(nic);
+#endif
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_E100_NAPI
+static int e100_poll(struct net_device *netdev, int *budget)
+{
+	struct nic *nic = netdev->priv;
+	unsigned int work_to_do = min(netdev->quota, *budget);
+	unsigned int work_done = 0;
+	int tx_cleaned;
+
+	e100_rx_clean(nic, &work_done, work_to_do);
+	tx_cleaned = e100_tx_clean(nic);
+
+	/* If no Rx and Tx cleanup work was done, exit polling mode. */
+	if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+		netif_rx_complete(netdev);
+		e100_enable_irq(nic);
+		return 0;
+	}
+
+	*budget -= work_done;
+	netdev->quota -= work_done;
+
+	return 1;
+}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void e100_netpoll(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	e100_disable_irq(nic);
+	e100_intr(nic->pdev->irq, netdev, NULL);
+	e100_enable_irq(nic);
+}
+#endif
+
+static struct net_device_stats *e100_get_stats(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	return &nic->net_stats;
+}
+
+static int e100_set_mac_address(struct net_device *netdev, void *p)
+{
+	struct nic *nic = netdev->priv;
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	e100_exec_cb(nic, NULL, e100_setup_iaaddr);
+
+	return 0;
+}
+
+static int e100_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)
+		return -EINVAL;
+	netdev->mtu = new_mtu;
+	return 0;
+}
+
+static int e100_asf(struct nic *nic)
+{
+	/* ASF can be enabled from eeprom */
+	return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) &&
+	   (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
+	   !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
+	   ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
+}
+
+static int e100_up(struct nic *nic)
+{
+	int err;
+
+	if((err = e100_rx_alloc_list(nic)))
+		return err;
+	if((err = e100_alloc_cbs(nic)))
+		goto err_rx_clean_list;
+	if((err = e100_hw_init(nic)))
+		goto err_clean_cbs;
+	e100_set_multicast_list(nic->netdev);
+	e100_start_receiver(nic);
+	netif_start_queue(nic->netdev);
+	mod_timer(&nic->watchdog, jiffies);
+	if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
+		nic->netdev->name, nic->netdev)))
+		goto err_no_irq;
+	e100_enable_irq(nic);
+	return 0;
+
+err_no_irq:
+	del_timer_sync(&nic->watchdog);
+	netif_stop_queue(nic->netdev);
+err_clean_cbs:
+	e100_clean_cbs(nic);
+err_rx_clean_list:
+	e100_rx_clean_list(nic);
+	return err;
+}
+
+static void e100_down(struct nic *nic)
+{
+	e100_hw_reset(nic);
+	free_irq(nic->pdev->irq, nic->netdev);
+	del_timer_sync(&nic->watchdog);
+	netif_carrier_off(nic->netdev);
+	netif_stop_queue(nic->netdev);
+	e100_clean_cbs(nic);
+	e100_rx_clean_list(nic);
+}
+
+static void e100_tx_timeout(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+
+	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
+		readb(&nic->csr->scb.status));
+	e100_down(netdev->priv);
+	e100_up(netdev->priv);
+}
+
+static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
+{
+	int err;
+	struct sk_buff *skb;
+
+	/* Use driver resources to perform internal MAC or PHY
+	 * loopback test.  A single packet is prepared and transmitted
+	 * in loopback mode, and the test passes if the received
+	 * packet compares byte-for-byte to the transmitted packet. */
+
+	if((err = e100_rx_alloc_list(nic)))
+		return err;
+	if((err = e100_alloc_cbs(nic)))
+		goto err_clean_rx;
+
+	/* ICH PHY loopback is broken so do MAC loopback instead */
+	if(nic->flags & ich && loopback_mode == lb_phy)
+		loopback_mode = lb_mac;
+
+	nic->loopback = loopback_mode;
+	if((err = e100_hw_init(nic)))
+		goto err_loopback_none;
+
+	if(loopback_mode == lb_phy)
+		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
+			BMCR_LOOPBACK);
+
+	e100_start_receiver(nic);
+
+	if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
+		err = -ENOMEM;
+		goto err_loopback_none;
+	}
+	skb_put(skb, ETH_DATA_LEN);
+	memset(skb->data, 0xFF, ETH_DATA_LEN);
+	e100_xmit_frame(skb, nic->netdev);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 100 + 1);
+
+	if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
+	   skb->data, ETH_DATA_LEN))
+       		err = -EAGAIN;
+
+err_loopback_none:
+	mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0);
+	nic->loopback = lb_none;
+	e100_hw_init(nic);
+	e100_clean_cbs(nic);
+err_clean_rx:
+	e100_rx_clean_list(nic);
+	return err;
+}
+
+#define MII_LED_CONTROL	0x1B
+static void e100_blink_led(unsigned long data)
+{
+	struct nic *nic = (struct nic *)data;
+	enum led_state {
+		led_on     = 0x01,
+		led_off    = 0x04,
+		led_on_559 = 0x05,
+		led_on_557 = 0x07,
+	};
+
+	nic->leds = (nic->leds & led_on) ? led_off :
+		(nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
+	mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds);
+	mod_timer(&nic->blink_timer, jiffies + HZ / 4);
+}
+
+static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct nic *nic = netdev->priv;
+	return mii_ethtool_gset(&nic->mii, cmd);
+}
+
+static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct nic *nic = netdev->priv;
+	int err;
+
+	mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
+	err = mii_ethtool_sset(&nic->mii, cmd);
+	e100_exec_cb(nic, NULL, e100_configure);
+
+	return err;
+}
+
+static void e100_get_drvinfo(struct net_device *netdev,
+	struct ethtool_drvinfo *info)
+{
+	struct nic *nic = netdev->priv;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->fw_version, "N/A");
+	strcpy(info->bus_info, pci_name(nic->pdev));
+}
+
+static int e100_get_regs_len(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+#define E100_PHY_REGS		0x1C
+#define E100_REGS_LEN		1 + E100_PHY_REGS + \
+	sizeof(nic->mem->dump_buf) / sizeof(u32)
+	return E100_REGS_LEN * sizeof(u32);
+}
+
+static void e100_get_regs(struct net_device *netdev,
+	struct ethtool_regs *regs, void *p)
+{
+	struct nic *nic = netdev->priv;
+	u32 *buff = p;
+	int i;
+
+	regs->version = (1 << 24) | nic->rev_id;
+	buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
+		readb(&nic->csr->scb.cmd_lo) << 16 |
+		readw(&nic->csr->scb.status);
+	for(i = E100_PHY_REGS; i >= 0; i--)
+		buff[1 + E100_PHY_REGS - i] =
+			mdio_read(netdev, nic->mii.phy_id, i);
+	memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
+	e100_exec_cb(nic, NULL, e100_dump);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 100 + 1);
+	memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
+		sizeof(nic->mem->dump_buf));
+}
+
+static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct nic *nic = netdev->priv;
+	wol->supported = (nic->mac >= mac_82558_D101_A4) ?  WAKE_MAGIC : 0;
+	wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0;
+}
+
+static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct nic *nic = netdev->priv;
+
+	if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+		return -EOPNOTSUPP;
+
+	if(wol->wolopts)
+		nic->flags |= wol_magic;
+	else
+		nic->flags &= ~wol_magic;
+
+	pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+	e100_exec_cb(nic, NULL, e100_configure);
+
+	return 0;
+}
+
+static u32 e100_get_msglevel(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	return nic->msg_enable;
+}
+
+static void e100_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct nic *nic = netdev->priv;
+	nic->msg_enable = value;
+}
+
+static int e100_nway_reset(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	return mii_nway_restart(&nic->mii);
+}
+
+static u32 e100_get_link(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	return mii_link_ok(&nic->mii);
+}
+
+static int e100_get_eeprom_len(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	return nic->eeprom_wc << 1;
+}
+
+#define E100_EEPROM_MAGIC	0x1234
+static int e100_get_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct nic *nic = netdev->priv;
+
+	eeprom->magic = E100_EEPROM_MAGIC;
+	memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len);
+
+	return 0;
+}
+
+static int e100_set_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct nic *nic = netdev->priv;
+
+	if(eeprom->magic != E100_EEPROM_MAGIC)
+		return -EINVAL;
+	memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
+
+	return e100_eeprom_save(nic, eeprom->offset >> 1,
+		(eeprom->len >> 1) + 1);
+}
+
+static void e100_get_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ring)
+{
+	struct nic *nic = netdev->priv;
+	struct param_range *rfds = &nic->params.rfds;
+	struct param_range *cbs = &nic->params.cbs;
+
+	ring->rx_max_pending = rfds->max;
+	ring->tx_max_pending = cbs->max;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rfds->count;
+	ring->tx_pending = cbs->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int e100_set_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ring)
+{
+	struct nic *nic = netdev->priv;
+	struct param_range *rfds = &nic->params.rfds;
+	struct param_range *cbs = &nic->params.cbs;
+
+	if(netif_running(netdev))
+		e100_down(nic);
+	rfds->count = max(ring->rx_pending, rfds->min);
+	rfds->count = min(rfds->count, rfds->max);
+	cbs->count = max(ring->tx_pending, cbs->min);
+	cbs->count = min(cbs->count, cbs->max);
+	if(netif_running(netdev))
+		e100_up(nic);
+
+	return 0;
+}
+
+static const char e100_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Link test     (on/offline)",
+	"Eeprom test   (on/offline)",
+	"Self test        (offline)",
+	"Mac loopback     (offline)",
+	"Phy loopback     (offline)",
+};
+#define E100_TEST_LEN	sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
+
+static int e100_diag_test_count(struct net_device *netdev)
+{
+	return E100_TEST_LEN;
+}
+
+static void e100_diag_test(struct net_device *netdev,
+	struct ethtool_test *test, u64 *data)
+{
+	struct nic *nic = netdev->priv;
+	int i;
+
+	memset(data, 0, E100_TEST_LEN * sizeof(u64));
+	data[0] = !mii_link_ok(&nic->mii);
+	data[1] = e100_eeprom_load(nic);
+	if(test->flags & ETH_TEST_FL_OFFLINE) {
+		if(netif_running(netdev))
+			e100_down(nic);
+		data[2] = e100_self_test(nic);
+		data[3] = e100_loopback_test(nic, lb_mac);
+		data[4] = e100_loopback_test(nic, lb_phy);
+		if(netif_running(netdev))
+			e100_up(nic);
+	}
+	for(i = 0; i < E100_TEST_LEN; i++)
+		test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
+}
+
+static int e100_phys_id(struct net_device *netdev, u32 data)
+{
+	struct nic *nic = netdev->priv;
+
+	if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+	mod_timer(&nic->blink_timer, jiffies);
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(data * HZ);
+	del_timer_sync(&nic->blink_timer);
+	mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
+
+	return 0;
+}
+
+static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+	/* device-specific stats */
+	"tx_deferred", "tx_single_collisions", "tx_multi_collisions",
+	"tx_flow_control_pause", "rx_flow_control_pause",
+	"rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets",
+};
+#define E100_NET_STATS_LEN	21
+#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
+
+static int e100_get_stats_count(struct net_device *netdev)
+{
+	return E100_STATS_LEN;
+}
+
+static void e100_get_ethtool_stats(struct net_device *netdev,
+	struct ethtool_stats *stats, u64 *data)
+{
+	struct nic *nic = netdev->priv;
+	int i;
+
+	for(i = 0; i < E100_NET_STATS_LEN; i++)
+		data[i] = ((unsigned long *)&nic->net_stats)[i];
+
+	data[i++] = nic->tx_deferred;
+	data[i++] = nic->tx_single_collisions;
+	data[i++] = nic->tx_multiple_collisions;
+	data[i++] = nic->tx_fc_pause;
+	data[i++] = nic->rx_fc_pause;
+	data[i++] = nic->rx_fc_unsupported;
+	data[i++] = nic->tx_tco_frames;
+	data[i++] = nic->rx_tco_frames;
+}
+
+static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	switch(stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test));
+		break;
+	case ETH_SS_STATS:
+		memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats));
+		break;
+	}
+}
+
+static struct ethtool_ops e100_ethtool_ops = {
+	.get_settings		= e100_get_settings,
+	.set_settings		= e100_set_settings,
+	.get_drvinfo		= e100_get_drvinfo,
+	.get_regs_len		= e100_get_regs_len,
+	.get_regs		= e100_get_regs,
+	.get_wol		= e100_get_wol,
+	.set_wol		= e100_set_wol,
+	.get_msglevel		= e100_get_msglevel,
+	.set_msglevel		= e100_set_msglevel,
+	.nway_reset		= e100_nway_reset,
+	.get_link		= e100_get_link,
+	.get_eeprom_len		= e100_get_eeprom_len,
+	.get_eeprom		= e100_get_eeprom,
+	.set_eeprom		= e100_set_eeprom,
+	.get_ringparam		= e100_get_ringparam,
+	.set_ringparam		= e100_set_ringparam,
+	.self_test_count	= e100_diag_test_count,
+	.self_test		= e100_diag_test,
+	.get_strings		= e100_get_strings,
+	.phys_id		= e100_phys_id,
+	.get_stats_count	= e100_get_stats_count,
+	.get_ethtool_stats	= e100_get_ethtool_stats,
+};
+
+static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct nic *nic = netdev->priv;
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data;
+
+	return generic_mii_ioctl(&nic->mii, mii, cmd, NULL);
+}
+
+static int e100_alloc(struct nic *nic)
+{
+	nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem),
+		&nic->dma_addr);
+	return nic->mem ? 0 : -ENOMEM;
+}
+
+static void e100_free(struct nic *nic)
+{
+	if(nic->mem) {
+		pci_free_consistent(nic->pdev, sizeof(struct mem),
+			nic->mem, nic->dma_addr);
+		nic->mem = NULL;
+	}
+}
+
+static int e100_open(struct net_device *netdev)
+{
+	struct nic *nic = netdev->priv;
+	int err = 0;
+
+	netif_carrier_off(netdev);
+	if((err = e100_up(nic)))
+		DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
+	return err;
+}
+
+static int e100_close(struct net_device *netdev)
+{
+	e100_down(netdev->priv);
+	return 0;
+}
+
+static int __devinit e100_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct nic *nic;
+	int err;
+
+	if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
+		if(((1 << debug) - 1) & NETIF_MSG_PROBE)
+			printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
+		return -ENOMEM;
+	}
+
+	netdev->open = e100_open;
+	netdev->stop = e100_close;
+	netdev->hard_start_xmit = e100_xmit_frame;
+	netdev->get_stats = e100_get_stats;
+	netdev->set_multicast_list = e100_set_multicast_list;
+	netdev->set_mac_address = e100_set_mac_address;
+	netdev->change_mtu = e100_change_mtu;
+	netdev->do_ioctl = e100_do_ioctl;
+	SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
+	netdev->tx_timeout = e100_tx_timeout;
+	netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
+#ifdef CONFIG_E100_NAPI
+	netdev->poll = e100_poll;
+	netdev->weight = E100_NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = e100_netpoll;
+#endif
+
+	nic = netdev->priv;
+	nic->netdev = netdev;
+	nic->pdev = pdev;
+	nic->msg_enable = (1 << debug) - 1;
+	pci_set_drvdata(pdev, netdev);
+
+	if((err = pci_enable_device(pdev))) {
+		DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
+		goto err_out_free_dev;
+	}
+
+	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
+			"base address, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	if((err = pci_request_regions(pdev, DRV_NAME))) {
+		DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
+		DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
+		goto err_out_free_res;
+	}
+
+	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
+	if(!nic->csr) {
+		DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+
+	if(ent->driver_data)
+		nic->flags |= ich;
+	else
+		nic->flags &= ~ich;
+
+	spin_lock_init(&nic->cb_lock);
+	spin_lock_init(&nic->cmd_lock);
+
+	init_timer(&nic->watchdog);
+	nic->watchdog.function = e100_watchdog;
+	nic->watchdog.data = (unsigned long)nic;
+	init_timer(&nic->blink_timer);
+	nic->blink_timer.function = e100_blink_led;
+	nic->blink_timer.data = (unsigned long)nic;
+
+	if((err = e100_alloc(nic))) {
+		DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	e100_get_defaults(nic);
+	e100_hw_reset(nic);
+	e100_phy_init(nic);
+
+	if((err = e100_eeprom_load(nic)))
+		goto err_out_free;
+	((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]);
+	((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]);
+	((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]);
+	if(!is_valid_ether_addr(netdev->dev_addr)) {
+		DPRINTK(PROBE, ERR, "Invalid MAC address from "
+			"EEPROM, aborting.\n");
+		err = -EAGAIN;
+		goto err_out_free;
+	}
+
+	/* Wol magic packet can be enabled from eeprom */
+	if((nic->mac >= mac_82558_D101_A4) &&
+	   (nic->eeprom[eeprom_id] & eeprom_id_wol))
+		nic->flags |= wol_magic;
+
+	pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+
+	if((err = register_netdev(netdev))) {
+		DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
+		goto err_out_free;
+	}
+
+	DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
+		"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
+		pci_resource_start(pdev, 0), pdev->irq,
+		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+
+	return 0;
+
+err_out_free:
+	e100_free(nic);
+err_out_iounmap:
+	iounmap(nic->csr);
+err_out_free_res:
+	pci_release_regions(pdev);
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+err_out_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+	return err;
+}
+
+static void __devexit e100_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+
+	if(netdev) {
+		struct nic *nic = netdev->priv;
+		unregister_netdev(netdev);
+		e100_free(nic);
+		iounmap(nic->csr);
+		free_netdev(netdev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+#ifdef CONFIG_PM
+static int e100_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev->priv;
+
+	if(netif_running(netdev))
+		e100_down(nic);
+	e100_hw_reset(nic);
+	netif_device_detach(netdev);
+
+	pci_save_state(pdev, nic->pm_state);
+	pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic)));
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, state);
+
+	return 0;
+}
+
+static int e100_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev->priv;
+
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev, nic->pm_state);
+	e100_hw_init(nic);
+
+	netif_device_attach(netdev);
+	if(netif_running(netdev))
+		e100_up(nic);
+
+	return 0;
+}
+#endif
+
+static struct pci_driver e100_driver = {
+	.name =         DRV_NAME,
+	.id_table =     e100_id_table,
+	.probe =        e100_probe,
+	.remove =       __devexit_p(e100_remove),
+#ifdef CONFIG_PM
+	.suspend =      e100_suspend,
+	.resume =       e100_resume,
+#endif
+};
+
+static int __init e100_init_module(void)
+{
+	if(((1 << debug) - 1) & NETIF_MSG_DRV) {
+		printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+		printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+	}
+        return pci_module_init(&e100_driver);
+}
+
+static void __exit e100_cleanup_module(void)
+{
+	pci_unregister_driver(&e100_driver);
+}
+
+module_init(e100_init_module);
+module_exit(e100_cleanup_module);
--- diff/drivers/net/kgdb_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/kgdb_eth.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,131 @@
+/*
+ * Network interface GDB stub
+ *
+ * Written by San Mehat (nettwerk@biodome.org)
+ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
+ * and Scott Foehner (sfoehner@engr.sgi.com)
+ *
+ * Twiddled for 2.6 by Robert Walsh <rjwalsh@durables.org>
+ * and wangdi <wangdi@clusterfs.com>.
+ *
+ * Refactored for netpoll API by Matt Mackall <mpm@selenic.com>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/netpoll.h>
+
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#define IN_BUF_SIZE 512 /* power of 2, please */
+#define OUT_BUF_SIZE 256
+
+static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE];
+static int in_head, in_tail, out_count;
+static atomic_t in_count;
+int kgdboe = 0; /* Default to tty mode */
+
+extern void set_debug_traps(void);
+extern void breakpoint(void);
+static void rx_hook(struct netpoll *np, int port, char *msg, int len);
+
+static struct netpoll np = {
+	.name = "kgdboe",
+	.dev_name = "eth0",
+	.rx_hook = rx_hook,
+	.local_port = 6443,
+	.remote_port = 6442,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+
+int eth_getDebugChar(void)
+{
+	int chr;
+
+	while (atomic_read(&in_count) == 0)
+		netpoll_poll(&np);
+
+	chr = in_buf[in_tail++];
+	in_tail &= (IN_BUF_SIZE - 1);
+	atomic_dec(&in_count);
+	return chr;
+}
+
+void eth_flushDebugChar(void)
+{
+	if(out_count && np.dev) {
+		netpoll_send_udp(&np, out_buf, out_count);
+		out_count = 0;
+	}
+}
+
+void eth_putDebugChar(int chr)
+{
+	out_buf[out_count++] = chr;
+	if(out_count == OUT_BUF_SIZE)
+		eth_flushDebugChar();
+}
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len)
+{
+	int i;
+
+	np->remote_port = port;
+
+	/* Is this gdb trying to attach? */
+	if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8))
+		kgdb_schedule_breakpoint();
+
+	for (i = 0; i < len; i++) {
+		if (msg[i] == 3)
+			kgdb_schedule_breakpoint();
+
+		if (atomic_read(&in_count) >= IN_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			in_head = in_tail = 0;
+			atomic_set(&in_count, 0);
+			break;
+		}
+		in_buf[in_head++] = msg[i];
+		in_head &= (IN_BUF_SIZE - 1);
+		atomic_inc(&in_count);
+	}
+}
+
+static int option_setup(char *opt)
+{
+	return netpoll_parse_options(&np, opt);
+}
+
+__setup("kgdboe=", option_setup);
+
+static int init_kgdboe(void)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) {
+		printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
+		return -1;
+	}
+#endif
+
+	set_debug_traps();
+
+	if(!np.remote_ip || netpoll_setup(&np))
+		return 1;
+
+	kgdboe = 1;
+	printk(KERN_INFO "kgdb: debugging over ethernet enabled\n");
+
+	return 0;
+}
+
+module_init(init_kgdboe);
--- diff/drivers/net/netconsole.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/netconsole.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,127 @@
+/*
+ *  linux/drivers/net/netconsole.c
+ *
+ *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
+ *
+ *  This file contains the implementation of an IRQ-safe, crash-safe
+ *  kernel console implementation that outputs kernel messages to the
+ *  network.
+ *
+ * Modification history:
+ *
+ * 2001-09-17    started by Ingo Molnar.
+ * 2003-08-11    2.6 port by Matt Mackall
+ *               simplified options
+ *               generic card hooks
+ *               works non-modular
+ * 2003-09-07    rewritten with netpoll api
+ */
+
+/****************************************************************
+ *      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, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************/
+
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty_driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/smp.h>
+#include <linux/netpoll.h>
+
+MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
+MODULE_DESCRIPTION("Console driver for network interfaces");
+MODULE_LICENSE("GPL");
+
+static char config[256];
+module_param_string(netconsole, config, 256, 0);
+MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
+
+static struct netpoll np = {
+	.name = "netconsole",
+	.dev_name = "eth0",
+	.local_port = 6665,
+	.remote_port = 6666,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static int configured = 0;
+
+#define MAX_PRINT_CHUNK 1000
+
+static void write_msg(struct console *con, const char *msg, unsigned int len)
+{
+	int frag, left;
+	unsigned long flags;
+
+	if (!np.dev)
+		return;
+
+	local_irq_save(flags);
+
+	for(left = len; left; ) {
+		frag = min(left, MAX_PRINT_CHUNK);
+		netpoll_send_udp(&np, msg, frag);
+		msg += frag;
+		left -= frag;
+	}
+
+	local_irq_restore(flags);
+}
+
+static struct console netconsole = {
+	.flags = CON_ENABLED | CON_PRINTBUFFER,
+	.write = write_msg
+};
+
+static int option_setup(char *opt)
+{
+	configured = !netpoll_parse_options(&np, opt);
+	return 0;
+}
+
+__setup("netconsole=", option_setup);
+
+static int init_netconsole(void)
+{
+	if(strlen(config))
+		option_setup(config);
+
+	if(!configured) {
+		printk("netconsole: not configured, aborting\n");
+		return -EINVAL;
+	}
+
+	if(netpoll_setup(&np))
+		return -EINVAL;
+
+	register_console(&netconsole);
+	printk(KERN_INFO "netconsole: network logging started\n");
+	return 0;
+}
+
+static void cleanup_netconsole(void)
+{
+	unregister_console(&netconsole);
+	netpoll_cleanup(&np);
+}
+
+module_init(init_netconsole);
+module_exit(cleanup_netconsole);
--- diff/drivers/scsi/aacraid/rkt.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/aacraid/rkt.c	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,416 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rkt.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned long bellbits;
+	u8 intstat, mask;
+	intstat = rkt_readb(dev, MUnit.OISR);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have 
+	 *	been enabled.
+	 */
+	mask = ~(dev->OIMR);
+	/* Check to see if this is our interrupt.  If it isn't just return */
+	if (intstat & mask) 
+	{
+		bellbits = rkt_readl(dev, OutboundDoorbellReg);
+		if (bellbits & DoorBellPrintfReady) {
+			aac_printf(dev, le32_to_cpu(rkt_readl (dev, IndexRegs.Mailbox[5])));
+			rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+			rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdReady) {
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+		}
+		else if (bellbits & DoorBellAdapterNormRespReady) {
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+		}
+		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/**
+ *	aac_rkt_enable_interrupt	-	Enable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Enable event reporting from the i960 for a given event.
+ */
+ 
+static void aac_rkt_enable_interrupt(struct aac_dev * dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_rkt_disable_interrupt	-	Disable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Disable event reporting from the i960 for a given event.
+ */
+
+static void aac_rkt_disable_interrupt(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	rkt_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int rkt_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
+{
+	unsigned long start;
+	int ok;
+	/*
+	 *	Write the command into Mailbox 0
+	 */
+	rkt_writel(dev, InboundMailbox0, cpu_to_le32(command));
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	rkt_writel(dev, InboundMailbox1, cpu_to_le32(p1));
+	rkt_writel(dev, InboundMailbox2, 0);
+	rkt_writel(dev, InboundMailbox3, 0);
+	rkt_writel(dev, InboundMailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Disable doorbell interrupts
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR |= 0x04);
+	/*
+	 *	Force the completion of the mask register write before issuing
+	 *	the interrupt.
+	 */
+	rkt_readb (dev, MUnit.OIMR);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	/*
+	 *	Wait up to 30 seconds
+	 */
+	while (time_before(jiffies, start+30*HZ)) 
+	{
+		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+		/*
+		 *	Mon960 will set doorbell0 bit when it has completed the command.
+		 */
+		if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+			/*
+			 *	Clear the doorbell.
+			 */
+			rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+			ok = 1;
+			break;
+		}
+		/*
+		 *	Yield the processor in case we are slow 
+		 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (ok != 1) {
+		/*
+		 *	Restore interrupt mask even though we timed out
+		 */
+		rkt_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+		return -ETIMEDOUT;
+	}
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	*status = le32_to_cpu(rkt_readl(dev, IndexRegs.Mailbox[0]));
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Restore interrupt mask
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+	return 0;
+
+}
+
+/**
+ *	aac_rkt_interrupt_adapter	-	interrupt adapter
+ *	@dev: Adapter
+ *
+ *	Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_rkt_notify_adapter		-	send an event to the adapter
+ *	@dev: Adapter
+ *	@event: Event to send
+ *
+ *	Notify the i960 that something it probably cares about has
+ *	happened.
+ */
+
+static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+		break;
+	case HostShutdown:
+//		rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
+		break;
+	case FastIo:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ *	aac_rkt_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_rkt_start_adapter(struct aac_dev *dev)
+{
+	u32 status;
+	struct aac_init *init;
+
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+	/*
+	 *	Tell the adapter we are back and up and running so it will scan
+	 *	its command queues and enable our interrupts
+	 */
+	dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	rkt_writeb(dev, MUnit.OIMR, 0xff);
+	rkt_writel(dev, MUnit.ODR, 0xffffffff);
+//	rkt_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
+	// We can only use a 32 bit address here
+	rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
+}
+
+/**
+ *	aac_rkt_init	-	initialize an i960 based AAC card
+ *	@dev: device to configure
+ *	@devnum: adapter number
+ *
+ *	Allocate and set up resources for the i960 based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_rkt_init(struct aac_dev *dev, unsigned long num)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char * name;
+
+	dev->devnum = num;
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	if((dev->regs.rkt = (struct rkt_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map i960.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (rkt_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		return -1;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (rkt_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
+		printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
+		return -1;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	while (!(rkt_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) 
+	{
+		if(time_after(jiffies, start+180*HZ))
+		{
+			status = rkt_readl(dev, IndexRegs.Mailbox[7]) >> 16;
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status);
+			return -1;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
+	{
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+		return -1;
+	}
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
+	dev->a_ops.adapter_enable_int = aac_rkt_enable_interrupt;
+	dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
+
+	if (aac_init_adapter(dev) == NULL)
+		return -1;
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if(dev->thread_pid < 0)
+	{
+		printk(KERN_ERR "aacraid: Unable to create rkt thread.\n");
+		return -1;
+	}	
+	/*
+	 *	Tell the adapter that all is configured, and it can start
+	 *	accepting requests
+	 */
+	aac_rkt_start_adapter(dev);
+	return 0;
+}
--- diff/drivers/scsi/aacraid/rkt.c.unused	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/aacraid/rkt.c.unused	2004-02-18 09:04:00.000000000 +0000
@@ -0,0 +1,416 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rkt.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned long bellbits;
+	u8 intstat, mask;
+	intstat = rkt_readb(dev, MUnit.OISR);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have 
+	 *	been enabled.
+	 */
+	mask = ~(dev->OIMR);
+	/* Check to see if this is our interrupt.  If it isn't just return */
+	if (intstat & mask) 
+	{
+		bellbits = rkt_readl(dev, OutboundDoorbellReg);
+		if (bellbits & DoorBellPrintfReady) {
+			aac_printf(dev, le32_to_cpu(rkt_readl (dev, IndexRegs.Mailbox[5])));
+			rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+			rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdReady) {
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+		}
+		else if (bellbits & DoorBellAdapterNormRespReady) {
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+		}
+		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/**
+ *	aac_rkt_enable_interrupt	-	Enable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Enable event reporting from the i960 for a given event.
+ */
+ 
+static void aac_rkt_enable_interrupt(struct aac_dev * dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask &= ~(OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	aac_rkt_disable_interrupt	-	Disable event reporting
+ *	@dev: Adapter
+ *	@event: Event to enable
+ *
+ *	Disable event reporting from the i960 for a given event.
+ */
+
+static void aac_rkt_disable_interrupt(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case HostNormCmdQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_1);
+		break;
+
+	case HostNormRespQue:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_2);
+		break;
+
+	case AdapNormCmdNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_3);
+		break;
+
+	case AdapNormRespNotFull:
+		dev->irq_mask |= (OUTBOUNDDOORBELL_4);
+		break;
+	}
+}
+
+/**
+ *	rkt_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous comamnd to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int rkt_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
+{
+	unsigned long start;
+	int ok;
+	/*
+	 *	Write the command into Mailbox 0
+	 */
+	rkt_writel(dev, InboundMailbox0, cpu_to_le32(command));
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	rkt_writel(dev, InboundMailbox1, cpu_to_le32(p1));
+	rkt_writel(dev, InboundMailbox2, 0);
+	rkt_writel(dev, InboundMailbox3, 0);
+	rkt_writel(dev, InboundMailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Disable doorbell interrupts
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR |= 0x04);
+	/*
+	 *	Force the completion of the mask register write before issuing
+	 *	the interrupt.
+	 */
+	rkt_readb (dev, MUnit.OIMR);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	/*
+	 *	Wait up to 30 seconds
+	 */
+	while (time_before(jiffies, start+30*HZ)) 
+	{
+		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+		/*
+		 *	Mon960 will set doorbell0 bit when it has completed the command.
+		 */
+		if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+			/*
+			 *	Clear the doorbell.
+			 */
+			rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+			ok = 1;
+			break;
+		}
+		/*
+		 *	Yield the processor in case we are slow 
+		 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (ok != 1) {
+		/*
+		 *	Restore interrupt mask even though we timed out
+		 */
+		rkt_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+		return -ETIMEDOUT;
+	}
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	*status = le32_to_cpu(rkt_readl(dev, IndexRegs.Mailbox[0]));
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Restore interrupt mask
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+	return 0;
+
+}
+
+/**
+ *	aac_rkt_interrupt_adapter	-	interrupt adapter
+ *	@dev: Adapter
+ *
+ *	Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_rkt_notify_adapter		-	send an event to the adapter
+ *	@dev: Adapter
+ *	@event: Event to send
+ *
+ *	Notify the i960 that something it probably cares about has
+ *	happened.
+ */
+
+static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+		break;
+	case HostShutdown:
+//		rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
+		break;
+	case FastIo:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ *	aac_rkt_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_rkt_start_adapter(struct aac_dev *dev)
+{
+	u32 status;
+	struct aac_init *init;
+
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
+	/*
+	 *	Tell the adapter we are back and up and running so it will scan
+	 *	its command queues and enable our interrupts
+	 */
+	dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	rkt_writeb(dev, MUnit.OIMR, 0xff);
+	rkt_writel(dev, MUnit.ODR, 0xffffffff);
+//	rkt_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
+	// We can only use a 32 bit address here
+	rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
+}
+
+/**
+ *	aac_rkt_init	-	initialize an i960 based AAC card
+ *	@dev: device to configure
+ *	@devnum: adapter number
+ *
+ *	Allocate and set up resources for the i960 based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_rkt_init(struct aac_dev *dev, unsigned long num)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char * name;
+
+	dev->devnum = num;
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	if((dev->regs.rkt = (struct rkt_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map i960.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (rkt_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		return -1;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (rkt_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
+		printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
+		return -1;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	while (!(rkt_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) 
+	{
+		if(time_after(jiffies, start+180*HZ))
+		{
+			status = rkt_readl(dev, IndexRegs.Mailbox[7]) >> 16;
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status);
+			return -1;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
+	{
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+		return -1;
+	}
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
+	dev->a_ops.adapter_enable_int = aac_rkt_enable_interrupt;
+	dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
+	dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
+
+	if (aac_init_adapter(dev) == NULL)
+		return -1;
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if(dev->thread_pid < 0)
+	{
+		printk(KERN_ERR "aacraid: Unable to create rkt thread.\n");
+		return -1;
+	}	
+	/*
+	 *	Tell the adapter that all is configured, and it can start
+	 *	accepting requests
+	 */
+	aac_rkt_start_adapter(dev);
+	return 0;
+}
--- diff/drivers/serial/au1x00_uart.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/serial/au1x00_uart.c	2004-02-18 09:04:01.000000000 +0000
@@ -0,0 +1,1393 @@
+/*
+ *  Driver for 8250/16550-type serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Copyright (C) 2001 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.  Currently, we don't
+ *  support this very well, and it may well be dropped from this driver
+ *  in future.  As such, mapbase should be NULL.
+ *
+ *  membase is an 'ioremapped' cookie.  This is compatible with the old
+ *  serial.c driver, and is currently the preferred form.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/delay.h>
+
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include "8250.h"
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...)	printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...)	do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)	printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)	do { } while (0)
+#endif
+
+#define PASS_LIMIT	256
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#define is_real_interrupt(irq)	((irq) != 0)
+
+static struct old_serial_port old_serial_port[] = {
+	{	.baud_base = 0,
+		.iomem_base = (u8 *)UART0_ADDR,
+		.irq = AU1000_UART0_INT,
+		.flags = STD_COM_FLAGS,
+		.iomem_reg_shift = 2,
+	}, {
+		.baud_base = 0,
+		.iomem_base = (u8 *)UART1_ADDR,
+		.irq = AU1000_UART1_INT,
+		.flags = STD_COM_FLAGS,
+		.iomem_reg_shift = 2
+	}, {
+		.baud_base = 0,
+		.iomem_base = (u8 *)UART2_ADDR,
+		.irq = AU1000_UART2_INT,
+		.flags = STD_COM_FLAGS,
+		.iomem_reg_shift = 2
+	}, {
+		.baud_base = 0,
+		.iomem_base = (u8 *)UART3_ADDR,
+		.irq = AU1000_UART3_INT,
+		.flags = STD_COM_FLAGS,
+		.iomem_reg_shift = 2
+	}
+};
+
+#define UART_NR	ARRAY_SIZE(old_serial_port)
+
+struct uart_8250_port {
+	struct uart_port	port;
+	struct timer_list	timer;		/* "no irq" timer */
+	struct list_head	list;		/* ports on this IRQ */
+	unsigned short		rev;
+	unsigned char		acr;
+	unsigned char		ier;
+	unsigned char		lcr;
+	unsigned char		mcr_mask;	/* mask of user bits */
+	unsigned char		mcr_force;	/* mask of forced bits */
+	unsigned char		lsr_break_flag;
+
+	/*
+	 * We provide a per-port pm hook.
+	 */
+	void			(*pm)(struct uart_port *port,
+				      unsigned int state, unsigned int old);
+};
+
+struct irq_info {
+	spinlock_t		lock;
+	struct list_head	*head;
+};
+
+static struct irq_info irq_lists[NR_IRQS];
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+	{ "unknown",	1,	0 },
+	{ "8250",	1,	0 },
+	{ "16450",	1,	0 },
+	{ "16550",	1,	0 },
+	/* PORT_16550A */
+	{ "AU1X00_UART",16,	UART_CLEAR_FIFO | UART_USE_FIFO },
+};
+
+static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
+{
+	return au_readl((unsigned long)up->port.membase + offset);
+}
+
+static _INLINE_ void
+serial_out(struct uart_8250_port *up, int offset, int value)
+{
+	au_writel(value, (unsigned long)up->port.membase + offset);
+}
+
+#define serial_inp(up, offset)		serial_in(up, offset)
+#define serial_outp(up, offset, value)	serial_out(up, offset, value)
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+{
+	unsigned char save_lcr, save_mcr;
+	unsigned long flags;
+
+	if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
+		return;
+
+	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%08lx): ",
+			up->port.line, up->port.iobase, up->port.membase);
+
+	/*
+	 * We really do need global IRQs disabled here - we're going to
+	 * be frobbing the chips IRQ enable register to see if it exists.
+	 */
+	spin_lock_irqsave(&up->port.lock, flags);
+//	save_flags(flags); cli();
+
+	save_mcr = serial_in(up, UART_MCR);
+	save_lcr = serial_in(up, UART_LCR);
+
+	up->port.type = PORT_16550A;
+	serial_outp(up, UART_LCR, save_lcr);
+
+	up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+	if (up->port.type == PORT_UNKNOWN)
+		goto out;
+
+	/*
+	 * Reset the UART.
+	 */
+	serial_outp(up, UART_MCR, save_mcr);
+	serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	serial_outp(up, UART_FCR, 0);
+	(void)serial_in(up, UART_RX);
+	serial_outp(up, UART_IER, 0);
+
+ out:	
+	spin_unlock_irqrestore(&up->port.lock, flags);
+//	restore_flags(flags);
+	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+}
+
+static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+	if (up->ier & UART_IER_THRI) {
+		up->ier &= ~UART_IER_THRI;
+		serial_out(up, UART_IER, up->ier);
+	}
+}
+
+static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+	if (!(up->ier & UART_IER_THRI)) {
+		up->ier |= UART_IER_THRI;
+		serial_out(up, UART_IER, up->ier);
+	}
+}
+
+static void serial8250_stop_rx(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+	up->ier &= ~UART_IER_RLSI;
+	up->port.read_status_mask &= ~UART_LSR_DR;
+	serial_out(up, UART_IER, up->ier);
+}
+
+static void serial8250_enable_ms(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+
+	up->ier |= UART_IER_MSI;
+	serial_out(up, UART_IER, up->ier);
+}
+
+static _INLINE_ void
+receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
+{
+	struct tty_struct *tty = up->port.info->tty;
+	unsigned char ch;
+	int max_count = 256;
+
+	do {
+		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return; // if TTY_DONT_FLIP is set
+		}
+		ch = serial_inp(up, UART_RX);
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		up->port.icount.rx++;
+
+		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+				       UART_LSR_FE | UART_LSR_OE))) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				up->port.icount.brk++;
+				/*
+				 * We do the SysRQ and SAK checking
+				 * here because otherwise the break
+				 * may get masked by ignore_status_mask
+				 * or read_status_mask.
+				 */
+				if (uart_handle_break(&up->port))
+					goto ignore_char;
+			} else if (*status & UART_LSR_PE)
+				up->port.icount.parity++;
+			else if (*status & UART_LSR_FE)
+				up->port.icount.frame++;
+			if (*status & UART_LSR_OE)
+				up->port.icount.overrun++;
+
+			/*
+			 * Mask off conditions which should be ingored.
+			 */
+			*status &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
+			if (up->port.line == up->port.cons->index) {
+				/* Recover the break flag from console xmit */
+				*status |= up->lsr_break_flag;
+				up->lsr_break_flag = 0;
+			}
+#endif
+			if (*status & UART_LSR_BI) {
+				DEBUG_INTR("handling break....");
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+			} else if (*status & UART_LSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+		if (uart_handle_sysrq_char(&up->port, ch, regs))
+			goto ignore_char;
+		if ((*status & up->port.ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((*status & UART_LSR_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character.
+			 */
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+	ignore_char:
+		*status = serial_inp(up, UART_LSR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+	tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct uart_8250_port *up)
+{
+	struct circ_buf *xmit = &up->port.info->xmit;
+	int count;
+
+	if (up->port.x_char) {
+		serial_outp(up, UART_TX, up->port.x_char);
+		up->port.icount.tx++;
+		up->port.x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+		serial8250_stop_tx(&up->port, 0);
+		return;
+	}
+
+	count = up->port.fifosize;
+	do {
+		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		up->port.icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&up->port);
+
+	DEBUG_INTR("THRE...");
+
+	if (uart_circ_empty(xmit))
+		serial8250_stop_tx(&up->port, 0);
+}
+
+static _INLINE_ void check_modem_status(struct uart_8250_port *up)
+{
+	int status;
+
+	status = serial_in(up, UART_MSR);
+
+	if ((status & UART_MSR_ANY_DELTA) == 0)
+		return;
+
+	if (status & UART_MSR_TERI)
+		up->port.icount.rng++;
+	if (status & UART_MSR_DDSR)
+		up->port.icount.dsr++;
+	if (status & UART_MSR_DDCD)
+		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+	if (status & UART_MSR_DCTS)
+		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+
+	wake_up_interruptible(&up->port.info->delta_msr_wait);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline void
+serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
+{
+	unsigned int status = serial_inp(up, UART_LSR);
+
+	DEBUG_INTR("status = %x...", status);
+
+	if (status & UART_LSR_DR)
+		receive_chars(up, &status, regs);
+	check_modem_status(up);
+	if (status & UART_LSR_THRE)
+		transmit_chars(up);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct irq_info *i = dev_id;
+	struct list_head *l, *end = NULL;
+	int pass_counter = 0;
+
+	DEBUG_INTR("serial8250_interrupt(%d)...", irq);
+
+	spin_lock(&i->lock);
+
+	l = i->head;
+	do {
+		struct uart_8250_port *up;
+		unsigned int iir;
+
+		up = list_entry(l, struct uart_8250_port, list);
+
+		iir = serial_in(up, UART_IIR);
+		if (!(iir & UART_IIR_NO_INT)) {
+			spin_lock(&up->port.lock);
+			serial8250_handle_port(up, regs);
+			spin_unlock(&up->port.lock);
+
+			end = NULL;
+		} else if (end == NULL)
+			end = l;
+
+		l = l->next;
+
+		if (l == i->head && pass_counter++ > PASS_LIMIT) {
+			/* If we hit this, we're dead. */
+			printk(KERN_ERR "serial8250: too much work for "
+				"irq%d\n", irq);
+			break;
+		}
+	} while (l != end);
+
+	spin_unlock(&i->lock);
+
+	DEBUG_INTR("end.\n");
+	/* FIXME! Was it really ours? */
+	return IRQ_HANDLED;
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
+{
+	spin_lock_irq(&i->lock);
+
+	if (!list_empty(i->head)) {
+		if (i->head == &up->list)
+			i->head = i->head->next;
+		list_del(&up->list);
+	} else {
+		BUG_ON(i->head != &up->list);
+		i->head = NULL;
+	}
+
+	spin_unlock_irq(&i->lock);
+}
+
+static int serial_link_irq_chain(struct uart_8250_port *up)
+{
+	struct irq_info *i = irq_lists + up->port.irq;
+	int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
+
+	spin_lock_irq(&i->lock);
+
+	if (i->head) {
+		list_add(&up->list, i->head);
+		spin_unlock_irq(&i->lock);
+
+		ret = 0;
+	} else {
+		INIT_LIST_HEAD(&up->list);
+		i->head = &up->list;
+		spin_unlock_irq(&i->lock);
+
+		ret = request_irq(up->port.irq, serial8250_interrupt,
+				  irq_flags, "serial", i);
+		if (ret < 0)
+			serial_do_unlink(i, up);
+	}
+
+	return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_8250_port *up)
+{
+	struct irq_info *i = irq_lists + up->port.irq;
+
+	BUG_ON(i->head == NULL);
+
+	if (list_empty(i->head))
+		free_irq(up->port.irq, i);
+
+	serial_do_unlink(i, up);
+}
+
+/*
+ * This function is used to handle ports that do not have an
+ * interrupt.  This doesn't work very well for 16450's, but gives
+ * barely passable results for a 16550A.  (Although at the expense
+ * of much CPU overhead).
+ */
+static void serial8250_timeout(unsigned long data)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)data;
+	unsigned int timeout;
+	unsigned int iir;
+
+	iir = serial_in(up, UART_IIR);
+	if (!(iir & UART_IIR_NO_INT)) {
+		spin_lock(&up->port.lock);
+		serial8250_handle_port(up, NULL);
+		spin_unlock(&up->port.lock);
+	}
+
+	timeout = up->port.timeout;
+	timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+	mod_timer(&up->timer, jiffies + timeout);
+}
+
+static unsigned int serial8250_tx_empty(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	return ret;
+}
+
+static unsigned int serial8250_get_mctrl(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long flags;
+	unsigned char status;
+	unsigned int ret;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	status = serial_in(up, UART_MSR);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	ret = 0;
+	if (status & UART_MSR_DCD)
+		ret |= TIOCM_CAR;
+	if (status & UART_MSR_RI)
+		ret |= TIOCM_RNG;
+	if (status & UART_MSR_DSR)
+		ret |= TIOCM_DSR;
+	if (status & UART_MSR_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned char mcr = 0;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	mcr = (mcr & up->mcr_mask) | up->mcr_force;
+
+	serial_out(up, UART_MCR, mcr);
+}
+
+static void serial8250_break_ctl(struct uart_port *port, int break_state)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	if (break_state == -1)
+		up->lcr |= UART_LCR_SBC;
+	else
+		up->lcr &= ~UART_LCR_SBC;
+	serial_out(up, UART_LCR, up->lcr);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial8250_startup(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long flags;
+	int retval;
+
+	/*
+	 * Clear the FIFO buffers and disable them.
+	 * (they will be reeanbled in set_termios())
+	 */
+	if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
+		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+		serial_outp(up, UART_FCR, 0);
+	}
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) serial_inp(up, UART_LSR);
+	(void) serial_inp(up, UART_RX);
+	(void) serial_inp(up, UART_IIR);
+	(void) serial_inp(up, UART_MSR);
+
+	/*
+	 * At this point, there's no way the LSR could still be 0xff;
+	 * if it is, then bail out, because there's likely no UART
+	 * here.
+	 */
+	if (!(up->port.flags & UPF_BUGGY_UART) &&
+	    (serial_inp(up, UART_LSR) == 0xff)) {
+		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+		return -ENODEV;
+	}
+
+	retval = serial_link_irq_chain(up);
+		if (retval)
+			return retval;
+
+	/*
+	 * Now, initialize the UART
+	 */
+	serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	if (up->port.flags & UPF_FOURPORT) {
+		if (!is_real_interrupt(up->port.irq))
+			up->port.mctrl |= TIOCM_OUT1;
+	} else
+		/*
+		 * Most PC uarts need OUT2 raised to enable interrupts.
+		 */
+		if (is_real_interrupt(up->port.irq))
+			up->port.mctrl |= TIOCM_OUT2;
+
+	serial8250_set_mctrl(&up->port, up->port.mctrl);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	/*
+	 * Finally, enable interrupts.  Note: Modem status interrupts
+	 * are set via set_termios(), which will be occurring imminently
+	 * anyway, so we don't enable them here.
+	 */
+	up->ier = UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(up, UART_IER, up->ier);
+
+	if (up->port.flags & UPF_FOURPORT) {
+		unsigned int icp;
+		/*
+		 * Enable interrupts on the AST Fourport board
+		 */
+		icp = (up->port.iobase & 0xfe0) | 0x01f;
+		outb_p(0x80, icp);
+		(void) inb_p(icp);
+	}
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void) serial_inp(up, UART_LSR);
+	(void) serial_inp(up, UART_RX);
+	(void) serial_inp(up, UART_IIR);
+	(void) serial_inp(up, UART_MSR);
+
+	return 0;
+}
+
+static void serial8250_shutdown(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long flags;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	up->ier = 0;
+	serial_outp(up, UART_IER, 0);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	if (up->port.flags & UPF_FOURPORT) {
+		/* reset interrupts on the AST Fourport board */
+		inb((up->port.iobase & 0xfe0) | 0x1f);
+		up->port.mctrl |= TIOCM_OUT1;
+	} else
+		up->port.mctrl &= ~TIOCM_OUT2;
+
+	serial8250_set_mctrl(&up->port, up->port.mctrl);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	/*
+	 * Disable break condition and FIFOs
+	 */
+	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
+	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+				  UART_FCR_CLEAR_RCVR |
+				  UART_FCR_CLEAR_XMIT);
+	serial_outp(up, UART_FCR, 0);
+
+	/*
+	 * Read data port to reset things, and then unlink from
+	 * the IRQ chain.
+	 */
+	(void) serial_in(up, UART_RX);
+
+	if (!is_real_interrupt(up->port.irq))
+		del_timer_sync(&up->timer);
+	else
+		serial_unlink_irq_chain(up);
+}
+
+static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+{
+	unsigned int quot;
+
+	/*
+	 * Handle magic divisors for baud rates above baud_base on
+	 * SMSC SuperIO chips.
+	 */
+	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+	    baud == (port->uartclk/4))
+		quot = 0x8001;
+	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+		 baud == (port->uartclk/8))
+		quot = 0x8002;
+	else
+		quot = uart_get_divisor(port, baud);
+
+	return quot;
+}
+
+static void
+serial8250_set_termios(struct uart_port *port, struct termios *termios,
+		       struct termios *old)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned char cval, fcr = 0;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		cval = 0x00;
+		break;
+	case CS6:
+		cval = 0x01;
+		break;
+	case CS7:
+		cval = 0x02;
+		break;
+	default:
+	case CS8:
+		cval = 0x03;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		cval |= 0x04;
+	if (termios->c_cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(termios->c_cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+	if (termios->c_cflag & CMSPAR)
+		cval |= UART_LCR_SPAR;
+#endif
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	quot = serial8250_get_divisor(port, baud);
+	quot = 0x35; /* FIXME */
+
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
+	    up->rev == 0x5201)
+		quot ++;
+
+	if (uart_config[up->port.type].flags & UART_USE_FIFO) {
+		if (baud < 2400)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;
+		else
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;
+	}
+
+	/*
+	 * Ok, we're now changing the port state.  Do it with
+	 * interrupts disabled.
+	 */
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (termios->c_iflag & INPCK)
+		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		up->port.read_status_mask |= UART_LSR_BI;
+
+	/*
+	 * Characteres to ignore
+	 */
+	up->port.ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		up->port.ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			up->port.ignore_status_mask |= UART_LSR_OE;
+	}
+
+	/*
+	 * ignore all characters if CREAD is not set
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		up->port.ignore_status_mask |= UART_LSR_DR;
+
+	/*
+	 * CTS flow control flag and modem status interrupts
+	 */
+	up->ier &= ~UART_IER_MSI;
+	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+		up->ier |= UART_IER_MSI;
+
+	serial_out(up, UART_IER, up->ier);
+	serial_outp(up, 0x28, quot & 0xffff);
+	up->lcr = cval;					/* Save LCR */
+	if (up->port.type != PORT_16750) {
+		if (fcr & UART_FCR_ENABLE_FIFO) {
+			/* emulated UARTs (Lucent Venus 167x) need two steps */
+			serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+		}
+		serial_outp(up, UART_FCR, fcr);		/* set fcr */
+	}
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+serial8250_pm(struct uart_port *port, unsigned int state,
+	      unsigned int oldstate)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	if (state) {
+		/* sleep */
+		if (up->pm)
+			up->pm(port, state, oldstate);
+	} else {
+		/* wake */
+		if (up->pm)
+			up->pm(port, state, oldstate);
+	}
+}
+
+/*
+ * Resource handling.  This is complicated by the fact that resources
+ * depend on the port type.  Maybe we should be claiming the standard
+ * 8250 ports, and then trying to get other resources as necessary?
+ */
+static int
+serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
+{
+	unsigned int size = 8 << up->port.regshift;
+	int ret = 0;
+
+	switch (up->port.iotype) {
+	case SERIAL_IO_MEM:
+		if (up->port.mapbase) {
+			*res = request_mem_region(up->port.mapbase, size, "serial");
+			if (!*res)
+				ret = -EBUSY;
+		}
+		break;
+
+	case SERIAL_IO_HUB6:
+	case SERIAL_IO_PORT:
+		*res = request_region(up->port.iobase, size, "serial");
+		if (!*res)
+			ret = -EBUSY;
+		break;
+	}
+	return ret;
+}
+
+
+static void serial8250_release_port(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	unsigned long start, offset = 0, size = 0;
+
+	size <<= up->port.regshift;
+
+	switch (up->port.iotype) {
+	case SERIAL_IO_MEM:
+		if (up->port.mapbase) {
+			/*
+			 * Unmap the area.
+			 */
+			iounmap(up->port.membase);
+			up->port.membase = NULL;
+
+			start = up->port.mapbase;
+
+			if (size)
+				release_mem_region(start + offset, size);
+			release_mem_region(start, 8 << up->port.regshift);
+		}
+		break;
+
+	case SERIAL_IO_HUB6:
+	case SERIAL_IO_PORT:
+		start = up->port.iobase;
+
+		if (size)
+			release_region(start + offset, size);
+		release_region(start + offset, 8 << up->port.regshift);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int serial8250_request_port(struct uart_port *port)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct resource *res = NULL, *res_rsa = NULL;
+	int ret = 0;
+
+	if (up->port.flags & UPF_RESOURCES) {
+		ret = serial8250_request_std_resource(up, &res);
+	}
+
+	/*
+	 * If we have a mapbase, then request that as well.
+	 */
+	if (ret == 0 && up->port.flags & UPF_IOREMAP) {
+		int size = res->end - res->start + 1;
+
+		up->port.membase = ioremap(up->port.mapbase, size);
+		if (!up->port.membase)
+			ret = -ENOMEM;
+	}
+
+	if (ret < 0) {
+		if (res_rsa)
+			release_resource(res_rsa);
+		if (res)
+			release_resource(res);
+	}
+	return ret;
+}
+
+static void serial8250_config_port(struct uart_port *port, int flags)
+{
+	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct resource *res_std = NULL, *res_rsa = NULL;
+	int probeflags = PROBE_ANY;
+
+	probeflags &= ~PROBE_RSA;
+
+	if (flags & UART_CONFIG_TYPE)
+		autoconfig(up, probeflags);
+
+	/*
+	 * If the port wasn't an RSA port, release the resource.
+	 */
+	if (up->port.type != PORT_RSA && res_rsa)
+		release_resource(res_rsa);
+
+	if (up->port.type == PORT_UNKNOWN && res_std)
+		release_resource(res_std);
+}
+
+static int
+serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+	    ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+	    ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS ||
+	    ser->type == PORT_STARTECH)
+		return -EINVAL;
+	return 0;
+}
+
+static const char *
+serial8250_type(struct uart_port *port)
+{
+	int type = port->type;
+
+	if (type >= ARRAY_SIZE(uart_config))
+		type = 0;
+	return uart_config[type].name;
+}
+
+static struct uart_ops serial8250_pops = {
+	.tx_empty	= serial8250_tx_empty,
+	.set_mctrl	= serial8250_set_mctrl,
+	.get_mctrl	= serial8250_get_mctrl,
+	.stop_tx	= serial8250_stop_tx,
+	.start_tx	= serial8250_start_tx,
+	.stop_rx	= serial8250_stop_rx,
+	.enable_ms	= serial8250_enable_ms,
+	.break_ctl	= serial8250_break_ctl,
+	.startup	= serial8250_startup,
+	.shutdown	= serial8250_shutdown,
+	.set_termios	= serial8250_set_termios,
+	.pm		= serial8250_pm,
+	.type		= serial8250_type,
+	.release_port	= serial8250_release_port,
+	.request_port	= serial8250_request_port,
+	.config_port	= serial8250_config_port,
+	.verify_port	= serial8250_verify_port,
+};
+
+static struct uart_8250_port serial8250_ports[UART_NR];
+
+static void __init serial8250_isa_init_ports(void)
+{
+	struct uart_8250_port *up;
+	static int first = 1;
+	int i;
+
+	if (!first)
+		return;
+	first = 0;
+
+	for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
+	     i++, up++) {
+		up->port.iobase   = old_serial_port[i].port;
+		up->port.irq      = old_serial_port[i].irq;
+		up->port.uartclk  = get_au1x00_uart_baud_base();
+		up->port.flags    = old_serial_port[i].flags |
+				    UPF_RESOURCES;
+		up->port.hub6     = old_serial_port[i].hub6;
+		up->port.membase  = old_serial_port[i].iomem_base;
+		up->port.iotype   = old_serial_port[i].io_type;
+		up->port.regshift = old_serial_port[i].iomem_reg_shift;
+		up->port.ops      = &serial8250_pops;
+	}
+}
+
+static void __init serial8250_register_ports(struct uart_driver *drv)
+{
+	int i;
+
+	serial8250_isa_init_ports();
+
+	for (i = 0; i < UART_NR; i++) {
+		struct uart_8250_port *up = &serial8250_ports[i];
+
+		up->port.line = i;
+		up->port.ops = &serial8250_pops;
+		init_timer(&up->timer);
+		up->timer.function = serial8250_timeout;
+
+		/*
+		 * ALPHA_KLUDGE_MCR needs to be killed.
+		 */
+		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+		up->mcr_force = ALPHA_KLUDGE_MCR;
+
+		uart_add_one_port(drv, &up->port);
+	}
+}
+
+#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *	Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_8250_port *up)
+{
+	unsigned int status, tmout = 10000;
+
+	/* Wait up to 10ms for the character(s) to be sent. */
+	do {
+		status = serial_in(up, UART_LSR);
+
+		if (status & UART_LSR_BI)
+			up->lsr_break_flag = UART_LSR_BI;
+
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+	/* Wait up to 1s for flow control if necessary */
+	if (up->port.flags & UPF_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout &&
+		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+			udelay(1);
+	}
+}
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ *
+ *	The console_lock must be held when we get here.
+ */
+static void
+serial8250_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_8250_port *up = &serial8250_ports[co->index];
+	unsigned int ier;
+	int i;
+
+	/*
+	 *	First save the UER then disable the interrupts
+	 */
+	ier = serial_in(up, UART_IER);
+	serial_out(up, UART_IER, 0);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(up);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		serial_out(up, UART_TX, *s);
+		if (*s == 10) {
+			wait_for_xmitr(up);
+			serial_out(up, UART_TX, 13);
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the IER
+	 */
+	wait_for_xmitr(up);
+	serial_out(up, UART_IER, ier);
+}
+
+static int __init serial8250_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index >= UART_NR)
+		co->index = 0;
+	port = &serial8250_ports[co->index].port;
+
+	/*
+	 * Temporary fix.
+	 */
+	spin_lock_init(&port->lock);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+extern struct uart_driver serial8250_reg;
+static struct console serial8250_console = {
+	.name		= "ttyS",
+	.write		= serial8250_console_write,
+	.device		= uart_console_device,
+	.setup		= serial8250_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &serial8250_reg,
+};
+
+static int __init serial8250_console_init(void)
+{
+	serial8250_isa_init_ports();
+	register_console(&serial8250_console);
+	return 0;
+}
+console_initcall(serial8250_console_init);
+
+#define SERIAL8250_CONSOLE	&serial8250_console
+#else
+#define SERIAL8250_CONSOLE	NULL
+#endif
+
+static struct uart_driver serial8250_reg = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "serial",
+	.devfs_name		= "tts/",
+	.dev_name		= "ttyS",
+	.major			= TTY_MAJOR,
+	.minor			= 64,
+	.nr			= UART_NR,
+	.cons			= SERIAL8250_CONSOLE,
+};
+
+/*
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+
+static int __register_serial(struct serial_struct *req, int line)
+{
+	struct uart_port port;
+
+	port.iobase   = req->port;
+	port.membase  = req->iomem_base;
+	port.irq      = req->irq;
+	port.uartclk  = req->baud_base * 16;
+	port.fifosize = req->xmit_fifo_size;
+	port.regshift = req->iomem_reg_shift;
+	port.iotype   = req->io_type;
+	port.flags    = req->flags | UPF_BOOT_AUTOCONF;
+	port.mapbase  = req->iomap_base;
+	port.line     = line;
+
+	if (HIGH_BITS_OFFSET)
+		port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
+
+	/*
+	 * If a clock rate wasn't specified by the low level
+	 * driver, then default to the standard clock rate.
+	 */
+	if (port.uartclk == 0)
+		port.uartclk = BASE_BAUD * 16;
+
+	return uart_register_port(&serial8250_reg, &port);
+}
+
+/**
+ *	register_serial - configure a 16x50 serial port at runtime
+ *	@req: request structure
+ *
+ *	Configure the serial port specified by the request. If the
+ *	port exists and is in use an error is returned. If the port
+ *	is not currently in the table it is added.
+ *
+ *	The port is then probed and if necessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+int register_serial(struct serial_struct *req)
+{
+	return __register_serial(req, -1);
+}
+
+int __init early_serial_setup(struct uart_port *port)
+{
+	serial8250_isa_init_ports();
+	serial8250_ports[port->line].port	= *port;
+	serial8250_ports[port->line].port.ops	= &serial8250_pops;
+	return 0;
+}
+
+/**
+ *	unregister_serial - remove a 16x50 serial port at runtime
+ *	@line: serial line number
+ *
+ *	Remove one serial port.  This may be called from interrupt
+ *	context.
+ */
+void unregister_serial(int line)
+{
+	uart_unregister_port(&serial8250_reg, line);
+}
+
+/*
+ * This is for ISAPNP only.
+ */
+void serial8250_get_irq_map(unsigned int *map)
+{
+	int i;
+
+	for (i = 0; i < UART_NR; i++) {
+		if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
+		    serial8250_ports[i].port.irq < 16)
+			*map |= 1 << serial8250_ports[i].port.irq;
+	}
+}
+
+/**
+ *	serial8250_suspend_port - suspend one serial port
+ *	@line:  serial line number
+ *      @level: the level of port suspension, as per uart_suspend_port
+ *
+ *	Suspend one serial port.
+ */
+void serial8250_suspend_port(int line)
+{
+	uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
+}
+
+/**
+ *	serial8250_resume_port - resume one serial port
+ *	@line:  serial line number
+ *      @level: the level of port resumption, as per uart_resume_port
+ *
+ *	Resume one serial port.
+ */
+void serial8250_resume_port(int line)
+{
+	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
+}
+
+static int __init serial8250_init(void)
+{
+	int ret, i;
+
+	printk(KERN_INFO "Serial: Au1x00 driver\n");
+
+	for (i = 0; i < NR_IRQS; i++)
+		spin_lock_init(&irq_lists[i].lock);
+
+	ret = uart_register_driver(&serial8250_reg);
+	if (ret >= 0)
+		serial8250_register_ports(&serial8250_reg);
+
+	return ret;
+}
+
+static void __exit serial8250_exit(void)
+{
+	int i;
+
+	for (i = 0; i < UART_NR; i++)
+		uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
+
+	uart_unregister_driver(&serial8250_reg);
+}
+
+module_init(serial8250_init);
+module_exit(serial8250_exit);
+
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+EXPORT_SYMBOL(serial8250_get_irq_map);
+EXPORT_SYMBOL(serial8250_suspend_port);
+EXPORT_SYMBOL(serial8250_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1x00 serial driver\n");
--- diff/drivers/serial/dz.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/serial/dz.c	2004-02-18 09:04:01.000000000 +0000
@@ -0,0 +1,827 @@
+/*
+ * dz.c: Serial port driver for DECStations equiped 
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+ * Changed name of dz_init to rs_init to be consistent with tc code
+ * [13-NOV-98] triemer fixed code to receive characters
+ *    after patches by harald to irq code.  
+ * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
+ *            field from "current" - somewhere between 2.1.121 and 2.1.131
+ Qua Jun 27 15:02:26 BRT 2001
+ * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
+ *  
+ * Parts (C) 1999 David Airlie, airlied@linux.ie 
+ * [07-SEP-99] Bugfixes 
+ *
+ * [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
+ * Converted to new serial core
+ */
+
+#undef DEBUG_DZ
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/bootinfo.h>
+#include <asm/dec/interrupts.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define CONSOLE_LINE (3)	/* for definition of struct console */
+
+#include "dz.h"
+
+#define DZ_INTR_DEBUG 1
+
+static char *dz_name = "DECstation DZ serial driver version ";
+static char *dz_version = "1.02";
+
+struct dz_port {
+	struct uart_port	port;
+	unsigned int		cflag;
+};
+
+static struct dz_port dz_ports[DZ_NB_PORT];
+
+#ifdef DEBUG_DZ
+/*
+ * debugging code to send out chars via prom 
+ */
+static void debug_console(const char *s, int count)
+{
+	unsigned i;
+
+	for (i = 0; i < count; i++) {
+		if (*s == 10)
+			prom_printf("%c", 13);
+		prom_printf("%c", *s++);
+	}
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+ *
+ * These routines are used to access the registers of the DZ 
+ * chip, hiding relocation differences between implementation.
+ * ------------------------------------------------------------
+ */
+
+static inline unsigned short dz_in(struct dz_port *dport, unsigned offset)
+{
+	volatile unsigned short *addr =
+		(volatile unsigned short *) (dport->port.membase + offset);
+	return *addr;
+}
+
+static inline void dz_out(struct dz_port *dport, unsigned offset,
+                          unsigned short value)
+{
+	volatile unsigned short *addr =
+		(volatile unsigned short *) (dport->port.membase + offset);
+	*addr = value;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop () and rs_start ()
+ *
+ * These routines are called before setting or resetting 
+ * tty->stopped. They enable or disable transmitter interrupts, 
+ * as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void dz_stop_tx(struct uart_port *uport, unsigned int tty_stop)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned short tmp, mask = 1 << dport->port.line;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+	tmp = dz_in(dport, DZ_TCR);	/* read the TX flag */
+	tmp &= ~mask;			/* clear the TX flag */
+	dz_out(dport, DZ_TCR, tmp);
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+static void dz_start_tx(struct uart_port *uport, unsigned int tty_start)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned short tmp, mask = 1 << dport->port.line;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+	tmp = dz_in(dport, DZ_TCR);	/* read the TX flag */
+	tmp |= mask;			/* set the TX flag */
+	dz_out(dport, DZ_TCR, tmp);
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+static void dz_stop_rx(struct uart_port *uport)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+	dport->cflag &= ~DZ_CREAD;
+	dz_out(dport, DZ_LPR, dport->cflag);
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+static void dz_enable_ms(struct uart_port *port)
+{
+	/* nothing to do */
+}
+
+/*
+ * ------------------------------------------------------------
+ * Here starts the interrupt handling routines.  All of the 
+ * following subroutines are declared as inline and are folded 
+ * into dz_interrupt.  They were separated out for readability's 
+ * sake. 
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ *	make drivers/serial/dz.s
+ *
+ * and look at the resulting assemble code in dz.s.
+ *
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * receive_char ()
+ *
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_receive_chars(struct dz_port *dport)
+{
+	struct tty_struct *tty = NULL;
+	struct uart_icount *icount;
+	int ignore = 0;
+	unsigned short status, tmp;
+	unsigned char ch;
+
+	/* this code is going to be a problem...
+	   the call to tty_flip_buffer is going to need
+	   to be rethought...
+	 */
+	do {
+		status = dz_in(dport, DZ_RBUF);
+
+		/* punt so we don't get duplicate characters */
+		if (!(status & DZ_DVAL))
+			goto ignore_char;
+
+
+		ch = UCHAR(status);	/* grab the char */
+
+#if 0
+		if (info->is_console) {
+			if (ch == 0)
+				return;		/* it's a break ... */
+		}
+#endif
+
+		tty = dport->port.info->tty;/* now tty points to the proper dev */
+		icount = &dport->port.icount;
+
+		if (!tty)
+			break;
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = 0;
+		icount->rx++;
+
+		/* keep track of the statistics */
+		if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
+			if (status & DZ_PERR)	/* parity error */
+				icount->parity++;
+			else if (status & DZ_FERR)	/* frame error */
+				icount->frame++;
+			if (status & DZ_OERR)	/* overrun error */
+				icount->overrun++;
+
+			/*  check to see if we should ignore the character
+			   and mask off conditions that should be ignored
+			 */
+
+			if (status & dport->port.ignore_status_mask) {
+				if (++ignore > 100)
+					break;
+				goto ignore_char;
+			}
+			/* mask off the error conditions we want to ignore */
+			tmp = status & dport->port.read_status_mask;
+
+			if (tmp & DZ_PERR) {
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+#ifdef DEBUG_DZ
+				debug_console("PERR\n", 5);
+#endif
+			} else if (tmp & DZ_FERR) {
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+#ifdef DEBUG_DZ
+				debug_console("FERR\n", 5);
+#endif
+			}
+			if (tmp & DZ_OERR) {
+#ifdef DEBUG_DZ
+				debug_console("OERR\n", 5);
+#endif
+				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+					tty->flip.count++;
+					tty->flip.flag_buf_ptr++;
+					tty->flip.char_buf_ptr++;
+					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				}
+			}
+		}
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	      ignore_char:
+	} while (status & DZ_DVAL);
+
+	if (tty)
+		tty_flip_buffer_push(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * transmit_char ()
+ *
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+static inline void dz_transmit_chars(struct dz_port *dport)
+{
+	struct circ_buf *xmit = &dport->port.info->xmit;
+	unsigned char tmp;
+
+	if (dport->port.x_char) {	/* XON/XOFF chars */
+		dz_out(dport, DZ_TDR, dport->port.x_char);
+		dport->port.icount.tx++;
+		dport->port.x_char = 0;
+		return;
+	}
+	/* if nothing to do or stopped or hardware stopped */
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
+		dz_stop_tx(&dport->port, 0);
+		return;
+	}
+
+	/*
+	 * if something to do ... (rember the dz has no output fifo so we go
+	 * one char at a time :-<
+	 */
+	tmp = xmit->buf[xmit->tail];
+	xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
+	dz_out(dport, DZ_TDR, tmp);
+	dport->port.icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
+		uart_write_wakeup(&dport->port);
+
+	/* Are we done */
+	if (uart_circ_empty(xmit))
+		dz_stop_tx(&dport->port, 0);
+}
+
+/*
+ * ------------------------------------------------------------
+ * check_modem_status ()
+ *
+ * Only valid for the MODEM line duh !
+ * ------------------------------------------------------------
+ */
+static inline void check_modem_status(struct dz_port *dport)
+{
+	unsigned short status;
+
+	/* if not ne modem line just return */
+	if (dport->port.line != DZ_MODEM)
+		return;
+
+	status = dz_in(dport, DZ_MSR);
+
+	/* it's easy, since DSR2 is the only bit in the register */
+	if (status)
+		dport->port.icount.dsr++;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_interrupt ()
+ *
+ * this is the main interrupt routine for the DZ chip.
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	struct dz_port *dport;
+	unsigned short status;
+
+	/* get the reason why we just got an irq */
+	status = dz_in((struct dz_port *)dev, DZ_CSR);
+	dport = &dz_ports[LINE(status)];
+
+	if (status & DZ_RDONE)
+		dz_receive_chars(dport);
+
+	if (status & DZ_TRDY)
+		dz_transmit_chars(dport);
+
+	/* FIXME: what about check modem status??? --rmk */
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the DZ interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+static unsigned int dz_get_mctrl(struct uart_port *uport)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+
+	if (dport->port.line == DZ_MODEM) {
+		/*
+		 * CHECKME: This is a guess from the other code... --rmk
+		 */
+		if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
+			mctrl &= ~TIOCM_DSR;
+	}
+
+	return mctrl;
+}
+
+static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned short tmp;
+
+	if (dport->port.line == DZ_MODEM) {
+		tmp = dz_in(dport, DZ_TCR);
+		if (mctrl & TIOCM_DTR)
+			tmp &= ~DZ_MODEM_DTR;
+		else
+			tmp |= DZ_MODEM_DTR;
+		dz_out(dport, DZ_TCR, tmp);
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * startup ()
+ *
+ * various initialization tasks
+ * ------------------------------------------------------------------- 
+ */
+static int dz_startup(struct uart_port *uport)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned long flags;
+	unsigned short tmp;
+
+	/* The dz lines for the mouse/keyboard must be
+	 * opened using their respective drivers.
+	 */
+	if ((dport->port.line == DZ_KEYBOARD) ||
+	    (dport->port.line == DZ_MOUSE))
+		return -ENODEV;
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+
+	/* enable the interrupt and the scanning */
+	tmp = dz_in(dport, DZ_CSR);
+	tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
+	dz_out(dport, DZ_CSR, tmp);
+
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+
+	return 0;
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * shutdown ()
+ *
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ * ------------------------------------------------------------------- 
+ */
+static void dz_shutdown(struct uart_port *uport)
+{
+	dz_stop_tx(uport, 0);
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows an RS485 driver to be written in user space. 
+ */
+static unsigned int dz_tx_empty(struct uart_port *uport)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned short status = dz_in(dport, DZ_LPR);
+
+	/* FIXME: this appears to be obviously broken --rmk. */
+	return status ? TIOCSER_TEMT : 0;
+}
+
+static void dz_break_ctl(struct uart_port *uport, int break_state)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned long flags;
+	unsigned short tmp, mask = 1 << uport->line;
+
+	spin_lock_irqsave(&uport->lock, flags);
+	tmp = dz_in(dport, DZ_TCR);
+	if (break_state)
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	dz_out(dport, DZ_TCR, tmp);
+	spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static void dz_set_termios(struct uart_port *uport, struct termios *termios,
+			   struct termios *old_termios)
+{
+	struct dz_port *dport = (struct dz_port *)uport;
+	unsigned long flags;
+	unsigned int cflag, baud;
+
+	cflag = dport->port.line;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		cflag |= DZ_CS5;
+		break;
+	case CS6:
+		cflag |= DZ_CS6;
+		break;
+	case CS7:
+		cflag |= DZ_CS7;
+		break;
+	case CS8:
+	default:
+		cflag |= DZ_CS8;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		cflag |= DZ_CSTOPB;
+	if (termios->c_cflag & PARENB)
+		cflag |= DZ_PARENB;
+	if (termios->c_cflag & PARODD)
+		cflag |= DZ_PARODD;
+
+	baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
+	switch (baud) {
+	case 50:
+		cflag |= DZ_B50;
+		break;
+	case 75:
+		cflag |= DZ_B75;
+		break;
+	case 110:
+		cflag |= DZ_B110;
+		break;
+	case 134:
+		cflag |= DZ_B134;
+		break;
+	case 150:
+		cflag |= DZ_B150;
+		break;
+	case 300:
+		cflag |= DZ_B300;
+		break;
+	case 600:
+		cflag |= DZ_B600;
+		break;
+	case 1200:
+		cflag |= DZ_B1200;
+		break;
+	case 1800:
+		cflag |= DZ_B1800;
+		break;
+	case 2000:
+		cflag |= DZ_B2000;
+		break;
+	case 2400:
+		cflag |= DZ_B2400;
+		break;
+	case 3600:
+		cflag |= DZ_B3600;
+		break;
+	case 4800:
+		cflag |= DZ_B4800;
+		break;
+	case 7200:
+		cflag |= DZ_B7200;
+		break;
+	case 9600:
+	default:
+		cflag |= DZ_B9600;
+	}
+
+	if (termios->c_cflag & CREAD)
+		cflag |= DZ_RXENAB;
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+
+	dz_out(dport, DZ_LPR, cflag);
+	dport->cflag = cflag;
+
+	/* setup accept flag */
+	dport->port.read_status_mask = DZ_OERR;
+	if (termios->c_iflag & INPCK)
+		dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
+
+	/* characters to ignore */
+	uport->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
+
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+
+static const char *dz_type(struct uart_port *port)
+{
+	return "DZ";
+}
+
+static void dz_release_port(struct uart_port *port)
+{
+	/* nothing to do */
+}
+
+static int dz_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void dz_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_DZ;
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int dz_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
+		ret = -EINVAL;
+	if (ser->irq != port->irq)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops dz_ops = {
+	.tx_empty	= dz_tx_empty,
+	.get_mctrl	= dz_get_mctrl,
+	.set_mctrl	= dz_set_mctrl,
+	.stop_tx	= dz_stop_tx,
+	.start_tx	= dz_start_tx,
+	.stop_rx	= dz_stop_rx,
+	.enable_ms	= dz_enable_ms,
+	.break_ctl	= dz_break_ctl,
+	.startup	= dz_startup,
+	.shutdown	= dz_shutdown,
+	.set_termios	= dz_set_termios,
+	.type		= dz_type,
+	.release_port	= dz_release_port,
+	.request_port	= dz_request_port,
+	.config_port	= dz_config_port,
+	.verify_port	= dz_verify_port,
+};
+
+static void __init dz_init_ports(void)
+{
+	static int first = 1;
+	struct dz_port *dport;
+	unsigned long base;
+	int i;
+
+	if (!first)
+		return;
+	first = 0;
+
+	if (mips_machtype == MACH_DS23100 ||
+	    mips_machtype == MACH_DS5100)
+		base = (unsigned long) KN01_DZ11_BASE;
+	else
+		base = (unsigned long) KN02_DZ11_BASE;
+
+	for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
+		spin_lock_init(&dport->port.lock);
+		dport->port.membase	= (char *) base;
+		dport->port.iotype	= SERIAL_IO_PORT;
+		dport->port.irq		= dec_interrupt[DEC_IRQ_DZ11];
+		dport->port.line	= i;
+		dport->port.fifosize	= 1;
+		dport->port.ops		= &dz_ops;
+		dport->port.flags	= UPF_BOOT_AUTOCONF;
+	}
+}
+
+static void dz_reset(struct dz_port *dport)
+{
+	dz_out(dport, DZ_CSR, DZ_CLR);
+
+	while (dz_in(dport, DZ_CSR) & DZ_CLR);
+		/* FIXME: cpu_relax? */
+
+	iob();
+
+	/* enable scanning */
+	dz_out(dport, DZ_CSR, DZ_MSE);
+}
+
+#ifdef CONFIG_SERIAL_DZ_CONSOLE
+static void dz_console_put_char(struct dz_port *dport, unsigned char ch)
+{
+	unsigned long flags;
+	int loops = 2500;
+	unsigned short tmp = ch;
+	/* this code sends stuff out to serial device - spinning its
+	   wheels and waiting. */
+
+	spin_lock_irqsave(&dport->port.lock, flags);
+
+	/* spin our wheels */
+	while (((dz_in(dport, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--)
+		/* FIXME: cpu_relax, udelay? --rmk */
+		;
+
+	/* Actually transmit the character. */
+	dz_out(dport, DZ_TDR, tmp);
+
+	spin_unlock_irqrestore(&dport->port.lock, flags);
+}
+/* 
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+ *
+ * dz_console_print is registered for printk.
+ * The console must be locked when we get here.
+ * ------------------------------------------------------------------- 
+ */
+static void dz_console_print(struct console *cons,
+			     const char *str,
+			     unsigned int count)
+{
+	struct dz_port *dport = &dz_ports[CONSOLE_LINE];
+#ifdef DEBUG_DZ
+	prom_printf((char *) str);
+#endif
+	while (count--) {
+		if (*str == '\n')
+			dz_console_put_char(dport, '\r');
+		dz_console_put_char(dport, *str++);
+	}
+}
+
+static int __init dz_console_setup(struct console *co, char *options)
+{
+	struct dz_port *dport = &dz_ports[CONSOLE_LINE];
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+	unsigned short mask, tmp;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	dz_reset(dport);
+
+	ret = uart_set_options(&dport->port, co, baud, parity, bits, flow);
+	if (ret == 0) {
+		mask = 1 << dport->port.line;
+		tmp = dz_in(dport, DZ_TCR);	/* read the TX flag */
+		if (!(tmp & mask)) {
+			tmp |= mask;		/* set the TX flag */
+			dz_out(dport, DZ_TCR, tmp);
+		}
+	}
+
+	return ret;
+}
+
+static struct console dz_sercons =
+{
+	.name	= "ttyS",
+	.write	= dz_console_print,
+	.device	= uart_console_device,
+	.setup	= dz_console_setup,
+	.flags	= CON_CONSDEV | CON_PRINTBUFFER,
+	.index	= CONSOLE_LINE,
+};
+
+void __init dz_serial_console_init(void)
+{
+	dz_init_ports();
+
+	register_console(&dz_sercons);
+}
+
+#define SERIAL_DZ_CONSOLE	&dz_sercons
+#else
+#define SERIAL_DZ_CONSOLE	NULL
+#endif /* CONFIG_SERIAL_DZ_CONSOLE */
+
+static struct uart_driver dz_reg = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "serial",
+#ifdef CONFIG_DEVFS
+	.dev_name		= "tts/%d",
+#else
+	.dev_name		= "ttyS%d",
+#endif
+	.major			= TTY_MAJOR,
+	.minor			= 64,
+	.nr			= DZ_NB_PORT,
+	.cons			= SERIAL_DZ_CONSOLE,
+};
+
+int __init dz_init(void)
+{
+	unsigned long flags;
+	int ret, i;
+
+	printk("%s%s\n", dz_name, dz_version);
+
+	dz_init_ports();
+
+	save_flags(flags);
+	cli();
+
+#ifndef CONFIG_SERIAL_DZ_CONSOLE
+	/* reset the chip */
+	dz_reset(&dz_ports[0]);
+#endif
+
+	/* order matters here... the trick is that flags
+	   is updated... in request_irq - to immediatedly obliterate
+	   it is unwise. */
+	restore_flags(flags);
+
+	if (request_irq(dz_ports[0].port.irq, dz_interrupt,
+			SA_INTERRUPT, "DZ", &dz_ports[0]))
+		panic("Unable to register DZ interrupt");
+
+	ret = uart_register_driver(&dz_reg);
+	if (ret != 0)
+		return ret;
+
+	for (i = 0; i < DZ_NB_PORT; i++)
+		uart_add_one_port(&dz_reg, &dz_ports[i].port);
+
+	return ret;
+}
+
+MODULE_DESCRIPTION("DECstation DZ serial driver");
+MODULE_LICENSE("GPL");
--- diff/drivers/serial/dz.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/serial/dz.h	2004-02-18 09:04:01.000000000 +0000
@@ -0,0 +1,118 @@
+/*
+ * dz.h: Serial port driver for DECStations equiped 
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ */
+#ifndef DZ_SERIAL_H
+#define DZ_SERIAL_H
+
+/*
+ * Definitions for the Control and Status Received.
+ */
+#define DZ_TRDY        0x8000                 /* Transmitter empty */
+#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enable */
+#define DZ_RDONE       0x0080                 /* Receiver data ready */
+#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
+#define DZ_MSE         0x0020                 /* Master Scan Enable */
+#define DZ_CLR         0x0010                 /* Master reset */
+#define DZ_MAINT       0x0008                 /* Loop Back Mode */
+
+/*
+ * Definitions for the Received buffer. 
+ */
+#define DZ_RBUF_MASK   0x00FF                 /* Data Mask in the Receive Buffer */
+#define DZ_LINE_MASK   0x0300                 /* Line Mask in the Receive Buffer */
+#define DZ_DVAL        0x8000                 /* Valid Data indicator */
+#define DZ_OERR        0x4000                 /* Overrun error indicator */
+#define DZ_FERR        0x2000                 /* Frame error indicator */
+#define DZ_PERR        0x1000                 /* Parity error indicator */
+
+#define LINE(x) (x & DZ_LINE_MASK) >> 8       /* Get the line number from the input buffer */
+#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK)
+
+/*
+ * Definitions for the Transmit Register.
+ */
+#define DZ_LINE_KEYBOARD 0x0001
+#define DZ_LINE_MOUSE    0x0002
+#define DZ_LINE_MODEM    0x0004
+#define DZ_LINE_PRINTER  0x0008
+
+#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
+
+/*
+ * Definitions for the Modem Status Register.
+ */
+#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
+
+/*
+ * Definitions for the Transmit Data Register.
+ */
+#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
+#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
+#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
+#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
+
+/*
+ * Definitions for the Line Parameter Register.
+ */
+#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
+#define DZ_MOUSE         0x0001               /* line 1 = mouse */
+#define DZ_MODEM         0x0002               /* line 2 = modem */
+#define DZ_PRINTER       0x0003               /* line 3 = printer */
+
+#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
+#define DZ_CS5           0x0000               /* 5 bits per byte */
+#define DZ_CS6           0x0008               /* 6 bits per byte */
+#define DZ_CS7           0x0010               /* 7 bits per byte */
+#define DZ_CS8           0x0018               /* 8 bits per byte */
+
+#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
+
+#define DZ_PARENB        0x0040               /* Parity enable */
+#define DZ_PARODD        0x0080               /* Odd parity instead of even */
+
+#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
+#define DZ_B50           0x0000
+#define DZ_B75           0x0100
+#define DZ_B110          0x0200
+#define DZ_B134          0x0300
+#define DZ_B150          0x0400
+#define DZ_B300          0x0500
+#define DZ_B600          0x0600
+#define DZ_B1200         0x0700 
+#define DZ_B1800         0x0800
+#define DZ_B2000         0x0900
+#define DZ_B2400         0x0A00
+#define DZ_B3600         0x0B00
+#define DZ_B4800         0x0C00
+#define DZ_B7200         0x0D00
+#define DZ_B9600         0x0E00
+
+#define DZ_CREAD         0x1000               /* Enable receiver */
+#define DZ_RXENAB        0x1000               /* enable receive char */
+/*
+ * Addresses for the DZ registers
+ */
+#define DZ_CSR       0x00            /* Control and Status Register */
+#define DZ_RBUF      0x08            /* Receive Buffer */
+#define DZ_LPR       0x08            /* Line Parameters Register */
+#define DZ_TCR       0x10            /* Transmitter Control Register */
+#define DZ_MSR       0x18            /* Modem Status Register */
+#define DZ_TDR       0x18            /* Transmit Data Register */
+
+#define DZ_NB_PORT 4
+
+#define DZ_XMIT_SIZE   4096                 /* buffer size */
+#define DZ_WAKEUP_CHARS   DZ_XMIT_SIZE/4
+
+#ifdef MODULE
+int init_module (void)
+void cleanup_module (void)
+#endif
+
+#endif /* DZ_SERIAL_H */
--- diff/drivers/serial/ip22zilog.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/serial/ip22zilog.c	2004-02-18 09:04:01.000000000 +0000
@@ -0,0 +1,1307 @@
+/*
+ * Driver for Zilog serial chips found on SGI workstations and
+ * servers.  This driver could actually be made more generic.
+ *
+ * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the
+ * old drivers/sgi/char/sgiserial.c code which itself is based of the original
+ * drivers/sbus/char/zs.c code.  A lot of code has been simply moved over
+ * directly from there but much has been rewritten.  Credits therefore go out
+ * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell
+ * for their work there.
+ *
+ *  Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
+ *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sgialib.h>
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
+
+#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#include "ip22zilog.h"
+
+int ip22serial_current_minor = 64;
+
+void ip22_do_break(void);
+
+/*
+ * On IP22 we need to delay after register accesses but we do not need to
+ * flush writes.
+ */
+#define ZSDELAY()		udelay(5)
+#define ZSDELAY_LONG()		udelay(20)
+#define ZS_WSYNC(channel)	do { } while (0)
+
+#define NUM_IP22ZILOG	1
+#define NUM_CHANNELS	(NUM_IP22ZILOG * 2)
+
+#define ZS_CLOCK		4915200 /* Zilog input clock rate. */
+#define ZS_CLOCK_DIVISOR	16      /* Divisor this driver uses. */
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct uart_ip22zilog_port {
+	struct uart_port		port;
+
+	/* IRQ servicing chain.  */
+	struct uart_ip22zilog_port	*next;
+
+	/* Current values of Zilog write registers.  */
+	unsigned char			curregs[NUM_ZSREGS];
+
+	unsigned int			flags;
+#define IP22ZILOG_FLAG_IS_CONS		0x00000004
+#define IP22ZILOG_FLAG_IS_KGDB		0x00000008
+#define IP22ZILOG_FLAG_MODEM_STATUS	0x00000010
+#define IP22ZILOG_FLAG_IS_CHANNEL_A	0x00000020
+#define IP22ZILOG_FLAG_REGS_HELD	0x00000040
+#define IP22ZILOG_FLAG_TX_STOPPED	0x00000080
+#define IP22ZILOG_FLAG_TX_ACTIVE	0x00000100
+
+	unsigned int cflag;
+
+	/* L1-A keyboard break state.  */
+	int				kbd_id;
+	int				l1_down;
+
+	unsigned char			parity_mask;
+	unsigned char			prev_status;
+};
+
+#define ZILOG_CHANNEL_FROM_PORT(PORT)	((struct zilog_channel *)((PORT)->membase))
+#define UART_ZILOG(PORT)		((struct uart_ip22zilog_port *)(PORT))
+#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM)		\
+	(UART_ZILOG(PORT)->curregs[REGNUM])
+#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL)	\
+	((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL))
+#define ZS_IS_CONS(UP)	((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
+#define ZS_IS_KGDB(UP)	((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
+#define ZS_WANTS_MODEM_STATUS(UP)	((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
+#define ZS_IS_CHANNEL_A(UP)	((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
+#define ZS_REGS_HELD(UP)	((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
+#define ZS_TX_STOPPED(UP)	((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
+#define ZS_TX_ACTIVE(UP)	((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
+
+/* Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the IP22 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ *
+ * The port lock must be held and local IRQs must be disabled
+ * when {read,write}_zsreg is invoked.
+ */
+static unsigned char read_zsreg(struct zilog_channel *channel,
+				unsigned char reg)
+{
+	unsigned char retval;
+
+	writeb(reg, &channel->control);
+	ZSDELAY();
+	retval = readb(&channel->control);
+	ZSDELAY();
+
+	return retval;
+}
+
+static void write_zsreg(struct zilog_channel *channel,
+			unsigned char reg, unsigned char value)
+{
+	writeb(reg, &channel->control);
+	ZSDELAY();
+	writeb(value, &channel->control);
+	ZSDELAY();
+}
+
+static void ip22zilog_clear_fifo(struct zilog_channel *channel)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		unsigned char regval;
+
+		regval = readb(&channel->control);
+		ZSDELAY();
+		if (regval & Rx_CH_AV)
+			break;
+
+		regval = read_zsreg(channel, R1);
+		readb(&channel->data);
+		ZSDELAY();
+
+		if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+			writeb(ERR_RES, &channel->control);
+			ZSDELAY();
+			ZS_WSYNC(channel);
+		}
+	}
+}
+
+/* This function must only be called when the TX is not busy.  The UART
+ * port lock must be held and local interrupts disabled.
+ */
+static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs)
+{
+	int i;
+
+	/* Let pending transmits finish.  */
+	for (i = 0; i < 1000; i++) {
+		unsigned char stat = read_zsreg(channel, R1);
+		if (stat & ALL_SNT)
+			break;
+		udelay(100);
+	}
+
+	writeb(ERR_RES, &channel->control);
+	ZSDELAY();
+	ZS_WSYNC(channel);
+
+	ip22zilog_clear_fifo(channel);
+
+	/* Disable all interrupts.  */
+	write_zsreg(channel, R1,
+		    regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
+
+	/* Set parity, sync config, stop bits, and clock divisor.  */
+	write_zsreg(channel, R4, regs[R4]);
+
+	/* Set misc. TX/RX control bits.  */
+	write_zsreg(channel, R10, regs[R10]);
+
+	/* Set TX/RX controls sans the enable bits.  */
+	write_zsreg(channel, R3, regs[R3] & ~RxENAB);
+	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+
+	/* Synchronous mode config.  */
+	write_zsreg(channel, R6, regs[R6]);
+	write_zsreg(channel, R7, regs[R7]);
+
+	/* Don't mess with the interrupt vector (R2, unused by us) and
+	 * master interrupt control (R9).  We make sure this is setup
+	 * properly at probe time then never touch it again.
+	 */
+
+	/* Disable baud generator.  */
+	write_zsreg(channel, R14, regs[R14] & ~BRENAB);
+
+	/* Clock mode control.  */
+	write_zsreg(channel, R11, regs[R11]);
+
+	/* Lower and upper byte of baud rate generator divisor.  */
+	write_zsreg(channel, R12, regs[R12]);
+	write_zsreg(channel, R13, regs[R13]);
+	
+	/* Now rewrite R14, with BRENAB (if set).  */
+	write_zsreg(channel, R14, regs[R14]);
+
+	/* External status interrupt control.  */
+	write_zsreg(channel, R15, regs[R15]);
+
+	/* Reset external status interrupts.  */
+	write_zsreg(channel, R0, RES_EXT_INT);
+	write_zsreg(channel, R0, RES_EXT_INT);
+
+	/* Rewrite R3/R5, this time without enables masked.  */
+	write_zsreg(channel, R3, regs[R3]);
+	write_zsreg(channel, R5, regs[R5]);
+
+	/* Rewrite R1, this time without IRQ enabled masked.  */
+	write_zsreg(channel, R1, regs[R1]);
+}
+
+/* Reprogram the Zilog channel HW registers with the copies found in the
+ * software state struct.  If the transmitter is busy, we defer this update
+ * until the next TX complete interrupt.  Else, we do it right now.
+ *
+ * The UART port lock must be held and local interrupts disabled.
+ */
+static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
+				       struct zilog_channel *channel)
+{
+	if (!ZS_REGS_HELD(up)) {
+		if (ZS_TX_ACTIVE(up)) {
+			up->flags |= IP22ZILOG_FLAG_REGS_HELD;
+		} else {
+			__load_zsregs(channel, up->curregs);
+		}
+	}
+}
+
+static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+				   struct zilog_channel *channel,
+				   struct pt_regs *regs)
+{
+	struct tty_struct *tty = up->port.info->tty;	/* XXX info==NULL? */
+
+	while (1) {
+		unsigned char ch, r1;
+
+		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+			tty->flip.work.func((void *)tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return;		/* XXX Ignores SysRq when we need it most. Fix. */
+		}
+
+		r1 = read_zsreg(channel, R1);
+		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+			writeb(ERR_RES, &channel->control);
+			ZSDELAY();
+			ZS_WSYNC(channel);
+		}
+
+		ch = readb(&channel->control);
+		ZSDELAY();
+
+		/* This funny hack depends upon BRK_ABRT not interfering
+		 * with the other bits we care about in R1.
+		 */
+		if (ch & BRK_ABRT)
+			r1 |= BRK_ABRT;
+
+		ch = readb(&channel->data);
+		ZSDELAY();
+
+		ch &= up->parity_mask;
+
+		if (ZS_IS_CONS(up) && (r1 & BRK_ABRT)) {
+			/* Wait for BREAK to deassert to avoid potentially
+			 * confusing the PROM.
+			 */
+			while (1) {
+				ch = readb(&channel->control);
+				ZSDELAY();
+				if (!(ch & BRK_ABRT))
+					break;
+			}
+			ip22_do_break();
+			return;
+		}
+
+		/* A real serial line, record the character and status.  */
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		up->port.icount.rx++;
+		if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
+			if (r1 & BRK_ABRT) {
+				r1 &= ~(PAR_ERR | CRC_ERR);
+				up->port.icount.brk++;
+				if (uart_handle_break(&up->port))
+					goto next_char;
+			}
+			else if (r1 & PAR_ERR)
+				up->port.icount.parity++;
+			else if (r1 & CRC_ERR)
+				up->port.icount.frame++;
+			if (r1 & Rx_OVR)
+				up->port.icount.overrun++;
+			r1 &= up->port.read_status_mask;
+			if (r1 & BRK_ABRT)
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+			else if (r1 & PAR_ERR)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (r1 & CRC_ERR)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+		if (uart_handle_sysrq_char(&up->port, ch, regs))
+			goto next_char;
+
+		if (up->port.ignore_status_mask == 0xff ||
+		    (r1 & up->port.ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((r1 & Rx_OVR) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+	next_char:
+		ch = readb(&channel->control);
+		ZSDELAY();
+		if (!(ch & Rx_CH_AV))
+			break;
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
+				   struct zilog_channel *channel,
+				   struct pt_regs *regs)
+{
+	unsigned char status;
+
+	status = readb(&channel->control);
+	ZSDELAY();
+
+	writeb(RES_EXT_INT, &channel->control);
+	ZSDELAY();
+	ZS_WSYNC(channel);
+
+	if (ZS_WANTS_MODEM_STATUS(up)) {
+		if (status & SYNC)
+			up->port.icount.dsr++;
+
+		/* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
+		 * But it does not tell us which bit has changed, we have to keep
+		 * track of this ourselves.
+		 */
+		if ((status & DCD) ^ up->prev_status)
+			uart_handle_dcd_change(&up->port,
+					       (status & DCD));
+		if ((status & CTS) ^ up->prev_status)
+			uart_handle_cts_change(&up->port,
+					       (status & CTS));
+
+		wake_up_interruptible(&up->port.info->delta_msr_wait);
+	}
+
+	up->prev_status = status;
+}
+
+static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
+				    struct zilog_channel *channel)
+{
+	struct circ_buf *xmit;
+
+	if (ZS_IS_CONS(up)) {
+		unsigned char status = readb(&channel->control);
+		ZSDELAY();
+
+		/* TX still busy?  Just wait for the next TX done interrupt.
+		 *
+		 * It can occur because of how we do serial console writes.  It would
+		 * be nice to transmit console writes just like we normally would for
+		 * a TTY line. (ie. buffered and TX interrupt driven).  That is not
+		 * easy because console writes cannot sleep.  One solution might be
+		 * to poll on enough port->xmit space becomming free.  -DaveM
+		 */
+		if (!(status & Tx_BUF_EMP))
+			return;
+	}
+
+	up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE;
+
+	if (ZS_REGS_HELD(up)) {
+		__load_zsregs(channel, up->curregs);
+		up->flags &= ~IP22ZILOG_FLAG_REGS_HELD;
+	}
+
+	if (ZS_TX_STOPPED(up)) {
+		up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+		goto ack_tx_int;
+	}
+
+	if (up->port.x_char) {
+		up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+		writeb(up->port.x_char, &channel->data);
+		ZSDELAY();
+		ZS_WSYNC(channel);
+
+		up->port.icount.tx++;
+		up->port.x_char = 0;
+		return;
+	}
+
+	if (up->port.info == NULL)
+		goto ack_tx_int;
+	xmit = &up->port.info->xmit;
+	if (uart_circ_empty(xmit)) {
+		uart_write_wakeup(&up->port);
+		goto ack_tx_int;
+	}
+	if (uart_tx_stopped(&up->port))
+		goto ack_tx_int;
+
+	up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+	writeb(xmit->buf[xmit->tail], &channel->data);
+	ZSDELAY();
+	ZS_WSYNC(channel);
+
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	up->port.icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&up->port);
+
+	return;
+
+ack_tx_int:
+	writeb(RES_Tx_P, &channel->control);
+	ZSDELAY();
+	ZS_WSYNC(channel);
+}
+
+static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_ip22zilog_port *up = dev_id;
+
+	while (up) {
+		struct zilog_channel *channel
+			= ZILOG_CHANNEL_FROM_PORT(&up->port);
+		unsigned char r3;
+
+		spin_lock(&up->port.lock);
+		r3 = read_zsreg(channel, R3);
+
+		/* Channel A */
+		if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+			writeb(RES_H_IUS, &channel->control);
+			ZSDELAY();
+			ZS_WSYNC(channel);
+
+			if (r3 & CHARxIP)
+				ip22zilog_receive_chars(up, channel, regs);
+			if (r3 & CHAEXT)
+				ip22zilog_status_handle(up, channel, regs);
+			if (r3 & CHATxIP)
+				ip22zilog_transmit_chars(up, channel);
+		}
+		spin_unlock(&up->port.lock);
+
+		/* Channel B */
+		up = up->next;
+		channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+		spin_lock(&up->port.lock);
+		if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+			writeb(RES_H_IUS, &channel->control);
+			ZSDELAY();
+			ZS_WSYNC(channel);
+
+			if (r3 & CHBRxIP)
+				ip22zilog_receive_chars(up, channel, regs);
+			if (r3 & CHBEXT)
+				ip22zilog_status_handle(up, channel, regs);
+			if (r3 & CHBTxIP)
+				ip22zilog_transmit_chars(up, channel);
+		}
+		spin_unlock(&up->port.lock);
+
+		up = up->next;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* A convenient way to quickly get R0 status.  The caller must _not_ hold the
+ * port lock, it is acquired here.
+ */
+static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
+{
+	struct zilog_channel *channel;
+	unsigned long flags;
+	unsigned char status;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	channel = ZILOG_CHANNEL_FROM_PORT(port);
+	status = readb(&channel->control);
+	ZSDELAY();
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return status;
+}
+
+/* The port lock is not held.  */
+static unsigned int ip22zilog_tx_empty(struct uart_port *port)
+{
+	unsigned char status;
+	unsigned int ret;
+
+	status = ip22zilog_read_channel_status(port);
+	if (status & Tx_BUF_EMP)
+		ret = TIOCSER_TEMT;
+	else
+		ret = 0;
+
+	return ret;
+}
+
+/* The port lock is not held.  */
+static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
+{
+	unsigned char status;
+	unsigned int ret;
+
+	status = ip22zilog_read_channel_status(port);
+
+	ret = 0;
+	if (status & DCD)
+		ret |= TIOCM_CAR;
+	if (status & SYNC)
+		ret |= TIOCM_DSR;
+	if (status & CTS)
+		ret |= TIOCM_CTS;
+
+	return ret;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+	unsigned char set_bits, clear_bits;
+
+	set_bits = clear_bits = 0;
+
+	if (mctrl & TIOCM_RTS)
+		set_bits |= RTS;
+	else
+		clear_bits |= RTS;
+	if (mctrl & TIOCM_DTR)
+		set_bits |= DTR;
+	else
+		clear_bits |= DTR;
+
+	/* NOTE: Not subject to 'transmitter active' rule.  */ 
+	up->curregs[R5] |= set_bits;
+	up->curregs[R5] &= ~clear_bits;
+	write_zsreg(channel, R5, up->curregs[R5]);
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+
+	up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
+}
+
+/* The port lock is held and interrupts are disabled.  */
+static void ip22zilog_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+	unsigned char status;
+
+	up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
+	up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED;
+
+	status = readb(&channel->control);
+	ZSDELAY();
+
+	/* TX busy?  Just wait for the TX done interrupt.  */
+	if (!(status & Tx_BUF_EMP))
+		return;
+
+	/* Send the first character to jump-start the TX done
+	 * IRQ sending engine.
+	 */
+	if (port->x_char) {
+		writeb(port->x_char, &channel->data);
+		ZSDELAY();
+		ZS_WSYNC(channel);
+
+		port->icount.tx++;
+		port->x_char = 0;
+	} else {
+		struct circ_buf *xmit = &port->info->xmit;
+
+		writeb(xmit->buf[xmit->tail], &channel->data);
+		ZSDELAY();
+		ZS_WSYNC(channel);
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+
+		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+			uart_write_wakeup(&up->port);
+	}
+}
+
+/* The port lock is not held.  */
+static void ip22zilog_stop_rx(struct uart_port *port)
+{
+	struct uart_ip22zilog_port *up = UART_ZILOG(port);
+	struct zilog_channel *channel;
+	unsigned long flags;
+
+	if (ZS_IS_CONS(up))
+		return;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+	/* Disable all RX interrupts.  */
+	up->curregs[R1] &= ~RxINT_MASK;
+	ip22zilog_maybe_update_regs(up, channel);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* The port lock is not held.  */
+static void ip22zilog_enable_ms(struct uart_port *port)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+	unsigned char new_reg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
+	if (new_reg != up->curregs[R15]) {
+		up->curregs[R15] = new_reg;
+
+		/* NOTE: Not subject to 'transmitter active' rule.  */ 
+		write_zsreg(channel, R15, up->curregs[R15]);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* The port lock is not held.  */
+static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+	unsigned char set_bits, clear_bits, new_reg;
+	unsigned long flags;
+
+	set_bits = clear_bits = 0;
+
+	if (break_state)
+		set_bits |= SND_BRK;
+	else
+		clear_bits |= SND_BRK;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
+	if (new_reg != up->curregs[R5]) {
+		up->curregs[R5] = new_reg;
+
+		/* NOTE: Not subject to 'transmitter active' rule.  */ 
+		write_zsreg(channel, R5, up->curregs[R5]);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
+{
+	struct zilog_channel *channel;
+
+	channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+	up->prev_status = readb(&channel->control);
+
+	/* Enable receiver and transmitter.  */
+	up->curregs[R3] |= RxENAB;
+	up->curregs[R5] |= TxENAB;
+
+	up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+	ip22zilog_maybe_update_regs(up, channel);
+}
+
+static int ip22zilog_startup(struct uart_port *port)
+{
+	struct uart_ip22zilog_port *up = UART_ZILOG(port);
+	unsigned long flags;
+
+	if (ZS_IS_CONS(up))
+		return 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+	__ip22zilog_startup(up);
+	spin_unlock_irqrestore(&port->lock, flags);
+	return 0;
+}
+
+/*
+ * The test for ZS_IS_CONS is explained by the following e-mail:
+ *****
+ * From: Russell King <rmk@arm.linux.org.uk>
+ * Date: Sun, 8 Dec 2002 10:18:38 +0000
+ *
+ * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote:
+ * > I boot my 2.5 boxes using "console=ttyS0,9600" argument,
+ * > and I noticed that something is not right with reference
+ * > counting in this case. It seems that when the console
+ * > is open by kernel initially, this is not accounted
+ * > as an open, and uart_startup is not called.
+ *
+ * That is correct.  We are unable to call uart_startup when the serial
+ * console is initialised because it may need to allocate memory (as
+ * request_irq does) and the memory allocators may not have been
+ * initialised.
+ *
+ * 1. initialise the port into a state where it can send characters in the
+ *    console write method.
+ *
+ * 2. don't do the actual hardware shutdown in your shutdown() method (but
+ *    do the normal software shutdown - ie, free irqs etc)
+ *****
+ */
+static void ip22zilog_shutdown(struct uart_port *port)
+{
+	struct uart_ip22zilog_port *up = UART_ZILOG(port);
+	struct zilog_channel *channel;
+	unsigned long flags;
+
+	if (ZS_IS_CONS(up))
+		return;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	channel = ZILOG_CHANNEL_FROM_PORT(port);
+
+	/* Disable receiver and transmitter.  */
+	up->curregs[R3] &= ~RxENAB;
+	up->curregs[R5] &= ~TxENAB;
+
+	/* Disable all interrupts and BRK assertion.  */
+	up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+	up->curregs[R5] &= ~SND_BRK;
+	ip22zilog_maybe_update_regs(up, channel);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Shared by TTY driver and serial console setup.  The port lock is held
+ * and local interrupts are disabled.
+ */
+static void
+ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,
+		       unsigned int iflag, int brg)
+{
+
+	up->curregs[R10] = NRZ;
+	up->curregs[R11] = TCBR | RCBR;
+
+	/* Program BAUD and clock source. */
+	up->curregs[R4] &= ~XCLK_MASK;
+	up->curregs[R4] |= X16CLK;
+	up->curregs[R12] = brg & 0xff;
+	up->curregs[R13] = (brg >> 8) & 0xff;
+	up->curregs[R14] = BRSRC | BRENAB;
+
+	/* Character size, stop bits, and parity. */
+	up->curregs[3] &= ~RxN_MASK;
+	up->curregs[5] &= ~TxN_MASK;
+	switch (cflag & CSIZE) {
+	case CS5:
+		up->curregs[3] |= Rx5;
+		up->curregs[5] |= Tx5;
+		up->parity_mask = 0x1f;
+		break;
+	case CS6:
+		up->curregs[3] |= Rx6;
+		up->curregs[5] |= Tx6;
+		up->parity_mask = 0x3f;
+		break;
+	case CS7:
+		up->curregs[3] |= Rx7;
+		up->curregs[5] |= Tx7;
+		up->parity_mask = 0x7f;
+		break;
+	case CS8:
+	default:
+		up->curregs[3] |= Rx8;
+		up->curregs[5] |= Tx8;
+		up->parity_mask = 0xff;
+		break;
+	};
+	up->curregs[4] &= ~0x0c;
+	if (cflag & CSTOPB)
+		up->curregs[4] |= SB2;
+	else
+		up->curregs[4] |= SB1;
+	if (cflag & PARENB)
+		up->curregs[4] |= PAR_ENAB;
+	else
+		up->curregs[4] &= ~PAR_ENAB;
+	if (!(cflag & PARODD))
+		up->curregs[4] |= PAR_EVEN;
+	else
+		up->curregs[4] &= ~PAR_EVEN;
+
+	up->port.read_status_mask = Rx_OVR;
+	if (iflag & INPCK)
+		up->port.read_status_mask |= CRC_ERR | PAR_ERR;
+	if (iflag & (BRKINT | PARMRK))
+		up->port.read_status_mask |= BRK_ABRT;
+
+	up->port.ignore_status_mask = 0;
+	if (iflag & IGNPAR)
+		up->port.ignore_status_mask |= CRC_ERR | PAR_ERR;
+	if (iflag & IGNBRK) {
+		up->port.ignore_status_mask |= BRK_ABRT;
+		if (iflag & IGNPAR)
+			up->port.ignore_status_mask |= Rx_OVR;
+	}
+
+	if ((cflag & CREAD) == 0)
+		up->port.ignore_status_mask = 0xff;
+}
+
+/* The port lock is not held.  */
+static void
+ip22zilog_set_termios(struct uart_port *port, struct termios *termios,
+		      struct termios *old)
+{
+	struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
+	unsigned long flags;
+	int baud, brg;
+
+	baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+	ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg);
+
+	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+		up->flags |= IP22ZILOG_FLAG_MODEM_STATUS;
+	else
+		up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
+
+	up->cflag = termios->c_cflag;
+
+	ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *ip22zilog_type(struct uart_port *port)
+{
+	return "IP22-Zilog";
+}
+
+/* We do not request/release mappings of the registers here, this
+ * happens at early serial probe time.
+ */
+static void ip22zilog_release_port(struct uart_port *port)
+{
+}
+
+static int ip22zilog_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* These do not need to do anything interesting either.  */
+static void ip22zilog_config_port(struct uart_port *port, int flags)
+{
+}
+
+/* We do not support letting the user mess with the divisor, IRQ, etc. */
+static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	return -EINVAL;
+}
+
+static struct uart_ops ip22zilog_pops = {
+	.tx_empty	=	ip22zilog_tx_empty,
+	.set_mctrl	=	ip22zilog_set_mctrl,
+	.get_mctrl	=	ip22zilog_get_mctrl,
+	.stop_tx	=	ip22zilog_stop_tx,
+	.start_tx	=	ip22zilog_start_tx,
+	.stop_rx	=	ip22zilog_stop_rx,
+	.enable_ms	=	ip22zilog_enable_ms,
+	.break_ctl	=	ip22zilog_break_ctl,
+	.startup	=	ip22zilog_startup,
+	.shutdown	=	ip22zilog_shutdown,
+	.set_termios	=	ip22zilog_set_termios,
+	.type		=	ip22zilog_type,
+	.release_port	=	ip22zilog_release_port,
+	.request_port	=	ip22zilog_request_port,
+	.config_port	=	ip22zilog_config_port,
+	.verify_port	=	ip22zilog_verify_port,
+};
+
+static struct uart_ip22zilog_port *ip22zilog_port_table;
+static struct zilog_layout **ip22zilog_chip_regs;
+
+static struct uart_ip22zilog_port *ip22zilog_irq_chain;
+static int zilog_irq = -1;
+
+static struct uart_driver ip22zilog_reg = {
+	.owner		=	THIS_MODULE,
+	.driver_name	=	"ttyS",
+	.devfs_name	=	"tty/",
+	.major		=	TTY_MAJOR,
+};
+
+static void * __init alloc_one_table(unsigned long size)
+{
+	void *ret;
+
+	ret = kmalloc(size, GFP_KERNEL);
+	if (ret != NULL)
+		memset(ret, 0, size);
+
+	return ret;
+}
+
+static void __init ip22zilog_alloc_tables(void)
+{
+	ip22zilog_port_table = (struct uart_ip22zilog_port *)
+		alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
+	ip22zilog_chip_regs = (struct zilog_layout **)
+		alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
+
+	if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
+		panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
+	}
+}
+
+/* Get the address of the registers for IP22-Zilog instance CHIP.  */
+static struct zilog_layout * __init get_zs(int chip)
+{
+	unsigned long base;
+
+	if (chip < 0 || chip >= NUM_IP22ZILOG) {
+		panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
+	}
+
+	/* Not probe-able, hard code it. */
+	base = (unsigned long) &sgioc->serport;
+
+	zilog_irq = SGI_SERIAL_IRQ;
+	request_mem_region(base, 8, "IP22-Zilog");
+
+	return (struct zilog_layout *) base;
+}
+
+#define ZS_PUT_CHAR_MAX_DELAY	2000	/* 10 ms */
+
+#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
+static void ip22zilog_put_char(struct zilog_channel *channel, unsigned char ch)
+{
+	int loops = ZS_PUT_CHAR_MAX_DELAY;
+
+	/* This is a timed polling loop so do not switch the explicit
+	 * udelay with ZSDELAY as that is a NOP on some platforms.  -DaveM
+	 */
+	do {
+		unsigned char val = readb(&channel->control);
+		if (val & Tx_BUF_EMP) {
+			ZSDELAY();
+			break;
+		}
+		udelay(5);
+	} while (--loops);
+
+	writeb(ch, &channel->data);
+	ZSDELAY();
+	ZS_WSYNC(channel);
+}
+
+static void
+ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
+{
+	struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+	struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	for (i = 0; i < count; i++, s++) {
+		ip22zilog_put_char(channel, *s);
+		if (*s == 10)
+			ip22zilog_put_char(channel, 13);
+	}
+	udelay(2);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+void
+ip22serial_console_termios(struct console *con, char *options)
+{
+	int baud = 9600, bits = 8, cflag;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (!serial_console)
+		return;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	cflag = CREAD | HUPCL | CLOCAL;
+
+	switch (baud) {
+		case 150: cflag |= B150; break;
+		case 300: cflag |= B300; break;
+		case 600: cflag |= B600; break;
+		case 1200: cflag |= B1200; break;
+		case 2400: cflag |= B2400; break;
+		case 4800: cflag |= B4800; break;
+		case 9600: cflag |= B9600; break;
+		case 19200: cflag |= B19200; break;
+		case 38400: cflag |= B38400; break;
+		default: baud = 9600; cflag |= B9600; break;
+	}
+
+	con->cflag = cflag | CS8;			/* 8N1 */
+}
+
+static int __init ip22zilog_console_setup(struct console *con, char *options)
+{
+	struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
+	unsigned long flags;
+	int baud, brg;
+
+	printk("Console: ttyS%d (IP22-Zilog)\n",
+	       (ip22zilog_reg.minor - 64) + con->index);
+
+	/* Get firmware console settings.  */
+	ip22serial_console_termios(con, options);
+
+	/* Firmware console speed is limited to 150-->38400 baud so
+	 * this hackish cflag thing is OK.
+	 */
+	switch (con->cflag & CBAUD) {
+	case B150: baud = 150; break;
+	case B300: baud = 300; break;
+	case B600: baud = 600; break;
+	case B1200: baud = 1200; break;
+	case B2400: baud = 2400; break;
+	case B4800: baud = 4800; break;
+	default: case B9600: baud = 9600; break;
+	case B19200: baud = 19200; break;
+	case B38400: baud = 38400; break;
+	};
+
+	brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	up->curregs[R15] = BRKIE;
+	ip22zilog_convert_to_zs(up, con->cflag, 0, brg);
+
+	__ip22zilog_startup(up);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	return 0;
+}
+
+static struct console ip22zilog_console = {
+	.name	=	"ttyS",
+	.write	=	ip22zilog_console_write,
+	.device	=	uart_console_device,
+	.setup	=	ip22zilog_console_setup,
+	.flags	=	CON_PRINTBUFFER,
+	.index	=	-1,
+	.data	=	&ip22zilog_reg,
+};
+#define IP22ZILOG_CONSOLE	(&ip22zilog_console)
+
+static int __init ip22zilog_console_init(void)
+{
+	int i;
+
+	if (con_is_present())
+		return 0;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		int this_minor = ip22zilog_reg.minor + i;
+
+		if ((this_minor - 64) == (serial_console - 1))
+			break;
+	}
+	if (i == NUM_CHANNELS)
+		return 0;
+
+	ip22zilog_console.index = i;
+	register_console(&ip22zilog_console);
+	return 0;
+}
+#else /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */
+#define IP22ZILOG_CONSOLE		(NULL)
+#define ip22zilog_console_init()	do { } while (0)
+#endif
+
+static void __init ip22zilog_prepare(void)
+{
+	struct uart_ip22zilog_port *up;
+	struct zilog_layout *rp;
+	int channel, chip;
+
+	/*
+	 * Temporary fix.
+	 */
+	for (channel = 0; channel < NUM_CHANNELS; channel++)
+		spin_lock_init(&ip22zilog_port_table[channel].port.lock);
+
+	ip22zilog_irq_chain = up = &ip22zilog_port_table[0];
+	for (channel = 0; channel < NUM_CHANNELS - 1; channel++)
+		up[channel].next = &up[channel + 1];
+	up[channel].next = NULL;
+
+	for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
+		if (!ip22zilog_chip_regs[chip]) {
+			ip22zilog_chip_regs[chip] = rp = get_zs(chip);
+
+			up[(chip * 2) + 0].port.membase = (char *) &rp->channelA;
+			up[(chip * 2) + 1].port.membase = (char *) &rp->channelB;
+		}
+
+		/* Channel A */
+		up[(chip * 2) + 0].port.iotype = UPIO_MEM;
+		up[(chip * 2) + 0].port.irq = zilog_irq;
+		up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
+		up[(chip * 2) + 0].port.fifosize = 1;
+		up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
+		up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
+		up[(chip * 2) + 0].port.flags = 0;
+		up[(chip * 2) + 0].port.line = (chip * 2) + 0;
+		up[(chip * 2) + 0].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
+
+		/* Channel B */
+		up[(chip * 2) + 1].port.iotype = UPIO_MEM;
+		up[(chip * 2) + 1].port.irq = zilog_irq;
+		up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
+		up[(chip * 2) + 1].port.fifosize = 1;
+		up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
+		up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
+		up[(chip * 2) + 1].port.flags = 0;
+		up[(chip * 2) + 1].port.line = (chip * 2) + 1;
+		up[(chip * 2) + 1].flags |= 0;
+	}
+}
+
+static void __init ip22zilog_init_hw(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+		struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+		unsigned long flags;
+		int baud, brg;
+
+		spin_lock_irqsave(&up->port.lock, flags);
+
+		if (ZS_IS_CHANNEL_A(up)) {
+			write_zsreg(channel, R9, FHWRES);
+			ZSDELAY_LONG();
+			(void) read_zsreg(channel, R0);
+		}
+
+		/* Normal serial TTY. */
+		up->parity_mask = 0xff;
+		up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+		up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+		up->curregs[R3] = RxENAB | Rx8;
+		up->curregs[R5] = TxENAB | Tx8;
+		up->curregs[R9] = NV | MIE;
+		up->curregs[R10] = NRZ;
+		up->curregs[R11] = TCBR | RCBR;
+		baud = 9600;
+		brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+		up->curregs[R12] = (brg & 0xff);
+		up->curregs[R13] = (brg >> 8) & 0xff;
+		up->curregs[R14] = BRSRC | BRENAB;
+		__load_zsregs(channel, up->curregs);
+
+		spin_unlock_irqrestore(&up->port.lock, flags);
+	}
+}
+
+static int __init ip22zilog_ports_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
+
+	ip22zilog_prepare();
+
+	if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
+			"IP22-Zilog", ip22zilog_irq_chain)) {
+		panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
+	}
+
+	ip22zilog_init_hw();
+
+	/* We can only init this once we have probed the Zilogs
+	 * in the system.
+	 */
+	ip22zilog_reg.nr = NUM_CHANNELS;
+	ip22zilog_reg.cons = IP22ZILOG_CONSOLE;
+
+	ip22zilog_reg.minor = ip22serial_current_minor;
+	ip22serial_current_minor += NUM_CHANNELS;
+
+	ret = uart_register_driver(&ip22zilog_reg);
+	if (ret == 0) {
+		int i;
+
+		for (i = 0; i < NUM_CHANNELS; i++) {
+			struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+
+			uart_add_one_port(&ip22zilog_reg, &up->port);
+		}
+	}
+
+	return ret;
+}
+
+static int __init ip22zilog_init(void)
+{
+	/* IP22 Zilog setup is hard coded, no probing to do.  */
+
+	ip22zilog_alloc_tables();
+
+	ip22zilog_ports_init();
+	ip22zilog_console_init();
+
+	return 0;
+}
+
+static void __exit ip22zilog_exit(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+
+		uart_remove_one_port(&ip22zilog_reg, &up->port);
+	}
+
+	uart_unregister_driver(&ip22zilog_reg);
+}
+
+module_init(ip22zilog_init);
+module_exit(ip22zilog_exit);
+
+/* David wrote it but I'm to blame for the bugs ...  */
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_DESCRIPTION("SGI Zilog serial port driver");
+MODULE_LICENSE("GPL");
--- diff/drivers/serial/ip22zilog.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/serial/ip22zilog.h	2004-02-18 09:04:01.000000000 +0000
@@ -0,0 +1,281 @@
+#ifndef _IP22_ZILOG_H
+#define _IP22_ZILOG_H
+
+#include <asm/byteorder.h>
+
+struct zilog_channel {
+#ifdef __BIG_ENDIAN
+	volatile unsigned char unused0[3];
+	volatile unsigned char control;
+	volatile unsigned char unused1[3];
+	volatile unsigned char data;
+#else /* __LITTLE_ENDIAN */
+	volatile unsigned char control;
+	volatile unsigned char unused0[3];
+	volatile unsigned char data;
+	volatile unsigned char unused1[3];
+#endif
+};
+
+struct zilog_layout {
+	struct zilog_channel channelB;
+	struct zilog_channel channelA;
+};
+
+#define NUM_ZSREGS    16
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#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	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+#define RxINT_MASK	0x18
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENAB  	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+#define RxN_MASK	0xc0
+
+/* Write Register 4 */
+
+#define	PAR_ENAB	0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+#define XCLK_MASK	0xC0
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define TxN_MASK	0x60
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENAB 	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define	ZCIE	2	/* Zero count IE */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC		0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	CRC_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY	0x00
+#define CHB_EXT_STAT	0x02
+#define CHB_Rx_AVAIL	0x04
+#define CHB_SPECIAL	0x06
+#define CHA_Tx_EMPTY	0x08
+#define CHA_EXT_STAT	0x0a
+#define CHA_Rx_AVAIL	0x0c
+#define CHA_SPECIAL	0x0e
+#define STATUS_MASK	0x0e
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    do { writeb(ERR_RES, &channel->control); \
+				     udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { writeb(RES_EXT_INT, &channel->control); \
+				     udelay(5); } while(0)
+
+#define ZS_CLEARFIFO(channel)   do { readb(&channel->data); \
+				     udelay(2); \
+				     readb(&channel->data); \
+				     udelay(2); \
+				     readb(&channel->data); \
+				     udelay(2); } while(0)
+
+#endif /* _IP22_ZILOG_H */
--- diff/include/asm-alpha/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Peter Rival (frival@zk3.dec.com)
+ */
+
+#ifndef _ALPHA_LOCKMETER_H
+#define _ALPHA_LOCKMETER_H
+
+#include <asm/hwrpb.h>
+#define CPU_CYCLE_FREQUENCY	hwrpb->cycle_freq
+
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#include <linux/version.h>
+
+#define SPINLOCK_MAGIC_INIT /**/
+
+/*
+ * Macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * We also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ * Note: although these defines and macros are the same as what is being used
+ *       in include/asm-i386/lockmeter.h, they are present here to easily
+ *	 allow an alternate Alpha implementation.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Alpha is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv)	((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)		((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv)	((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)	((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock;
+	/* readers subtract 2, so we have to:		*/
+	/* 	- andnot off a possible writer (bit 0)	*/
+	/*	- get the absolute value		*/
+	/*	- divide by 2 (right shift by one)	*/
+	/* to find the number of readers		*/
+	if (tmp == 0) return(0);
+	else return(IABS(tmp & ~1)>>1);
+}
+
+#endif /* _ALPHA_LOCKMETER_H */
--- diff/include/asm-generic/compat_signal.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-generic/compat_signal.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,25 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H
+#define _ASM_GENERIC_COMPAT_SIGNAL_H
+
+#ifndef __ASSEMBLY__
+#include <linux/compat.h>
+
+typedef compat_uptr_t compat_sighandler_t;
+
+typedef struct compat_sigaltstack {
+	compat_uptr_t ss_sp;
+	compat_int_t ss_flags;
+	compat_size_t ss_size;
+} compat_stack_t;
+
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+struct compat_sigaction {
+	compat_sighandler_t sa_handler;
+	compat_uint_t sa_flags;
+	compat_sigset_t sa_mask;		/* mask last for extensibility */
+};
+
+#endif /* !__ASSEMBLY__ */
+#endif /* !_ASM_GENERIC_COMPAT_SIGNAL_H */
--- diff/include/asm-i386/atomic_kmap.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/atomic_kmap.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,95 @@
+/*
+ * atomic_kmap.h: temporary virtual kernel memory mappings
+ *
+ * Copyright (C) 2003 Ingo Molnar <mingo@redhat.com>
+ */
+
+#ifndef _ASM_ATOMIC_KMAP_H
+#define _ASM_ATOMIC_KMAP_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+#define HIGHMEM_DEBUG 1
+#else
+#define HIGHMEM_DEBUG 0
+#endif
+
+extern pte_t *kmap_pte;
+#define kmap_prot PAGE_KERNEL
+
+#define PKMAP_BASE (0xff000000UL)
+#define NR_SHARED_PMDS ((0xffffffff-PKMAP_BASE+1)/PMD_SIZE)
+
+static inline unsigned long __kmap_atomic_vaddr(enum km_type type)
+{
+	enum fixed_addresses idx;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	return __fix_to_virt(FIX_KMAP_BEGIN + idx);
+}
+
+static inline void *__kmap_atomic_noflush(struct page *page, enum km_type type)
+{
+	enum fixed_addresses idx;
+	unsigned long vaddr;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+	/*
+	 * NOTE: entries that rely on some secondary TLB-flush
+	 * effect must not be global:
+	 */
+	set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
+
+	return (void*) vaddr;
+}
+
+static inline void *__kmap_atomic(struct page *page, enum km_type type)
+{
+	enum fixed_addresses idx;
+	unsigned long vaddr;
+
+	idx = type + KM_TYPE_NR*smp_processor_id();
+	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#if HIGHMEM_DEBUG
+	BUG_ON(!pte_none(*(kmap_pte-idx)));
+#else
+	/*
+	 * Performance optimization - do not flush if the new
+	 * pte is the same as the old one:
+	 */
+	if (pte_val(*(kmap_pte-idx)) == pte_val(mk_pte(page, kmap_prot)))
+		return (void *) vaddr;
+#endif
+	set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+	__flush_tlb_one(vaddr);
+
+	return (void*) vaddr;
+}
+
+static inline void __kunmap_atomic(void *kvaddr, enum km_type type)
+{
+#if HIGHMEM_DEBUG
+	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+	/*
+	 * force other mappings to Oops if they'll try to access
+	 * this pte without first remap it
+	 */
+	pte_clear(kmap_pte-idx);
+	__flush_tlb_one(vaddr);
+#endif
+}
+
+#define __kunmap_atomic_type(type) \
+		__kunmap_atomic((void *)__kmap_atomic_vaddr(type), (type))
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_ATOMIC_KMAP_H */
--- diff/include/asm-i386/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-i386/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb_local.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-i386/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks.
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code here from include/lockmeter.h.
+ *
+ */
+
+#ifndef _I386_LOCKMETER_H
+#define _I386_LOCKMETER_H
+
+#include <asm/spinlock.h>
+#include <asm/rwlock.h>
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+extern unsigned long cpu_khz;
+#define CPU_CYCLE_FREQUENCY	(cpu_khz * 1000)
+#else
+#define CPU_CYCLE_FREQUENCY	450000000
+#endif
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a spin lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.  Not normally a problem!!
+ * we also assume that the hash table has less than 65535 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	/* read and write lock attempts may cause the lock value to temporarily */
+	/* be negative.  Until it is >= 0 we know nothing (i. e. can't tell if  */
+	/* is -1 because it was write locked and somebody tried to read lock it */
+	/* or if it is -1 because it was read locked and somebody tried to write*/
+	/* lock it. ........................................................... */
+	do {
+		tmp = (int) rwlock_ptr->lock;
+	} while (tmp < 0);
+	if (tmp == 0) return(0);
+	else return(RW_LOCK_BIAS-tmp);
+}
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0)
+
+/* this is a lot of typing just to get gcc to emit "rdtsc" */
+static inline long long get_cycles64 (void)
+{
+	union longlong_u {
+		long long intlong;
+		struct intint_s {
+			uint32_t eax;
+			uint32_t edx;
+		} intint;
+	} longlong;
+
+	rdtsc(longlong.intint.eax,longlong.intint.edx);
+	return longlong.intlong;
+}
+
+#endif /* _I386_LOCKMETER_H */
--- diff/include/asm-ia64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ */
+
+#ifndef _IA64_LOCKMETER_H
+#define _IA64_LOCKMETER_H
+
+#ifdef local_cpu_data
+#define CPU_CYCLE_FREQUENCY	local_cpu_data->itc_freq
+#else
+#define CPU_CYCLE_FREQUENCY	my_cpu_data.itc_freq
+#endif
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	volatile unsigned short lock;
+	volatile unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int read_counter:31;
+	volatile int write_lock:1;
+	volatile unsigned short index;
+	volatile unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)	((rwlock_ptr)->read_counter)
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->read_counter)
+
+#endif /* _IA64_LOCKMETER_H */
+
--- diff/include/asm-mips/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *  Ported to mips32 for Asita Technologies
+ *   by D.J. Barrow ( dj.barrow@asitatechnologies.com )
+ */
+#ifndef _ASM_LOCKMETER_H
+#define _ASM_LOCKMETER_H
+
+/* do_gettimeoffset is a function pointer on mips */
+/* & it is not included by <linux/time.h> */
+#include <asm/time.h>
+#include <linux/time.h>
+#include <asm/div64.h>
+
+#define SPINLOCK_MAGIC_INIT	/* */
+
+#define CPU_CYCLE_FREQUENCY	get_cpu_cycle_frequency()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+static uint32_t cpu_cycle_frequency = 0;
+
+static uint32_t get_cpu_cycle_frequency(void)
+{
+    /* a total hack, slow and invasive, but ... it works */
+    int sec;
+    uint32_t start_cycles;
+    struct timeval tv;
+
+    if (cpu_cycle_frequency == 0) {	/* uninitialized */
+	do_gettimeofday(&tv);
+	sec = tv.tv_sec;	/* set up to catch the tv_sec rollover */
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	sec = tv.tv_sec;	/* rolled over to a new sec value */
+	start_cycles = get_cycles();
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	cpu_cycle_frequency = get_cycles() - start_cycles;
+    }
+
+    return cpu_cycle_frequency;
+}
+
+extern struct timeval xtime;
+
+static uint64_t get_cycles64(void)
+{
+    static uint64_t last_get_cycles64 = 0;
+    uint64_t ret;
+    unsigned long sec;
+    unsigned long usec, usec_offset;
+
+again:
+    sec  = xtime.tv_sec;
+    usec = xtime.tv_usec;
+    usec_offset = do_gettimeoffset();
+    if ((xtime.tv_sec != sec)  ||
+	(xtime.tv_usec != usec)||
+	(usec_offset >= 20000))
+	goto again;
+
+    ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency);
+    /* We can't do a normal 64 bit division on mips without libgcc.a */
+    do_div(ret,1000000);
+    ret +=  ((uint64_t)sec * cpu_cycle_frequency);
+
+    /* XXX why does time go backwards?  do_gettimeoffset?  general time adj? */
+    if (ret <= last_get_cycles64)
+	ret  = last_get_cycles64+1;
+    last_get_cycles64 = ret;
+
+    return ret;
+}
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ */
+#define INDEX_MASK   0x7FFF0000
+#define READERS_MASK 0x0000FFFF
+#define INDEX_SHIFT 16
+#define PUT_INDEX(lockp,index)   \
+        lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT)
+#define GET_INDEX(lockp) \
+        (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT)
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	return (tmp >= 0) ? tmp : 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->lock > 0)
+
+#endif /* _ASM_LOCKMETER_H */
--- diff/include/asm-sparc64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sparc64/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SPARC64_LOCKMETER_H
+#define _SPARC64_LOCKMETER_H
+
+#include <linux/smp.h>
+#include <asm/spinlock.h>
+#include <asm/timer.h>
+#include <asm/timex.h>
+
+/* Actually, this is not the CPU frequency by the system tick
+ * frequency which is good enough for lock metering.
+ */
+#define CPU_CYCLE_FREQUENCY	(timer_tick_offset * HZ)
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#define PUT_INDEX(lock_ptr,indexv)	(lock_ptr)->index = (indexv)
+#define GET_INDEX(lock_ptr)		(lock_ptr)->index
+
+#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv)
+#define GET_RWINDEX(rwlock_ptr)        (rwlock_ptr)->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    (rwlock_ptr)->cpu = (cpuv)
+#define GET_RW_CPU(rwlock_ptr)         (rwlock_ptr)->cpu
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	signed int tmp = rwlock_ptr->lock;
+
+	if (tmp > 0)
+		return tmp;
+	else
+		return 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) > 0)
+
+#define get_cycles64()	get_cycles()
+
+#endif /* _SPARC64_LOCKMETER_H */
--- diff/include/asm-x86_64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,71 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+extern void set_debug_traps(void);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb	(0)
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-x86_64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb_local.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/linux/compat_siginfo.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/compat_siginfo.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,170 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGINFO_H
+#define _ASM_GENERIC_COMPAT_SIGINFO_H
+
+#include <linux/config.h>
+#include <linux/compat.h>
+
+#ifndef CONFIG_COMPAT
+
+/* No compatibility layer required, add empty definitions for the compiler */
+
+typedef struct compat_siginfo{
+} compat_siginfo_t;
+
+static inline int compat_copy_siginfo_to_user(compat_siginfo_t __user *to,
+						struct siginfo *from)
+{
+	return -1;
+}
+
+#else
+
+#include <linux/compiler.h>
+#include <asm/siginfo.h>
+
+/* compat view of sigval_t */
+typedef union compat_sigval {
+	compat_int_t sival_int;
+	compat_uptr_t sival_ptr;
+} compat_sigval_t;
+
+/*
+ * This is the size (including padding) of the part of the
+ * struct siginfo that is before the union.
+ */
+#ifndef __ARCH_SI_COMPAT_PREAMBLE_SIZE
+#define __ARCH_SI_COMPAT_PREAMBLE_SIZE	(3 * sizeof(int))
+#endif
+
+#define SI_COMPAT_MAX_SIZE	128
+#ifndef SI_COMPAT_PAD_SIZE
+#define SI_COMPAT_PAD_SIZE	((SI_COMPAT_MAX_SIZE - __ARCH_SI_COMPAT_PREAMBLE_SIZE) / sizeof(int))
+#endif
+
+/* 32-bit view of si.uid_t */
+#ifndef __ARCH_SI_COMPAT_UID_T
+#define __ARCH_SI_COMPAT_UID_T compat_uid_t
+#endif
+
+/* 32-bit view of si.band_t */
+#ifndef __ARCH_SI_COMPAT_BAND_T
+#define __ARCH_SI_COMPAT_BAND_T compat_int_t
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGINFO_T
+
+/* Compat view of siginfo_t */
+typedef struct compat_siginfo {
+	compat_int_t si_signo;
+	compat_int_t si_errno;
+	compat_int_t si_code;
+
+	union {
+		compat_int_t _pad[SI_COMPAT_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			compat_timer_t _tid;	/* timer id */
+			compat_int_t _overrun;		/* overrun count */
+			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+			compat_sigval_t _sigval;	/* same as below */
+			compat_int_t _sys_private;       /* not to be passed to user */
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			compat_pid_t _pid;		/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			compat_pid_t _pid;		/* which child */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_int_t _status;		/* exit code */
+			compat_clock_t _utime;
+			compat_clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+			compat_int_t _trapno;	/* TRAP # which caused the signal */
+#endif
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			__ARCH_SI_COMPAT_BAND_T _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			compat_int_t _fd;
+		} _sigpoll;
+	} _sifields;
+} compat_siginfo_t;
+#endif /* !HAVE_ARCH_COMPAT_SIGINFO_T */
+
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+#define si_trapno	_sifields._sigfault._trapno
+#endif
+
+/*
+ * sigevent definitions
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+
+#define SIGEV_COMPAT_MAX_SIZE	64
+#ifndef SIGEV_COMPAT_PAD_SIZE
+#define SIGEV_COMPAT_PAD_SIZE	((SIGEV_COMPAT_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGEVENT_T
+
+/* 32-bit view of sigevent_t */
+typedef struct compat_sigevent {
+	compat_sigval_t sigev_value;
+	compat_int_t sigev_signo;
+	compat_int_t sigev_notify;
+	union {
+		compat_int_t _pad[SIGEV_COMPAT_PAD_SIZE];
+		compat_int_t _tid;
+
+		struct {
+			compat_uptr_t _function;
+			compat_uptr_t _attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} compat_sigevent_t;
+
+#endif /* HAVE_ARCH_COMPAT_SIGEVENT_T */
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline void compat_copy_siginfo(struct compat_siginfo *to, struct compat_siginfo *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(*to));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, __ARCH_SI_COMPAT_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+}
+
+#endif /* !HAVE_ARCH_COMPAT_COPY_SIGINFO */
+
+extern int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, struct siginfo *from);
+
+#endif /* CONFIG_COMPAT */
+#endif /* _ASM_GENERIC_COMPAT_SIGINFO_H */
+
--- diff/include/linux/dwarf2-lang.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2-lang.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,132 @@
+#ifndef DWARF2_LANG
+#define DWARF2_LANG
+#include <linux/dwarf2.h>
+
+/*
+ * This 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, or (at your option) any later
+ * version.
+ */
+/*
+ * This file defines macros that allow generation of DWARF debug records
+ * for asm files.  This file is platform independent.  Register numbers
+ * (which are about the only thing that is platform dependent) are to be
+ * supplied by a platform defined file.
+ */
+#define DWARF_preamble()	.section	.debug_frame,"",@progbits
+/*
+ * This macro starts a debug frame section.  The debug_frame describes
+ * where to find the registers that the enclosing function saved on
+ * entry.
+ *
+ * ORD is use by the label generator and should be the same as what is
+ * passed to CFI_postamble.
+ *
+ * pc,	pc register gdb ordinal.
+ *
+ * code_align this is the factor used to define locations or regions
+ * where the given definitions apply.  If you use labels to define these
+ * this should be 1.
+ *
+ * data_align this is the factor used to define register offsets.  If
+ * you use struct offset, this should be the size of the register in
+ * bytes or the negative of that.  This is how it is used: you will
+ * define a register as the reference register, say the stack pointer,
+ * then you will say where a register is located relative to this
+ * reference registers value, say 40 for register 3 (the gdb register
+ * number).  The <40> will be multiplied by <data_align> to define the
+ * byte offset of the given register (3, in this example).  So if your
+ * <40> is the byte offset and the reference register points at the
+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
+ * 4-byte element in that structure you would want 4.  And if your
+ * reference register points at the end of the structure you would want
+ * a negative data_align value(and you would have to do other math as
+ * well).
+ */
+
+#define CFI_preamble(ORD, pc, code_align, data_align)	\
+.section	.debug_frame,"",@progbits ;		\
+frame/**/_/**/ORD:						\
+	.long end/**/_/**/ORD-start/**/_/**/ORD;			\
+start/**/_/**/ORD:						\
+	.long	DW_CIE_ID;				\
+	.byte	DW_CIE_VERSION;			\
+	.byte 0	 ;				\
+	.uleb128 code_align;				\
+	.sleb128 data_align;				\
+	.byte pc;
+
+/*
+ * After the above macro and prior to the CFI_postamble, you need to
+ * define the initial state.  This starts with defining the reference
+ * register and, usually the pc.  Here are some helper macros:
+ */
+
+#define CFA_define_reference(reg, offset)	\
+	.byte DW_CFA_def_cfa;			\
+	.uleb128 reg;				\
+	.uleb128 (offset);
+
+#define CFA_define_offset(reg, offset)		\
+	.byte (DW_CFA_offset + reg);		\
+	.uleb128 (offset);
+
+#define CFI_postamble(ORD)			\
+	.align 4;				\
+end/**/_/**/ORD:
+/*
+ * So now your code pushs stuff on the stack, you need a new location
+ * and the rules for what to do.  This starts a running description of
+ * the call frame.  You need to describe what changes with respect to
+ * the call registers as the location of the pc moves through the code.
+ * The following builds an FDE (fram descriptor entry?).  Like the
+ * above, it has a preamble and a postamble.  It also is tied to the CFI
+ * above.
+ * The first entry after the preamble must be the location in the code
+ * that the call frame is being described for.
+ */
+#define FDE_preamble(ORD, fde_no, initial_address, length)	\
+	.long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;		\
+FDE_start/**/_/**/fde_no:						\
+	.long frame/**/_/**/ORD;					\
+	.long initial_address;					\
+	.long length;
+
+#define FDE_postamble(fde_no)			\
+	.align 4;				\
+FDE_end/**/_/**/fde_no:
+/*
+ * That done, you can now add registers, subtract registers, move the
+ * reference and even change the reference.  You can also define a new
+ * area of code the info applies to.  For discontinuous bits you should
+ * start a new FDE.  You may have as many as you like.
+ */
+
+/*
+ * To advance the address by <bytes>
+ */
+
+#define FDE_advance(bytes)			\
+	.byte DW_CFA_advance_loc4		\
+	.long bytes
+
+
+
+/*
+ * With the above you can define all the register locations.  But
+ * suppose the reference register moves... Takes the new offset NOT an
+ * increment.  This is how esp is tracked if it is not saved.
+ */
+
+#define CFA_define_cfa_offset(offset) \
+	.byte $DW_CFA_def_cfa_offset; \
+	.uleb128 (offset);
+/*
+ * Or suppose you want to use a different reference register...
+ */
+#define CFA_define_cfa_register(reg)		\
+	.byte DW_CFA_def_cfa_register;		\
+	.uleb128 reg;
+
+#endif
--- diff/include/linux/dwarf2.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,738 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
+   provided support for this effort -- June 21, 1995.
+
+   Derived from the DWARF 1 implementation written by Ron Guilmette
+   (rfg@netcom.com), November 1990.
+
+   This file is part of GCC.
+
+   GCC 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, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+   This file also now contains definitions from the DWARF 3 specification.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.	*/
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section.	*/
+#ifndef __ASSEMBLY__
+typedef struct
+{
+  unsigned char li_length	   [4];
+  unsigned char li_version	   [2];
+  unsigned char li_prologue_length [4];
+  unsigned char li_min_insn_length [1];
+  unsigned char li_default_is_stmt [1];
+  unsigned char li_line_base	   [1];
+  unsigned char li_line_range	   [1];
+  unsigned char li_opcode_base	   [1];
+}
+DWARF2_External_LineInfo;
+
+typedef struct
+{
+  unsigned long  li_length;
+  unsigned short li_version;
+  unsigned int	 li_prologue_length;
+  unsigned char  li_min_insn_length;
+  unsigned char  li_default_is_stmt;
+  int		 li_line_base;
+  unsigned char  li_line_range;
+  unsigned char  li_opcode_base;
+}
+DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section.	*/
+typedef struct
+{
+  unsigned char pn_length  [4];
+  unsigned char pn_version [2];
+  unsigned char pn_offset  [4];
+  unsigned char pn_size    [4];
+}
+DWARF2_External_PubNames;
+
+typedef struct
+{
+  unsigned long  pn_length;
+  unsigned short pn_version;
+  unsigned long  pn_offset;
+  unsigned long  pn_size;
+}
+DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section.  */
+typedef struct
+{
+  unsigned char  cu_length	  [4];
+  unsigned char  cu_version	  [2];
+  unsigned char  cu_abbrev_offset [4];
+  unsigned char  cu_pointer_size  [1];
+}
+DWARF2_External_CompUnit;
+
+typedef struct
+{
+  unsigned long  cu_length;
+  unsigned short cu_version;
+  unsigned long  cu_abbrev_offset;
+  unsigned char  cu_pointer_size;
+}
+DWARF2_Internal_CompUnit;
+
+typedef struct
+{
+  unsigned char  ar_length	 [4];
+  unsigned char  ar_version	 [2];
+  unsigned char  ar_info_offset  [4];
+  unsigned char  ar_pointer_size [1];
+  unsigned char  ar_segment_size [1];
+}
+DWARF2_External_ARange;
+
+typedef struct
+{
+  unsigned long  ar_length;
+  unsigned short ar_version;
+  unsigned long  ar_info_offset;
+  unsigned char  ar_pointer_size;
+  unsigned char  ar_segment_size;
+}
+DWARF2_Internal_ARange;
+
+#define ENUM(name) enum name {
+#define IF_NOT_ASM(a) a
+#define COMMA ,
+#else
+#define ENUM(name)
+#define IF_NOT_ASM(a)
+#define COMMA
+
+#endif
+
+/* Tag names and codes.  */
+ENUM(dwarf_tag)
+
+    DW_TAG_padding = 0x00 COMMA
+    DW_TAG_array_type = 0x01 COMMA
+    DW_TAG_class_type = 0x02 COMMA
+    DW_TAG_entry_point = 0x03 COMMA
+    DW_TAG_enumeration_type = 0x04 COMMA
+    DW_TAG_formal_parameter = 0x05 COMMA
+    DW_TAG_imported_declaration = 0x08 COMMA
+    DW_TAG_label = 0x0a COMMA
+    DW_TAG_lexical_block = 0x0b COMMA
+    DW_TAG_member = 0x0d COMMA
+    DW_TAG_pointer_type = 0x0f COMMA
+    DW_TAG_reference_type = 0x10 COMMA
+    DW_TAG_compile_unit = 0x11 COMMA
+    DW_TAG_string_type = 0x12 COMMA
+    DW_TAG_structure_type = 0x13 COMMA
+    DW_TAG_subroutine_type = 0x15 COMMA
+    DW_TAG_typedef = 0x16 COMMA
+    DW_TAG_union_type = 0x17 COMMA
+    DW_TAG_unspecified_parameters = 0x18 COMMA
+    DW_TAG_variant = 0x19 COMMA
+    DW_TAG_common_block = 0x1a COMMA
+    DW_TAG_common_inclusion = 0x1b COMMA
+    DW_TAG_inheritance = 0x1c COMMA
+    DW_TAG_inlined_subroutine = 0x1d COMMA
+    DW_TAG_module = 0x1e COMMA
+    DW_TAG_ptr_to_member_type = 0x1f COMMA
+    DW_TAG_set_type = 0x20 COMMA
+    DW_TAG_subrange_type = 0x21 COMMA
+    DW_TAG_with_stmt = 0x22 COMMA
+    DW_TAG_access_declaration = 0x23 COMMA
+    DW_TAG_base_type = 0x24 COMMA
+    DW_TAG_catch_block = 0x25 COMMA
+    DW_TAG_const_type = 0x26 COMMA
+    DW_TAG_constant = 0x27 COMMA
+    DW_TAG_enumerator = 0x28 COMMA
+    DW_TAG_file_type = 0x29 COMMA
+    DW_TAG_friend = 0x2a COMMA
+    DW_TAG_namelist = 0x2b COMMA
+    DW_TAG_namelist_item = 0x2c COMMA
+    DW_TAG_packed_type = 0x2d COMMA
+    DW_TAG_subprogram = 0x2e COMMA
+    DW_TAG_template_type_param = 0x2f COMMA
+    DW_TAG_template_value_param = 0x30 COMMA
+    DW_TAG_thrown_type = 0x31 COMMA
+    DW_TAG_try_block = 0x32 COMMA
+    DW_TAG_variant_part = 0x33 COMMA
+    DW_TAG_variable = 0x34 COMMA
+    DW_TAG_volatile_type = 0x35 COMMA
+    /* DWARF 3.  */
+    DW_TAG_dwarf_procedure = 0x36 COMMA
+    DW_TAG_restrict_type = 0x37 COMMA
+    DW_TAG_interface_type = 0x38 COMMA
+    DW_TAG_namespace = 0x39 COMMA
+    DW_TAG_imported_module = 0x3a COMMA
+    DW_TAG_unspecified_type = 0x3b COMMA
+    DW_TAG_partial_unit = 0x3c COMMA
+    DW_TAG_imported_unit = 0x3d COMMA
+    /* SGI/MIPS Extensions.  */
+    DW_TAG_MIPS_loop = 0x4081 COMMA
+    /* GNU extensions.	*/
+    DW_TAG_format_label = 0x4101 COMMA	/* For FORTRAN 77 and Fortran 90.  */
+    DW_TAG_function_template = 0x4102 COMMA	/* For C++.  */
+    DW_TAG_class_template = 0x4103 COMMA	/* For C++.  */
+    DW_TAG_GNU_BINCL = 0x4104 COMMA
+    DW_TAG_GNU_EINCL = 0x4105 COMMA
+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
+    DW_TAG_upc_shared_type = 0x8765 COMMA
+    DW_TAG_upc_strict_type = 0x8766 COMMA
+    DW_TAG_upc_relaxed_type = 0x8767
+IF_NOT_ASM(};)
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* Flag that tells whether entry has a child or not.  */
+#define DW_children_no	 0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+ENUM(dwarf_form)
+
+    DW_FORM_addr = 0x01 COMMA
+    DW_FORM_block2 = 0x03 COMMA
+    DW_FORM_block4 = 0x04 COMMA
+    DW_FORM_data2 = 0x05 COMMA
+    DW_FORM_data4 = 0x06 COMMA
+    DW_FORM_data8 = 0x07 COMMA
+    DW_FORM_string = 0x08 COMMA
+    DW_FORM_block = 0x09 COMMA
+    DW_FORM_block1 = 0x0a COMMA
+    DW_FORM_data1 = 0x0b COMMA
+    DW_FORM_flag = 0x0c COMMA
+    DW_FORM_sdata = 0x0d COMMA
+    DW_FORM_strp = 0x0e COMMA
+    DW_FORM_udata = 0x0f COMMA
+    DW_FORM_ref_addr = 0x10 COMMA
+    DW_FORM_ref1 = 0x11 COMMA
+    DW_FORM_ref2 = 0x12 COMMA
+    DW_FORM_ref4 = 0x13 COMMA
+    DW_FORM_ref8 = 0x14 COMMA
+    DW_FORM_ref_udata = 0x15 COMMA
+    DW_FORM_indirect = 0x16
+IF_NOT_ASM(};)
+
+/* Attribute names and codes.  */
+
+ENUM(dwarf_attribute)
+
+    DW_AT_sibling = 0x01 COMMA
+    DW_AT_location = 0x02 COMMA
+    DW_AT_name = 0x03 COMMA
+    DW_AT_ordering = 0x09 COMMA
+    DW_AT_subscr_data = 0x0a COMMA
+    DW_AT_byte_size = 0x0b COMMA
+    DW_AT_bit_offset = 0x0c COMMA
+    DW_AT_bit_size = 0x0d COMMA
+    DW_AT_element_list = 0x0f COMMA
+    DW_AT_stmt_list = 0x10 COMMA
+    DW_AT_low_pc = 0x11 COMMA
+    DW_AT_high_pc = 0x12 COMMA
+    DW_AT_language = 0x13 COMMA
+    DW_AT_member = 0x14 COMMA
+    DW_AT_discr = 0x15 COMMA
+    DW_AT_discr_value = 0x16 COMMA
+    DW_AT_visibility = 0x17 COMMA
+    DW_AT_import = 0x18 COMMA
+    DW_AT_string_length = 0x19 COMMA
+    DW_AT_common_reference = 0x1a COMMA
+    DW_AT_comp_dir = 0x1b COMMA
+    DW_AT_const_value = 0x1c COMMA
+    DW_AT_containing_type = 0x1d COMMA
+    DW_AT_default_value = 0x1e COMMA
+    DW_AT_inline = 0x20 COMMA
+    DW_AT_is_optional = 0x21 COMMA
+    DW_AT_lower_bound = 0x22 COMMA
+    DW_AT_producer = 0x25 COMMA
+    DW_AT_prototyped = 0x27 COMMA
+    DW_AT_return_addr = 0x2a COMMA
+    DW_AT_start_scope = 0x2c COMMA
+    DW_AT_stride_size = 0x2e COMMA
+    DW_AT_upper_bound = 0x2f COMMA
+    DW_AT_abstract_origin = 0x31 COMMA
+    DW_AT_accessibility = 0x32 COMMA
+    DW_AT_address_class = 0x33 COMMA
+    DW_AT_artificial = 0x34 COMMA
+    DW_AT_base_types = 0x35 COMMA
+    DW_AT_calling_convention = 0x36 COMMA
+    DW_AT_count = 0x37 COMMA
+    DW_AT_data_member_location = 0x38 COMMA
+    DW_AT_decl_column = 0x39 COMMA
+    DW_AT_decl_file = 0x3a COMMA
+    DW_AT_decl_line = 0x3b COMMA
+    DW_AT_declaration = 0x3c COMMA
+    DW_AT_discr_list = 0x3d COMMA
+    DW_AT_encoding = 0x3e COMMA
+    DW_AT_external = 0x3f COMMA
+    DW_AT_frame_base = 0x40 COMMA
+    DW_AT_friend = 0x41 COMMA
+    DW_AT_identifier_case = 0x42 COMMA
+    DW_AT_macro_info = 0x43 COMMA
+    DW_AT_namelist_items = 0x44 COMMA
+    DW_AT_priority = 0x45 COMMA
+    DW_AT_segment = 0x46 COMMA
+    DW_AT_specification = 0x47 COMMA
+    DW_AT_static_link = 0x48 COMMA
+    DW_AT_type = 0x49 COMMA
+    DW_AT_use_location = 0x4a COMMA
+    DW_AT_variable_parameter = 0x4b COMMA
+    DW_AT_virtuality = 0x4c COMMA
+    DW_AT_vtable_elem_location = 0x4d COMMA
+    /* DWARF 3 values.	*/
+    DW_AT_allocated	= 0x4e COMMA
+    DW_AT_associated	= 0x4f COMMA
+    DW_AT_data_location = 0x50 COMMA
+    DW_AT_stride	= 0x51 COMMA
+    DW_AT_entry_pc	= 0x52 COMMA
+    DW_AT_use_UTF8	= 0x53 COMMA
+    DW_AT_extension	= 0x54 COMMA
+    DW_AT_ranges	= 0x55 COMMA
+    DW_AT_trampoline	= 0x56 COMMA
+    DW_AT_call_column	= 0x57 COMMA
+    DW_AT_call_file	= 0x58 COMMA
+    DW_AT_call_line	= 0x59 COMMA
+    /* SGI/MIPS extensions.  */
+    DW_AT_MIPS_fde = 0x2001 COMMA
+    DW_AT_MIPS_loop_begin = 0x2002 COMMA
+    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
+    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
+    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
+    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
+    DW_AT_MIPS_linkage_name = 0x2007 COMMA
+    DW_AT_MIPS_stride = 0x2008 COMMA
+    DW_AT_MIPS_abstract_name = 0x2009 COMMA
+    DW_AT_MIPS_clone_origin = 0x200a COMMA
+    DW_AT_MIPS_has_inlines = 0x200b COMMA
+    /* GNU extensions.	*/
+    DW_AT_sf_names   = 0x2101 COMMA
+    DW_AT_src_info   = 0x2102 COMMA
+    DW_AT_mac_info   = 0x2103 COMMA
+    DW_AT_src_coords = 0x2104 COMMA
+    DW_AT_body_begin = 0x2105 COMMA
+    DW_AT_body_end   = 0x2106 COMMA
+    DW_AT_GNU_vector = 0x2107 COMMA
+    /* VMS extensions.	*/
+    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
+    /* UPC extension.  */
+    DW_AT_upc_threads_scaled = 0x3210
+IF_NOT_ASM(};)
+
+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.	*/
+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
+
+/* Location atom names and codes.  */
+ENUM(dwarf_location_atom)
+
+    DW_OP_addr = 0x03 COMMA
+    DW_OP_deref = 0x06 COMMA
+    DW_OP_const1u = 0x08 COMMA
+    DW_OP_const1s = 0x09 COMMA
+    DW_OP_const2u = 0x0a COMMA
+    DW_OP_const2s = 0x0b COMMA
+    DW_OP_const4u = 0x0c COMMA
+    DW_OP_const4s = 0x0d COMMA
+    DW_OP_const8u = 0x0e COMMA
+    DW_OP_const8s = 0x0f COMMA
+    DW_OP_constu = 0x10 COMMA
+    DW_OP_consts = 0x11 COMMA
+    DW_OP_dup = 0x12 COMMA
+    DW_OP_drop = 0x13 COMMA
+    DW_OP_over = 0x14 COMMA
+    DW_OP_pick = 0x15 COMMA
+    DW_OP_swap = 0x16 COMMA
+    DW_OP_rot = 0x17 COMMA
+    DW_OP_xderef = 0x18 COMMA
+    DW_OP_abs = 0x19 COMMA
+    DW_OP_and = 0x1a COMMA
+    DW_OP_div = 0x1b COMMA
+    DW_OP_minus = 0x1c COMMA
+    DW_OP_mod = 0x1d COMMA
+    DW_OP_mul = 0x1e COMMA
+    DW_OP_neg = 0x1f COMMA
+    DW_OP_not = 0x20 COMMA
+    DW_OP_or = 0x21 COMMA
+    DW_OP_plus = 0x22 COMMA
+    DW_OP_plus_uconst = 0x23 COMMA
+    DW_OP_shl = 0x24 COMMA
+    DW_OP_shr = 0x25 COMMA
+    DW_OP_shra = 0x26 COMMA
+    DW_OP_xor = 0x27 COMMA
+    DW_OP_bra = 0x28 COMMA
+    DW_OP_eq = 0x29 COMMA
+    DW_OP_ge = 0x2a COMMA
+    DW_OP_gt = 0x2b COMMA
+    DW_OP_le = 0x2c COMMA
+    DW_OP_lt = 0x2d COMMA
+    DW_OP_ne = 0x2e COMMA
+    DW_OP_skip = 0x2f COMMA
+    DW_OP_lit0 = 0x30 COMMA
+    DW_OP_lit1 = 0x31 COMMA
+    DW_OP_lit2 = 0x32 COMMA
+    DW_OP_lit3 = 0x33 COMMA
+    DW_OP_lit4 = 0x34 COMMA
+    DW_OP_lit5 = 0x35 COMMA
+    DW_OP_lit6 = 0x36 COMMA
+    DW_OP_lit7 = 0x37 COMMA
+    DW_OP_lit8 = 0x38 COMMA
+    DW_OP_lit9 = 0x39 COMMA
+    DW_OP_lit10 = 0x3a COMMA
+    DW_OP_lit11 = 0x3b COMMA
+    DW_OP_lit12 = 0x3c COMMA
+    DW_OP_lit13 = 0x3d COMMA
+    DW_OP_lit14 = 0x3e COMMA
+    DW_OP_lit15 = 0x3f COMMA
+    DW_OP_lit16 = 0x40 COMMA
+    DW_OP_lit17 = 0x41 COMMA
+    DW_OP_lit18 = 0x42 COMMA
+    DW_OP_lit19 = 0x43 COMMA
+    DW_OP_lit20 = 0x44 COMMA
+    DW_OP_lit21 = 0x45 COMMA
+    DW_OP_lit22 = 0x46 COMMA
+    DW_OP_lit23 = 0x47 COMMA
+    DW_OP_lit24 = 0x48 COMMA
+    DW_OP_lit25 = 0x49 COMMA
+    DW_OP_lit26 = 0x4a COMMA
+    DW_OP_lit27 = 0x4b COMMA
+    DW_OP_lit28 = 0x4c COMMA
+    DW_OP_lit29 = 0x4d COMMA
+    DW_OP_lit30 = 0x4e COMMA
+    DW_OP_lit31 = 0x4f COMMA
+    DW_OP_reg0 = 0x50 COMMA
+    DW_OP_reg1 = 0x51 COMMA
+    DW_OP_reg2 = 0x52 COMMA
+    DW_OP_reg3 = 0x53 COMMA
+    DW_OP_reg4 = 0x54 COMMA
+    DW_OP_reg5 = 0x55 COMMA
+    DW_OP_reg6 = 0x56 COMMA
+    DW_OP_reg7 = 0x57 COMMA
+    DW_OP_reg8 = 0x58 COMMA
+    DW_OP_reg9 = 0x59 COMMA
+    DW_OP_reg10 = 0x5a COMMA
+    DW_OP_reg11 = 0x5b COMMA
+    DW_OP_reg12 = 0x5c COMMA
+    DW_OP_reg13 = 0x5d COMMA
+    DW_OP_reg14 = 0x5e COMMA
+    DW_OP_reg15 = 0x5f COMMA
+    DW_OP_reg16 = 0x60 COMMA
+    DW_OP_reg17 = 0x61 COMMA
+    DW_OP_reg18 = 0x62 COMMA
+    DW_OP_reg19 = 0x63 COMMA
+    DW_OP_reg20 = 0x64 COMMA
+    DW_OP_reg21 = 0x65 COMMA
+    DW_OP_reg22 = 0x66 COMMA
+    DW_OP_reg23 = 0x67 COMMA
+    DW_OP_reg24 = 0x68 COMMA
+    DW_OP_reg25 = 0x69 COMMA
+    DW_OP_reg26 = 0x6a COMMA
+    DW_OP_reg27 = 0x6b COMMA
+    DW_OP_reg28 = 0x6c COMMA
+    DW_OP_reg29 = 0x6d COMMA
+    DW_OP_reg30 = 0x6e COMMA
+    DW_OP_reg31 = 0x6f COMMA
+    DW_OP_breg0 = 0x70 COMMA
+    DW_OP_breg1 = 0x71 COMMA
+    DW_OP_breg2 = 0x72 COMMA
+    DW_OP_breg3 = 0x73 COMMA
+    DW_OP_breg4 = 0x74 COMMA
+    DW_OP_breg5 = 0x75 COMMA
+    DW_OP_breg6 = 0x76 COMMA
+    DW_OP_breg7 = 0x77 COMMA
+    DW_OP_breg8 = 0x78 COMMA
+    DW_OP_breg9 = 0x79 COMMA
+    DW_OP_breg10 = 0x7a COMMA
+    DW_OP_breg11 = 0x7b COMMA
+    DW_OP_breg12 = 0x7c COMMA
+    DW_OP_breg13 = 0x7d COMMA
+    DW_OP_breg14 = 0x7e COMMA
+    DW_OP_breg15 = 0x7f COMMA
+    DW_OP_breg16 = 0x80 COMMA
+    DW_OP_breg17 = 0x81 COMMA
+    DW_OP_breg18 = 0x82 COMMA
+    DW_OP_breg19 = 0x83 COMMA
+    DW_OP_breg20 = 0x84 COMMA
+    DW_OP_breg21 = 0x85 COMMA
+    DW_OP_breg22 = 0x86 COMMA
+    DW_OP_breg23 = 0x87 COMMA
+    DW_OP_breg24 = 0x88 COMMA
+    DW_OP_breg25 = 0x89 COMMA
+    DW_OP_breg26 = 0x8a COMMA
+    DW_OP_breg27 = 0x8b COMMA
+    DW_OP_breg28 = 0x8c COMMA
+    DW_OP_breg29 = 0x8d COMMA
+    DW_OP_breg30 = 0x8e COMMA
+    DW_OP_breg31 = 0x8f COMMA
+    DW_OP_regx = 0x90 COMMA
+    DW_OP_fbreg = 0x91 COMMA
+    DW_OP_bregx = 0x92 COMMA
+    DW_OP_piece = 0x93 COMMA
+    DW_OP_deref_size = 0x94 COMMA
+    DW_OP_xderef_size = 0x95 COMMA
+    DW_OP_nop = 0x96 COMMA
+    /* DWARF 3 extensions.  */
+    DW_OP_push_object_address = 0x97 COMMA
+    DW_OP_call2 = 0x98 COMMA
+    DW_OP_call4 = 0x99 COMMA
+    DW_OP_call_ref = 0x9a COMMA
+    /* GNU extensions.	*/
+    DW_OP_GNU_push_tls_address = 0xe0
+IF_NOT_ASM(};)
+
+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.	*/
+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
+
+/* Type encodings.  */
+ENUM(dwarf_type)
+
+    DW_ATE_void = 0x0 COMMA
+    DW_ATE_address = 0x1 COMMA
+    DW_ATE_boolean = 0x2 COMMA
+    DW_ATE_complex_float = 0x3 COMMA
+    DW_ATE_float = 0x4 COMMA
+    DW_ATE_signed = 0x5 COMMA
+    DW_ATE_signed_char = 0x6 COMMA
+    DW_ATE_unsigned = 0x7 COMMA
+    DW_ATE_unsigned_char = 0x8 COMMA
+    /* DWARF 3.  */
+    DW_ATE_imaginary_float = 0x9
+IF_NOT_ASM(};)
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+ENUM(dwarf_array_dim_ordering)
+
+    DW_ORD_row_major = 0 COMMA
+    DW_ORD_col_major = 1
+IF_NOT_ASM(};)
+
+/* Access attribute.  */
+ENUM(dwarf_access_attribute)
+
+    DW_ACCESS_public = 1 COMMA
+    DW_ACCESS_protected = 2 COMMA
+    DW_ACCESS_private = 3
+IF_NOT_ASM(};)
+
+/* Visibility.	*/
+ENUM(dwarf_visibility_attribute)
+
+    DW_VIS_local = 1 COMMA
+    DW_VIS_exported = 2 COMMA
+    DW_VIS_qualified = 3
+IF_NOT_ASM(};)
+
+/* Virtuality.	*/
+ENUM(dwarf_virtuality_attribute)
+
+    DW_VIRTUALITY_none = 0 COMMA
+    DW_VIRTUALITY_virtual = 1 COMMA
+    DW_VIRTUALITY_pure_virtual = 2
+IF_NOT_ASM(};)
+
+/* Case sensitivity.  */
+ENUM(dwarf_id_case)
+
+    DW_ID_case_sensitive = 0 COMMA
+    DW_ID_up_case = 1 COMMA
+    DW_ID_down_case = 2 COMMA
+    DW_ID_case_insensitive = 3
+IF_NOT_ASM(};)
+
+/* Calling convention.	*/
+ENUM(dwarf_calling_convention)
+
+    DW_CC_normal = 0x1 COMMA
+    DW_CC_program = 0x2 COMMA
+    DW_CC_nocall = 0x3
+IF_NOT_ASM(};)
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute.  */
+ENUM(dwarf_inline_attribute)
+
+    DW_INL_not_inlined = 0 COMMA
+    DW_INL_inlined = 1 COMMA
+    DW_INL_declared_not_inlined = 2 COMMA
+    DW_INL_declared_inlined = 3
+IF_NOT_ASM(};)
+
+/* Discriminant lists.	*/
+ENUM(dwarf_discrim_list)
+
+    DW_DSC_label = 0 COMMA
+    DW_DSC_range = 1
+IF_NOT_ASM(};)
+
+/* Line number opcodes.  */
+ENUM(dwarf_line_number_ops)
+
+    DW_LNS_extended_op = 0 COMMA
+    DW_LNS_copy = 1 COMMA
+    DW_LNS_advance_pc = 2 COMMA
+    DW_LNS_advance_line = 3 COMMA
+    DW_LNS_set_file = 4 COMMA
+    DW_LNS_set_column = 5 COMMA
+    DW_LNS_negate_stmt = 6 COMMA
+    DW_LNS_set_basic_block = 7 COMMA
+    DW_LNS_const_add_pc = 8 COMMA
+    DW_LNS_fixed_advance_pc = 9 COMMA
+    /* DWARF 3.  */
+    DW_LNS_set_prologue_end = 10 COMMA
+    DW_LNS_set_epilogue_begin = 11 COMMA
+    DW_LNS_set_isa = 12
+IF_NOT_ASM(};)
+
+/* Line number extended opcodes.  */
+ENUM(dwarf_line_number_x_ops)
+
+    DW_LNE_end_sequence = 1 COMMA
+    DW_LNE_set_address = 2 COMMA
+    DW_LNE_define_file = 3
+IF_NOT_ASM(};)
+
+/* Call frame information.  */
+ENUM(dwarf_call_frame_info)
+
+    DW_CFA_advance_loc = 0x40 COMMA
+    DW_CFA_offset = 0x80 COMMA
+    DW_CFA_restore = 0xc0 COMMA
+    DW_CFA_nop = 0x00 COMMA
+    DW_CFA_set_loc = 0x01 COMMA
+    DW_CFA_advance_loc1 = 0x02 COMMA
+    DW_CFA_advance_loc2 = 0x03 COMMA
+    DW_CFA_advance_loc4 = 0x04 COMMA
+    DW_CFA_offset_extended = 0x05 COMMA
+    DW_CFA_restore_extended = 0x06 COMMA
+    DW_CFA_undefined = 0x07 COMMA
+    DW_CFA_same_value = 0x08 COMMA
+    DW_CFA_register = 0x09 COMMA
+    DW_CFA_remember_state = 0x0a COMMA
+    DW_CFA_restore_state = 0x0b COMMA
+    DW_CFA_def_cfa = 0x0c COMMA
+    DW_CFA_def_cfa_register = 0x0d COMMA
+    DW_CFA_def_cfa_offset = 0x0e COMMA
+
+    /* DWARF 3.  */
+    DW_CFA_def_cfa_expression = 0x0f COMMA
+    DW_CFA_expression = 0x10 COMMA
+    DW_CFA_offset_extended_sf = 0x11 COMMA
+    DW_CFA_def_cfa_sf = 0x12 COMMA
+    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
+
+    /* SGI/MIPS specific.  */
+    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
+
+    /* GNU extensions.	*/
+    DW_CFA_GNU_window_save = 0x2d COMMA
+    DW_CFA_GNU_args_size = 0x2e COMMA
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+IF_NOT_ASM(};)
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_lo_user	  0x1c
+#define DW_CFA_hi_user	  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+ENUM(dwarf_source_language)
+
+    DW_LANG_C89 = 0x0001 COMMA
+    DW_LANG_C = 0x0002 COMMA
+    DW_LANG_Ada83 = 0x0003 COMMA
+    DW_LANG_C_plus_plus = 0x0004 COMMA
+    DW_LANG_Cobol74 = 0x0005 COMMA
+    DW_LANG_Cobol85 = 0x0006 COMMA
+    DW_LANG_Fortran77 = 0x0007 COMMA
+    DW_LANG_Fortran90 = 0x0008 COMMA
+    DW_LANG_Pascal83 = 0x0009 COMMA
+    DW_LANG_Modula2 = 0x000a COMMA
+    DW_LANG_Java = 0x000b COMMA
+    /* DWARF 3.  */
+    DW_LANG_C99 = 0x000c COMMA
+    DW_LANG_Ada95 = 0x000d COMMA
+    DW_LANG_Fortran95 = 0x000e COMMA
+    /* MIPS.  */
+    DW_LANG_Mips_Assembler = 0x8001 COMMA
+    /* UPC.  */
+    DW_LANG_Upc = 0x8765
+IF_NOT_ASM(};)
+
+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.	*/
+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.	*/
+
+/* Names and codes for macro information.  */
+ENUM(dwarf_macinfo_record_type)
+
+    DW_MACINFO_define = 1 COMMA
+    DW_MACINFO_undef = 2 COMMA
+    DW_MACINFO_start_file = 3 COMMA
+    DW_MACINFO_end_file = 4 COMMA
+    DW_MACINFO_vendor_ext = 255
+IF_NOT_ASM(};)
+
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
+
+#endif /* _ELF_DWARF2_H */
--- diff/include/linux/kthread.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/kthread.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,81 @@
+#ifndef _LINUX_KTHREAD_H
+#define _LINUX_KTHREAD_H
+/* Simple interface for creating and stopping kernel threads without mess. */
+#include <linux/err.h>
+#include <linux/sched.h>
+
+/**
+ * kthread_create: create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread.  The thread will be stopped: use wake_up_process() to start
+ * it.  See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called).  The return value should be zero
+ * or a negative error number: it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
+struct task_struct *kthread_create(int (*threadfn)(void *data),
+				   void *data,
+				   const char namefmt[], ...);
+
+/**
+ * kthread_run: create and wake a thread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: Convenient wrapper for kthread_create() followed by
+ * wake_up_process().  Returns the kthread, or ERR_PTR(-ENOMEM). */
+#define kthread_run(threadfn, data, namefmt, ...)			   \
+({									   \
+	struct task_struct *__k						   \
+		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+	if (!IS_ERR(__k))						   \
+		wake_up_process(__k);					   \
+	__k;								   \
+})
+
+/**
+ * kthread_bind: bind a just-created kthread to a cpu.
+ * @k: thread created by kthread_create().
+ * @cpu: cpu (might not be online, must be possible) for @k to run on.
+ *
+ * Description: This function is equivalent to set_cpus_allowed(),
+ * except that @cpu doesn't need to be online, and the thread must be
+ * stopped (ie. just returned from kthread_create().
+ */
+void kthread_bind(struct task_struct *k, unsigned int cpu);
+
+/**
+ * kthread_stop: stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_stop() for @k to return true, wakes it, and
+ * waits for it to exit.  Your threadfn() must not call do_exit()
+ * itself if you use this function!  This can also be called after
+ * kthread_create() instead of calling wake_up_process(): the thread
+ * will exit without calling threadfn().
+ *
+ * Returns the result of threadfn(), or -EINTR if wake_up_process()
+ * was never called. */
+int kthread_stop(struct task_struct *k);
+
+/**
+ * kthread_should_stop: should this kthread return now?
+ *
+ * When someone calls kthread_stop on your kthread, it will be woken
+ * and this will return true.  You should then return, and your return
+ * value will be passed through to kthread_stop().
+ */
+int kthread_should_stop(void);
+
+#endif /* _LINUX_KTHREAD_H */
--- diff/include/linux/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/lockmeter.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,320 @@
+/*
+ *  Copyright (C) 1999-2002 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code to include/asm/lockmeter.h.
+ *
+ */
+
+#ifndef _LINUX_LOCKMETER_H
+#define _LINUX_LOCKMETER_H
+
+
+/*---------------------------------------------------
+ *	architecture-independent lockmeter.h
+ *-------------------------------------------------*/
+
+/*
+ * raybry -- version 2: added efficient hold time statistics
+ *           requires lstat recompile, so flagged as new version
+ * raybry -- version 3: added global reader lock data
+ * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port
+ */
+#define LSTAT_VERSION	5
+
+int	lstat_update(void*, void*, int);
+int	lstat_update_time(void*, void*, int, uint32_t);
+
+/*
+ * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we
+ * need to force compatibility in the inter-communication data structure.
+ */
+
+#if defined(CONFIG_MIPS32_COMPAT)
+#define TIME_T		uint32_t
+#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
+#define TIME_T		uint64_t
+#else
+#define TIME_T		time_t
+#endif
+
+#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32)
+#define POINTER		void *
+#else
+#define	POINTER		int64_t
+#endif
+
+/*
+ * Values for the "action" parameter passed to lstat_update.
+ *	ZZZ - do we want a try-success status here???
+ */
+#define LSTAT_ACT_NO_WAIT	0
+#define LSTAT_ACT_SPIN		1
+#define LSTAT_ACT_REJECT	2
+#define LSTAT_ACT_WW_SPIN       3
+#define LSTAT_ACT_SLEPT		4 /* UNUSED */
+
+#define LSTAT_ACT_MAX_VALUES	4 /* NOTE: Increase to 5 if use ACT_SLEPT */
+
+/*
+ * Special values for the low 2 bits of an RA passed to
+ * lstat_update.
+ */
+/* we use these values to figure out what kind of lock data */
+/* is stored in the statistics table entry at index ....... */
+#define LSTAT_RA_SPIN           0  /* spin lock data */
+#define LSTAT_RA_READ           1  /* read lock statistics */
+#define LSTAT_RA_SEMA		2  /* RESERVED */
+#define LSTAT_RA_WRITE          3  /* write lock statistics*/
+
+#define LSTAT_RA(n)	\
+	((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) )
+
+/*
+ * Constants used for lock addresses in the lstat_directory
+ * to indicate special values of the lock address.
+ */
+#define	LSTAT_MULTI_LOCK_ADDRESS	NULL
+
+/*
+ * Maximum size of the lockstats tables. Increase this value
+ * if its not big enough. (Nothing bad happens if its not
+ * big enough although some locks will not be monitored.)
+ * We record overflows of this quantity in lstat_control.dir_overflows
+ *
+ * Note:  The max value here must fit into the field set
+ * and obtained by the macro's PUT_INDEX() and GET_INDEX().
+ * This value depends on how many bits are available in the
+ * lock word in the particular machine implementation we are on.
+ */
+#define LSTAT_MAX_STAT_INDEX		2000
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ *	This defines an entry in the lockstat directory. It contains
+ *	information about a lock being monitored.
+ *	A directory entry only contains the lock identification -
+ *	counts on usage of the lock are kept elsewhere in a per-cpu
+ *	data structure to minimize cache line pinging.
+ */
+typedef struct {
+	POINTER	caller_ra;		  /* RA of code that set lock */
+	POINTER	lock_ptr;		  /* lock address */
+	ushort	next_stat_index;  /* Used to link multiple locks that have the same hash table value */
+} lstat_directory_entry_t;
+
+/*
+ *	A multi-dimensioned array used to contain counts for lock accesses.
+ *	The array is 3-dimensional:
+ *		- CPU number. Keep from thrashing cache lines between CPUs
+ *		- Directory entry index. Identifies the lock
+ *		- Action. Indicates what kind of contention occurred on an
+ *		  access to the lock.
+ *
+ *	The index of an entry in the directory is the same as the 2nd index
+ *	of the entry in the counts array.
+ */
+/*
+ *  This table contains data for spin_locks, write locks, and read locks
+ *  Not all data is used for all cases.  In particular, the hold time
+ *  information is not stored here for read locks since that is a global
+ *  (e. g. cannot be separated out by return address) quantity.
+ *  See the lstat_read_lock_counts_t structure for the global read lock
+ *  hold time.
+ */
+typedef struct {
+	uint64_t    cum_wait_ticks;	/* sum of wait times               */
+	                                /* for write locks, sum of time a  */
+					/* writer is waiting for a reader  */
+	int64_t	    cum_hold_ticks;	/* cumulative sum of holds         */
+	                                /* not used for read mode locks    */
+					/* must be signed. ............... */
+	uint32_t    max_wait_ticks;	/* max waiting time                */
+	uint32_t    max_hold_ticks;	/* max holding time                */
+	uint64_t    cum_wait_ww_ticks;  /* sum times writer waits on writer*/
+	uint32_t    max_wait_ww_ticks;  /* max wait time writer vs writer  */
+	                                /* prev 2 only used for write locks*/
+	uint32_t    acquire_time;       /* time lock acquired this CPU     */
+	uint32_t    count[LSTAT_ACT_MAX_VALUES];
+} lstat_lock_counts_t;
+
+typedef lstat_lock_counts_t	lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX];
+
+/*
+ * User request to:
+ *	- turn statistic collection on/off, or to reset
+ */
+#define LSTAT_OFF	 0
+#define LSTAT_ON	 1
+#define LSTAT_RESET      2
+#define LSTAT_RELEASE    3
+
+#define LSTAT_MAX_READ_LOCK_INDEX 1000
+typedef struct {
+	POINTER	    lock_ptr;            /* address of lock for output stats */
+	uint32_t    read_lock_count;
+	int64_t     cum_hold_ticks;       /* sum of read lock hold times over */
+	                                  /* all callers. ....................*/
+	uint32_t    write_index;          /* last write lock hash table index */
+	uint32_t    busy_periods;         /* count of busy periods ended this */
+	uint64_t    start_busy;           /* time this busy period started. ..*/
+	uint64_t    busy_ticks;           /* sum of busy periods this lock. ..*/
+	uint64_t    max_busy;             /* longest busy period for this lock*/
+	uint32_t    max_readers;          /* maximum number of readers ...... */
+#ifdef USER_MODE_TESTING
+	rwlock_t    entry_lock;           /* lock for this read lock entry... */
+	                                  /* avoid having more than one rdr at*/
+	                                  /* needed for user space testing... */
+	                                  /* not needed for kernel 'cause it  */
+					  /* is non-preemptive. ............. */
+#endif
+} lstat_read_lock_counts_t;
+typedef lstat_read_lock_counts_t	lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX];
+
+#if defined(__KERNEL__) || defined(USER_MODE_TESTING)
+
+#ifndef USER_MODE_TESTING
+#include <asm/lockmeter.h>
+#else
+#include "asm_newlockmeter.h"
+#endif
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ * This version eliminates the per processor lock stack.  What we do is to
+ * store the index of the lock hash structure in unused bits in the lock
+ * itself.  Then on unlock we can find the statistics record without doing
+ * any additional hash or lock stack lookup.  This works for spin_locks.
+ * Hold time reporting is now basically as cheap as wait time reporting
+ * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT
+ * as in version 1.1.* of lockmeter.
+ *
+ * For rw_locks, we store the index of a global reader stats structure in
+ * the lock and the writer index is stored in the latter structure.
+ * For read mode locks we hash at the time of the lock to find an entry
+ * in the directory for reader wait time and the like.
+ * At unlock time for read mode locks, we update just the global structure
+ * so we don't need to know the reader directory index value at unlock time.
+ *
+ */
+
+/*
+ * Protocol to change lstat_control.state
+ *   This is complicated because we don't want the cum_hold_time for
+ * a rw_lock to be decremented in _read_lock_ without making sure it
+ * is incremented in _read_lock_ and vice versa.  So here is the
+ * way we change the state of lstat_control.state:
+ * I.  To Turn Statistics On
+ *     After allocating storage, set lstat_control.state non-zero.
+ * This works because we don't start updating statistics for in use
+ * locks until the reader lock count goes to zero.
+ * II. To Turn Statistics Off:
+ * (0)  Disable interrupts on this CPU
+ * (1)  Seize the lstat_control.directory_lock
+ * (2)  Obtain the current value of lstat_control.next_free_read_lock_index
+ * (3)  Store a zero in lstat_control.state.
+ * (4)  Release the lstat_control.directory_lock
+ * (5)  For each lock in the read lock list up to the saved value
+ *      (well, -1) of the next_free_read_lock_index, do the following:
+ *      (a)  Check validity of the stored lock address
+ *           by making sure that the word at the saved addr
+ *           has an index that matches this entry.  If not
+ *           valid, then skip this entry.
+ *      (b)  If there is a write lock already set on this lock,
+ *           skip to (d) below.
+ *      (c)  Set a non-metered write lock on the lock
+ *      (d)  set the cached INDEX in the lock to zero
+ *      (e)  Release the non-metered write lock.
+ * (6)  Re-enable interrupts
+ *
+ * These rules ensure that a read lock will not have its statistics
+ * partially updated even though the global lock recording state has
+ * changed.  See put_lockmeter_info() for implementation.
+ *
+ * The reason for (b) is that there may be write locks set on the
+ * syscall path to put_lockmeter_info() from user space.  If we do
+ * not do this check, then we can deadlock.  A similar problem would
+ * occur if the lock was read locked by the current CPU.  At the
+ * moment this does not appear to happen.
+ */
+
+/*
+ * Main control structure for lockstat. Used to turn statistics on/off
+ * and to maintain directory info.
+ */
+typedef struct {
+	int				state;
+	spinlock_t		control_lock;		/* used to serialize turning statistics on/off   */
+	spinlock_t		directory_lock;		/* for serialize adding entries to directory     */
+	volatile int	next_free_dir_index;/* next free entry in the directory */
+	/* FIXME not all of these fields are used / needed .............. */
+                /* the following fields represent data since     */
+		/* first "lstat on" or most recent "lstat reset" */
+	TIME_T      first_started_time;     /* time when measurement first enabled */
+	TIME_T      started_time;           /* time when measurement last started  */
+	TIME_T      ending_time;            /* time when measurement last disabled */
+	uint64_t    started_cycles64;       /* cycles when measurement last started          */
+	uint64_t    ending_cycles64;        /* cycles when measurement last disabled         */
+	uint64_t    enabled_cycles64;       /* total cycles with measurement enabled         */
+	int         intervals;              /* number of measurement intervals recorded      */
+	                                    /* i. e. number of times did lstat on;lstat off  */
+	lstat_directory_entry_t	*dir;		/* directory */
+	int         dir_overflow;           /* count of times ran out of space in directory  */
+	int         rwlock_overflow;        /* count of times we couldn't allocate a rw block*/
+	ushort		*hashtab;		 	    /* hash table for quick dir scans */
+	lstat_cpu_counts_t	*counts[NR_CPUS];	 /* Array of pointers to per-cpu stats */
+    int         next_free_read_lock_index;   /* next rwlock reader (global) stats block  */
+    lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats  */
+} lstat_control_t;
+
+#endif	/* defined(__KERNEL__) || defined(USER_MODE_TESTING) */
+
+typedef struct {
+	short		lstat_version;		/* version of the data */
+	short		state;			/* the current state is returned */
+	int		maxcpus;		/* Number of cpus present */
+	int		next_free_dir_index;	/* index of the next free directory entry */
+	TIME_T          first_started_time;	/* when measurement enabled for first time */
+	TIME_T          started_time;		/* time in secs since 1969 when stats last turned on  */
+	TIME_T		ending_time;		/* time in secs since 1969 when stats last turned off */
+	uint32_t	cycleval;		/* cycles per second */
+#ifdef notyet
+	void		*kernel_magic_addr;	/* address of kernel_magic */
+	void		*kernel_end_addr;	/* contents of kernel magic (points to "end") */
+#endif
+	int              next_free_read_lock_index; /* index of next (global) read lock stats struct */
+	uint64_t         started_cycles64;	/* cycles when measurement last started        */
+	uint64_t         ending_cycles64;	/* cycles when stats last turned off           */
+	uint64_t         enabled_cycles64;	/* total cycles with measurement enabled       */
+	int              intervals;		/* number of measurement intervals recorded      */
+						/* i.e. number of times we did lstat on;lstat off*/
+	int              dir_overflow;		/* number of times we wanted more space in directory */
+	int              rwlock_overflow;	/* # of times we wanted more space in read_locks_count */
+	struct new_utsname   uts;		/* info about machine where stats are measured */
+						/* -T option of lockstat allows data to be     */
+						/* moved to another machine. ................. */
+} lstat_user_request_t;
+
+#endif /* _LINUX_LOCKMETER_H */
--- diff/include/linux/netpoll.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/netpoll.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,38 @@
+/*
+ * Common code for low-level network console, dump, and debugger code
+ *
+ * Derived from netconsole, kgdb-over-ethernet, and netdump patches
+ */
+
+#ifndef _LINUX_NETPOLL_H
+#define _LINUX_NETPOLL_H
+
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+
+struct netpoll;
+
+struct netpoll {
+	struct net_device *dev;
+	char dev_name[16], *name;
+	void (*rx_hook)(struct netpoll *, int, char *, int);
+	u32 local_ip, remote_ip;
+	u16 local_port, remote_port;
+	unsigned char local_mac[6], remote_mac[6];
+	struct list_head rx_list;
+};
+
+void netpoll_poll(struct netpoll *np);
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
+void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
+int netpoll_parse_options(struct netpoll *np, char *opt);
+int netpoll_setup(struct netpoll *np);
+int netpoll_trap(void);
+void netpoll_set_trap(int trap);
+void netpoll_cleanup(struct netpoll *np);
+int netpoll_rx(struct sk_buff *skb);
+
+
+#endif
--- diff/include/linux/stop_machine.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/stop_machine.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,52 @@
+#ifndef _LINUX_STOP_MACHINE
+#define _LINUX_STOP_MACHINE
+/* "Bogolock": stop the entire machine, disable interrupts.  This is a
+   very heavy lock, which is equivalent to grabbing every spinlock
+   (and more).  So the "read" side to such a lock is anything which
+   diables preeempt. */
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+/**
+ * stop_machine_run: freeze the machine on all CPUs and run this function
+ * @fn: the function to run
+ * @data: the data ptr for the @fn()
+ * @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS.
+ *
+ * Description: This causes a thread to be scheduled on every other cpu,
+ * each of which disables interrupts, and finally interrupts are disabled
+ * on the current CPU.  The result is that noone is holding a spinlock
+ * or inside any other preempt-disabled region when @fn() runs.
+ *
+ * This can be thought of as a very heavy write lock, equivalent to
+ * grabbing every spinlock in the kernel. */
+int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu);
+
+/**
+ * __stop_machine_run: freeze the machine on all CPUs and run this function
+ * @fn: the function to run
+ * @data: the data ptr for the @fn
+ * @cpu: the cpu to run @fn on (or any, if @cpu == NR_CPUS.
+ *
+ * Description: This is a special version of the above, which returns the
+ * thread which has run @fn(): kthread_stop will return the return value
+ * of @fn().  Used by hotplug cpu.
+ */
+struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
+				       unsigned int cpu);
+
+#else
+
+static inline int stop_machine_run(int (*fn)(void *), void *data,
+				   unsigned int cpu)
+{
+	int ret;
+	local_irq_disable();
+	ret = fn(data);
+	local_irq_enable();
+	return ret;
+}
+#endif /* CONFIG_SMP */
+#endif /* _LINUX_STOP_MACHINE */
--- diff/include/linux/syscalls.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/syscalls.h	2004-02-18 09:04:02.000000000 +0000
@@ -0,0 +1,480 @@
+/*
+ * syscalls.h - Linux syscall interfaces (non-arch-specific)
+ *
+ * Copyright (c) 2004 Randy Dunlap
+ * Copyright (c) 2004 Open Source Development Labs
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifndef _LINUX_SYSCALLS_H
+#define _LINUX_SYSCALLS_H
+
+struct epoll_event;
+struct iattr;
+struct inode;
+struct iocb;
+struct io_event;
+struct iovec;
+struct itimerspec;
+struct itimerval;
+struct linux_dirent;
+struct linux_dirent64;
+struct list_head;
+struct msgbuf;
+struct msghdr;
+struct msqid_ds;
+struct new_utsname;
+struct nfsctl_arg;
+struct __old_kernel_stat;
+struct pollfd;
+struct rlimit;
+struct rusage;
+struct sched_param;
+struct semaphore;
+struct sembuf;
+struct shmid_ds;
+struct sockaddr;
+struct stat;
+struct stat64;
+struct statfs;
+struct statfs64;
+struct __sysctl_args;
+struct sysinfo;
+struct timespec;
+struct timeval;
+struct timex;
+struct timezone;
+struct tms;
+struct utimbuf;
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/aio_abi.h>
+#include <linux/capability.h>
+#include <linux/list.h>
+#include <linux/sem.h>
+#include <asm/semaphore.h>
+#include <asm/siginfo.h>
+#include <asm/signal.h>
+#include <linux/quota.h>
+
+asmlinkage long sys_time(int *tloc);
+asmlinkage long sys_stime(time_t *tptr);
+asmlinkage long sys_gettimeofday(struct timeval __user *tv,
+				struct timezone __user *tz);
+asmlinkage long sys_settimeofday(struct timeval __user *tv,
+				struct timezone __user *tz);
+asmlinkage long sys_adjtimex(struct timex __user *txc_p);
+
+asmlinkage long sys_times(struct tms __user *tbuf);
+
+asmlinkage long sys_gettid(void);
+asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+asmlinkage unsigned long sys_alarm(unsigned int seconds);
+asmlinkage long sys_getpid(void);
+asmlinkage long sys_getppid(void);
+asmlinkage long sys_getuid(void);
+asmlinkage long sys_geteuid(void);
+asmlinkage long sys_getgid(void);
+asmlinkage long sys_getegid(void);
+asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
+asmlinkage long sys_getpgid(pid_t pid);
+asmlinkage long sys_getpgrp(void);
+asmlinkage long sys_getsid(pid_t pid);
+asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist);
+
+asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
+asmlinkage long sys_setgid(gid_t gid);
+asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
+asmlinkage long sys_setuid(uid_t uid);
+asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
+asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+asmlinkage long sys_setfsuid(uid_t uid);
+asmlinkage long sys_setfsgid(gid_t gid);
+asmlinkage long sys_setpgid(pid_t pid, pid_t pgid);
+asmlinkage long sys_setsid(void);
+asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist);
+
+asmlinkage long sys_acct(const char *name);
+asmlinkage long sys_capget(cap_user_header_t header,
+				cap_user_data_t dataptr);
+asmlinkage long sys_capset(cap_user_header_t header,
+				const cap_user_data_t data);
+asmlinkage long sys_personality(u_long personality);
+
+asmlinkage long sys_sigpending(old_sigset_t __user *set);
+asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set,
+				old_sigset_t __user *oset);
+asmlinkage long sys_getitimer(int which, struct itimerval __user *value);
+asmlinkage long sys_setitimer(int which,
+				struct itimerval __user *value,
+				struct itimerval __user *ovalue);
+asmlinkage long sys_timer_gettime(timer_t timer_id,
+				struct itimerspec __user *setting);
+asmlinkage long sys_timer_getoverrun(timer_t timer_id);
+asmlinkage long sys_timer_settime(timer_t timer_id, int flags,
+				const struct itimerspec __user *new_setting,
+				struct itimerspec __user *old_setting);
+asmlinkage long sys_timer_delete(timer_t timer_id);
+asmlinkage long sys_clock_settime(clockid_t which_clock,
+				const struct timespec __user *tp);
+asmlinkage long sys_clock_gettime(clockid_t which_clock,
+				struct timespec __user *tp);
+asmlinkage long sys_clock_getres(clockid_t which_clock,
+				struct timespec __user *tp);
+asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags,
+				const struct timespec __user *rqtp,
+				struct timespec __user *rmtp);
+
+asmlinkage long sys_nice(int increment);
+asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
+					struct sched_param __user *param);
+asmlinkage long sys_sched_setparam(pid_t pid,
+					struct sched_param __user *param);
+asmlinkage long sys_sched_getscheduler(pid_t pid);
+asmlinkage long sys_sched_getparam(pid_t pid,
+					struct sched_param __user *param);
+asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
+					unsigned long __user *user_mask_ptr);
+asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
+					unsigned long __user *user_mask_ptr);
+asmlinkage long sys_sched_yield(void);
+asmlinkage long sys_sched_get_priority_max(int policy);
+asmlinkage long sys_sched_get_priority_min(int policy);
+asmlinkage long sys_sched_rr_get_interval(pid_t pid,
+					struct timespec __user *interval);
+asmlinkage long sys_setpriority(int which, int who, int niceval);
+asmlinkage long sys_getpriority(int which, int who);
+
+asmlinkage long sys_shutdown(int, int);
+asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
+				void __user *arg);
+asmlinkage long sys_restart_syscall(void);
+
+asmlinkage long sys_exit(int error_code);
+asmlinkage void sys_exit_group(int error_code);
+asmlinkage long sys_wait4(pid_t pid, unsigned int *stat_addr,
+				int options, struct rusage *ru);
+asmlinkage long sys_waitpid(pid_t pid, unsigned int *stat_addr, int options);
+asmlinkage long sys_set_tid_address(int __user *tidptr);
+asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
+			struct timespec __user *utime, u32 __user *uaddr2);
+
+asmlinkage long sys_init_module(void __user *umod, unsigned long len,
+				const char __user *uargs);
+asmlinkage long sys_delete_module(const char __user *name_user,
+				unsigned int flags);
+
+asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set,
+				sigset_t __user *oset, size_t sigsetsize);
+asmlinkage long sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize);
+asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese,
+				siginfo_t __user *uinfo,
+				const struct timespec __user *uts,
+				size_t sigsetsize);
+asmlinkage long sys_kill(int pid, int sig);
+asmlinkage long sys_tgkill(int tgid, int pid, int sig);
+asmlinkage long sys_tkill(int pid, int sig);
+asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t __user *uinfo);
+asmlinkage long sys_rt_sigaction(int sig,
+				const struct sigaction __user *act,
+				struct sigaction __user *oact,
+				size_t sigsetsize);
+asmlinkage long sys_sgetmask(void);
+asmlinkage long sys_ssetmask(int newmask);
+asmlinkage unsigned long sys_signal(int sig, __sighandler_t handler);
+asmlinkage long sys_pause(void);
+
+asmlinkage long sys_sync(void);
+asmlinkage long sys_fsync(unsigned int fd);
+asmlinkage long sys_fdatasync(unsigned int fd);
+asmlinkage long sys_bdflush(int func, long data);
+asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name,
+				char __user *type, unsigned long flags,
+				void __user *data);
+asmlinkage long sys_umount(char __user *name, int flags);
+asmlinkage long sys_oldumount(char __user *name);
+asmlinkage long sys_truncate(const char __user *path,
+				unsigned long length);
+asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
+asmlinkage long sys_stat(char __user *filename,
+			struct __old_kernel_stat __user *statbuf);
+asmlinkage long sys_statfs(const char __user * path,
+				struct statfs __user *buf);
+asmlinkage long sys_statfs64(const char __user *path, size_t sz,
+				struct statfs64 __user *buf);
+asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user *buf);
+asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz,
+				struct statfs64 __user *buf);
+asmlinkage long sys_lstat(char __user *filename,
+			struct __old_kernel_stat __user *statbuf);
+asmlinkage long sys_fstat(unsigned int fd,
+			struct __old_kernel_stat __user *statbuf);
+asmlinkage long sys_newstat(char __user *filename,
+				struct stat __user *statbuf);
+asmlinkage long sys_newlstat(char __user *filename,
+				struct stat __user *statbuf);
+asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf);
+asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf);
+#if BITS_PER_LONG == 32
+asmlinkage long sys_stat64(char __user *filename,
+				struct stat64 __user *statbuf);
+asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
+asmlinkage long sys_lstat64(char __user *filename,
+				struct stat64 __user *statbuf);
+asmlinkage long sys_truncate64(const char __user *path, loff_t length);
+asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
+#endif
+
+asmlinkage long sys_setxattr(char __user *path, char __user *name,
+				void __user *value, size_t size, int flags);
+asmlinkage long sys_lsetxattr(char __user *path, char __user *name,
+				void __user *value, size_t size, int flags);
+asmlinkage long sys_fsetxattr(int fd, char __user *name, void __user *value,
+				size_t size, int flags);
+asmlinkage ssize_t sys_getxattr(char __user *path, char __user *name,
+				void __user *value, size_t size);
+asmlinkage ssize_t sys_lgetxattr(char __user *path, char __user *name,
+				void __user *value, size_t size);
+asmlinkage ssize_t sys_fgetxattr(int fd, char __user *name,
+				void __user *value, size_t size);
+asmlinkage ssize_t sys_listxattr(char __user *path, char __user *list,
+				size_t size);
+asmlinkage ssize_t sys_llistxattr(char __user *path, char __user *list,
+				size_t size);
+asmlinkage ssize_t sys_flistxattr(int fd, char __user *list, size_t size);
+asmlinkage long sys_removexattr(char __user *path, char __user *name);
+asmlinkage long sys_lremovexattr(char __user *path, char __user *name);
+asmlinkage long sys_fremovexattr(int fd, char __user *name);
+
+asmlinkage unsigned long sys_brk(unsigned long brk);
+asmlinkage long sys_mprotect(unsigned long start, size_t len,
+				unsigned long prot);
+asmlinkage unsigned long sys_mremap(unsigned long addr,
+				unsigned long old_len, unsigned long new_len,
+				unsigned long flags, unsigned long new_addr);
+long sys_remap_file_pages(unsigned long start, unsigned long size,
+			unsigned long prot, unsigned long pgoff,
+			unsigned long flags);
+asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
+asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice);
+asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice);
+asmlinkage long sys_munmap(unsigned long addr, size_t len);
+asmlinkage long sys_mlock(unsigned long start, size_t len);
+asmlinkage long sys_munlock(unsigned long start, size_t len);
+asmlinkage long sys_mlockall(int flags);
+asmlinkage long sys_munlockall(void);
+asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior);
+asmlinkage long sys_mincore(unsigned long start, size_t len,
+				unsigned char __user * vec);
+
+asmlinkage long sys_pivot_root(const char __user *new_root,
+				const char __user *put_old);
+asmlinkage long sys_chroot(const char __user *filename);
+asmlinkage long sys_mknod(const char __user *filename, int mode,
+				unsigned dev);
+asmlinkage long sys_link(const char __user *oldname,
+				const char __user *newname);
+asmlinkage long sys_symlink(const char *old, const char *new);
+asmlinkage long sys_unlink(const char __user *pathname);
+asmlinkage long sys_rename(const char __user *oldname,
+				const char __user *newname);
+asmlinkage long sys_chmod(const char __user *filename, mode_t mode);
+asmlinkage long sys_fchmod(unsigned int fd, mode_t mode);
+
+asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+#if BITS_PER_LONG == 32
+asmlinkage long sys_fcntl64(unsigned int fd,
+				unsigned int cmd, unsigned long arg);
+#endif
+asmlinkage long sys_dup(unsigned int fildes);
+asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
+asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd,
+				unsigned long arg);
+asmlinkage long sys_flock(unsigned int fd, unsigned int cmd);
+asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
+asmlinkage long sys_io_destroy(aio_context_t ctx);
+asmlinkage long sys_io_getevents(aio_context_t ctx_id,
+				long min_nr,
+				long nr,
+				struct io_event *events,
+				struct timespec *timeout);
+asmlinkage long sys_io_submit(aio_context_t, long,
+				struct iocb __user **);
+asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb *iocb,
+			      struct io_event *result);
+asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd,
+				off_t __user *offset, size_t count);
+asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd,
+				loff_t __user *offset, size_t count);
+asmlinkage long sys_readlink(const char __user *path,
+				char __user *buf, int bufsiz);
+asmlinkage long sys_creat(const char __user *pathname, int mode);
+asmlinkage long sys_open(const char __user *filename,
+				int flags, int mode);
+asmlinkage long sys_close(unsigned int fd);
+asmlinkage long sys_access(const char __user *filename, int mode);
+asmlinkage long sys_vhangup(void);
+asmlinkage long sys_chown(const char __user *filename,
+				uid_t user, gid_t group);
+asmlinkage long sys_lchown(const char __user *filename,
+				uid_t user, gid_t group);
+asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
+#ifdef CONFIG_UID16
+asmlinkage long sys_chown16(const char *filename,
+				old_uid_t user, old_gid_t group);
+asmlinkage long sys_lchown16(const char *filename,
+				old_uid_t user, old_gid_t group);
+asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group);
+asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid);
+asmlinkage long sys_setgid16(old_gid_t gid);
+asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid);
+asmlinkage long sys_setuid16(old_uid_t uid);
+asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid);
+asmlinkage long sys_getresuid16(old_uid_t *ruid,
+				old_uid_t *euid, old_uid_t *suid);
+asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid);
+asmlinkage long sys_getresgid16(old_gid_t *rgid,
+				old_gid_t *egid, old_gid_t *sgid);
+asmlinkage long sys_setfsuid16(old_uid_t uid);
+asmlinkage long sys_setfsgid16(old_gid_t gid);
+asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist);
+asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist);
+asmlinkage long sys_getuid16(void);
+asmlinkage long sys_geteuid16(void);
+asmlinkage long sys_getgid16(void);
+asmlinkage long sys_getegid16(void);
+#endif
+
+asmlinkage long sys_utime(char __user *filename,
+				struct utimbuf __user *times);
+asmlinkage long sys_utimes(char __user *filename,
+				struct timeval __user *utimes);
+asmlinkage off_t sys_lseek(unsigned int fd, off_t offset,
+				unsigned int origin);
+asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
+			unsigned long offset_low, loff_t __user *result,
+			unsigned int origin);
+asmlinkage ssize_t sys_read(unsigned int fd, char __user *buf,
+				size_t count);
+asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+asmlinkage ssize_t sys_readv(unsigned long fd,
+				const struct iovec __user *vec,
+				unsigned long vlen);
+asmlinkage ssize_t sys_write(unsigned int fd, const char __user *buf,
+				size_t count);
+asmlinkage ssize_t sys_writev(unsigned long fd,
+				const struct iovec __user *vec,
+				unsigned long vlen);
+asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
+				size_t count, loff_t pos);
+asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
+				size_t count, loff_t pos);
+asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
+asmlinkage long sys_mkdir(const char __user *pathname, int mode);
+asmlinkage long sys_chdir(const char __user *filename);
+asmlinkage long sys_fchdir(unsigned int fd);
+asmlinkage long sys_rmdir(const char __user *pathname);
+asmlinkage long sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
+asmlinkage long sys_quotactl(unsigned int cmd, const char *special,
+				qid_t id, caddr_t addr);
+asmlinkage long sys_getdents(unsigned int fd,
+				struct linux_dirent __user *dirent,
+				unsigned int count);
+asmlinkage long sys_getdents64(unsigned int fd,
+				struct linux_dirent64 __user *dirent,
+				unsigned int count);
+
+asmlinkage long sys_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen);
+asmlinkage long sys_getsockopt(int fd, int level, int optname,
+				char __user *optval, int __user *optlen);
+asmlinkage long sys_bind(int, struct sockaddr *, int);
+asmlinkage long sys_connect(int, struct sockaddr *, int);
+asmlinkage long sys_accept(int, struct sockaddr *, int *);
+asmlinkage long sys_getsockname(int, struct sockaddr *, int *);
+asmlinkage long sys_getpeername(int, struct sockaddr *, int *);
+asmlinkage long sys_send(int, void *, size_t, unsigned);
+asmlinkage long sys_sendto(int, void *, size_t, unsigned,
+				struct sockaddr *, int);
+asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
+asmlinkage long sys_recv(int, void *, size_t, unsigned);
+asmlinkage long sys_recvfrom(int, void *, size_t, unsigned,
+				struct sockaddr *, int *);
+asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
+asmlinkage long sys_socket(int, int, int);
+asmlinkage long sys_socketpair(int, int, int, int [2]);
+asmlinkage long sys_socketcall(int call, unsigned long __user *args);
+asmlinkage long sys_listen(int, int);
+asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
+				long timeout);
+asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+			fd_set __user *exp, struct timeval __user *tvp);
+asmlinkage long sys_epoll_create(int size);
+asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
+				struct epoll_event __user *event);
+asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+				int maxevents, int timeout);
+asmlinkage long sys_gethostname(char __user *name, int len);
+asmlinkage long sys_sethostname(char __user *name, int len);
+asmlinkage long sys_setdomainname(char __user *name, int len);
+asmlinkage long sys_newuname(struct new_utsname __user *name);
+
+asmlinkage long sys_getrlimit(unsigned int resource,
+				struct rlimit __user *rlim);
+#if defined(COMPAT_RLIM_OLD_INFINITY) || !(defined(CONFIG_IA64) || defined(CONFIG_V850))
+asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
+#endif
+asmlinkage long sys_setrlimit(unsigned int resource,
+				struct rlimit __user *rlim);
+asmlinkage long sys_getrusage(int who, struct rusage __user *ru);
+asmlinkage long sys_umask(int mask);
+
+asmlinkage long sys_msgget(key_t key, int msgflg);
+asmlinkage long sys_msgsnd(int msqid, struct msgbuf __user *msgp,
+				size_t msgsz, int msgflg);
+asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp,
+				size_t msgsz, long msgtyp, int msgflg);
+asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
+
+asmlinkage long sys_semget(key_t key, int nsems, int semflg);
+asmlinkage long sys_semop(int semid, struct sembuf __user *sops,
+				unsigned nsops);
+asmlinkage long sys_semctl(int semid, int semnum, int cmd, union semun arg);
+asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
+				unsigned nsops,
+				const struct timespec __user *timeout);
+asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
+				int shmflg, unsigned long *addr);
+asmlinkage long sys_shmget(key_t key, size_t size, int flag);
+asmlinkage long sys_shmdt(char __user *shmaddr);
+asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
+
+asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn);
+asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+				unsigned long off, unsigned long len,
+				void *buf);
+asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+				unsigned long off, unsigned long len,
+				void *buf);
+
+asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
+			unsigned long arg4, unsigned long arg5);
+asmlinkage long sys_swapon(const char __user *specialfile, int swap_flags);
+asmlinkage long sys_swapoff(const char __user *specialfile);
+asmlinkage long sys_sysctl(struct __sysctl_args __user *args);
+asmlinkage long sys_sysinfo(struct sysinfo __user *info);
+asmlinkage long sys_sysfs(int option,
+				unsigned long arg1, unsigned long arg2);
+asmlinkage long sys_nfsservctl(int cmd,
+				struct nfsctl_arg __user *arg,
+				void __user *res);
+asmlinkage long sys_syslog(int type, char __user *buf, int len);
+asmlinkage long sys_uselib(const char __user *library);
+asmlinkage long sys_ni_syscall(void);
+
+#endif
--- diff/ipc/compat.c	1970-01-01 01:00:00.000000000 +0100
+++ source/ipc/compat.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,699 @@
+/*
+ * 32 bit compatibility code for System V IPC
+ *
+ * Copyright (C) 1997,1998	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997		David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1999		Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2000		VA Linux Co
+ * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
+ * Copyright (C) 2000           Hewlett-Packard Co.
+ * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000           Gerhard Tonn (ton@de.ibm.com)
+ * Copyright (C) 2000-2002      Andi Kleen, SuSE Labs (x86-64 port)
+ * Copyright (C) 2000		Silicon Graphics, Inc.
+ * Copyright (C) 2001		IBM
+ * Copyright (C) 2004		IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2004		Arnd Bergmann (arnd@arndb.de)
+ *
+ * This code is collected from the versions for sparc64, mips64, s390x, ia64,
+ * ppc64 and x86_64, all of which are based on the original sparc64 version
+ * by Jakub Jelinek.
+ *
+ */
+#include <linux/compat.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/highuid.h>
+#include <linux/init.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include "util.h"
+
+struct compat_msgbuf {
+	compat_long_t mtype;
+	char mtext[1];
+};
+
+struct compat_ipc_perm {
+	key_t key;
+	compat_uid_t uid;
+	compat_gid_t gid;
+	compat_uid_t cuid;
+	compat_gid_t cgid;
+	compat_mode_t mode;
+	unsigned short seq;
+};
+
+struct compat_semid_ds {
+	struct compat_ipc_perm sem_perm;
+	compat_time_t sem_otime;
+	compat_time_t sem_ctime;
+	compat_uptr_t sem_base;
+	compat_uptr_t sem_pending;
+	compat_uptr_t sem_pending_last;
+	compat_uptr_t undo;
+	unsigned short sem_nsems;
+};
+
+struct compat_msqid_ds {
+	struct compat_ipc_perm msg_perm;
+	compat_uptr_t msg_first;
+	compat_uptr_t msg_last;
+	compat_time_t msg_stime;
+	compat_time_t msg_rtime;
+	compat_time_t msg_ctime;
+	compat_ulong_t msg_lcbytes;
+	compat_ulong_t msg_lqbytes;
+	unsigned short msg_cbytes;
+	unsigned short msg_qnum;
+	unsigned short msg_qbytes;
+	compat_ipc_pid_t msg_lspid;
+	compat_ipc_pid_t msg_lrpid;
+};
+
+struct compat_shmid_ds {
+	struct compat_ipc_perm shm_perm;
+	int shm_segsz;
+	compat_time_t shm_atime;
+	compat_time_t shm_dtime;
+	compat_time_t shm_ctime;
+	compat_ipc_pid_t shm_cpid;
+	compat_ipc_pid_t shm_lpid;
+	unsigned short shm_nattch;
+	unsigned short shm_unused;
+	compat_uptr_t shm_unused2;
+	compat_uptr_t shm_unused3;
+};
+
+struct compat_ipc_kludge {
+	compat_uptr_t msgp;
+	compat_long_t msgtyp;
+};
+
+struct compat_shm_info {
+	compat_int_t used_ids;
+	compat_ulong_t shm_tot, shm_rss, shm_swp;
+	compat_ulong_t swap_attempts, swap_successes;
+};
+
+extern int sem_ctls[];
+#define sc_semopm	(sem_ctls[2])
+#define MAXBUF (64*1024)
+
+static inline int compat_ipc_parse_version(int *cmd)
+{
+        if (*cmd & IPC_64) {
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+		/* why is this needed? */
+                *cmd ^= IPC_64;
+#endif
+                return IPC_64;
+        } else {
+                return IPC_OLD;
+        }
+}
+static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
+					  struct compat_ipc64_perm *up64)
+{
+	int err;
+
+	err  = __get_user(p64->uid, &up64->uid);
+	err |= __get_user(p64->gid, &up64->gid);
+	err |= __get_user(p64->mode, &up64->mode);
+	return err;
+}
+
+static inline int __get_compat_ipc_perm(struct ipc_perm *p,
+					struct compat_ipc_perm *up)
+{
+	int err;
+
+	err  = __get_user(p->uid, &up->uid);
+	err |= __get_user(p->gid, &up->gid);
+	err |= __get_user(p->mode, &up->mode);
+	return err;
+}
+
+static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
+					  struct compat_ipc64_perm *up64)
+{
+	int err;
+
+	err  = __put_user(p64->key, &up64->key);
+	err |= __put_user(p64->uid, &up64->uid);
+	err |= __put_user(p64->gid, &up64->gid);
+	err |= __put_user(p64->cuid, &up64->cuid);
+	err |= __put_user(p64->cgid, &up64->cgid);
+	err |= __put_user(p64->mode, &up64->mode);
+	err |= __put_user(p64->seq, &up64->seq);
+	return err;
+}
+
+static inline int __put_compat_ipc_perm(struct ipc_perm *p,
+					struct compat_ipc_perm *up)
+{
+	int err;
+	compat_uid_t u;
+	compat_gid_t g;
+
+	err  = __put_user(p->key, &up->key);
+	SET_UID(u, p->uid);
+	err |= __put_user(u, &up->uid);
+	SET_GID(g, p->gid);
+	err |= __put_user(g, &up->gid);
+	SET_UID(u, p->cuid);
+	err |= __put_user(u, &up->cuid);
+	SET_GID(g, p->cgid);
+	err |= __put_user(g, &up->cgid);
+	err |= __put_user(p->mode, &up->mode);
+	err |= __put_user(p->seq, &up->seq);
+	return err;
+}
+
+static inline int get_compat_semid64_ds(struct semid64_ds *s64,
+					struct compat_semid64_ds *up64)
+{
+	if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
+}
+
+static inline int get_compat_semid_ds(struct semid_ds *s,
+				      struct compat_semid_ds *up)
+{
+	if (!access_ok (VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
+}
+
+static inline int put_compat_semid64_ds(struct semid64_ds *s64,
+					struct compat_semid64_ds *up64)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
+	err |= __put_user(s64->sem_otime, &up64->sem_otime);
+	err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
+	err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
+	return err;
+}
+
+static inline int put_compat_semid_ds(struct semid_ds *s,
+				      struct compat_semid_ds *up)
+{
+	int err;
+
+	if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
+		err = -EFAULT;
+	err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
+	err |= __put_user(s->sem_otime, &up->sem_otime);
+	err |= __put_user(s->sem_ctime, &up->sem_ctime);
+	err |= __put_user(s->sem_nsems, &up->sem_nsems);
+	return err;
+}
+
+static inline int do_semctl(int semid, int semnum, int cmd, union semun arg)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_semctl(semid, semnum, cmd, arg);
+	set_fs(old_fs);
+
+	return err;
+}
+long compat_sys_semctl(int first, int second, int third, void __user *uptr)
+{
+	union semun fourth;
+	u32 pad;
+	int err, err2;
+	struct semid64_ds s64;
+	struct semid_ds s;
+	int version = compat_ipc_parse_version(&third);
+
+	if (!uptr)
+		return -EINVAL;
+	if (get_user(pad, (u32 __user *) uptr))
+		return -EFAULT;
+	if ((third & (~IPC_64)) == SETVAL)
+		fourth.val = (int) pad;
+	else
+		fourth.__pad = compat_ptr(pad);
+	switch (third & (~IPC_64)) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case SEM_INFO:
+	case GETVAL:
+	case GETPID:
+	case GETNCNT:
+	case GETZCNT:
+	case GETALL:
+	case SETVAL:
+	case SETALL:
+		err = sys_semctl(first, second, third, fourth);
+		break;
+
+	case IPC_STAT:
+	case SEM_STAT:
+		if (version == IPC_64) {
+			fourth.__pad = &s64;
+			err = do_semctl(first, second, third, fourth);
+			if (err < 0)
+				break;
+			err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
+		} else {
+			fourth.__pad = &s;
+			err = do_semctl(first, second, third, fourth);
+			if (err < 0)
+				break;
+			err2 = put_compat_semid_ds(&s, compat_ptr(pad));
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_semid64_ds(&s64, compat_ptr(pad));
+			if (err)
+				break;
+			fourth.__pad = &s64;
+		} else {
+			err = get_compat_semid_ds(&s, compat_ptr(pad));
+			if (err)
+				break;
+			fourth.__pad = &s;
+		}
+		err = do_semctl(first, second, third, fourth);
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
+{
+	struct msgbuf *p;
+	struct compat_msgbuf __user *up;
+	mm_segment_t old_fs;
+	int err;
+
+	if (first < 0)
+		return -EINVAL;
+	if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
+		return -EINVAL;
+
+#ifdef CONFIG_MIPS64 /* FIXME: This looks wrong */
+	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+#else
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+#endif
+	if (!p)
+		return -ENOMEM;
+	err = -EFAULT;
+	up = uptr;
+	if (get_user(p->mtype, &up->mtype) ||
+	    copy_from_user(p->mtext, &up->mtext, second))
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgsnd(first, p, second, third);
+	set_fs(old_fs);
+out:
+	kfree(p);
+	return err;
+}
+
+long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
+			   int version, void __user *uptr)
+{
+	struct msgbuf *p;
+	struct compat_msgbuf __user *up;
+	mm_segment_t old_fs;
+	int err;
+
+	if (first < 0)
+		return -EINVAL;
+	if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
+		return -EINVAL;
+
+#ifdef CONFIG_ARCH_MIPS
+	second += 4;
+#endif
+
+	if (!version) {
+		struct compat_ipc_kludge __user *uipck = uptr;
+		struct compat_ipc_kludge ipck;
+
+		err = -EINVAL;
+		if (!uptr)
+			goto out;
+		err = -EFAULT;
+		if (copy_from_user (&ipck, uipck, sizeof(ipck)))
+			goto out;
+		uptr = compat_ptr(ipck.msgp);
+		msgtyp = ipck.msgtyp;
+	}
+	err = -ENOMEM;
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
+	if (!p)
+		goto out;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
+	set_fs(old_fs);
+	if (err < 0)
+		goto free_then_out;
+	up = uptr;
+	if (put_user(p->mtype, &up->mtype) ||
+	    __copy_to_user(&up->mtext, p->mtext, err))
+		err = -EFAULT;
+free_then_out:
+	kfree(p);
+out:
+	return err;
+}
+
+static inline int get_compat_msqid64(struct msqid64_ds *m64,
+				     struct compat_msqid64_ds __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
+	err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
+	return err;
+}
+
+static inline int get_compat_msqid(struct msqid_ds *m,
+				   struct compat_msqid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
+	err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
+	return err;
+}
+
+static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
+				 struct compat_msqid64_ds __user __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
+	err |= __put_user(m64->msg_stime, &up64->msg_stime);
+	err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
+	err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
+	err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
+	err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
+	err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
+	err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
+	err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
+	return err;
+}
+
+static inline int put_compat_msqid_ds(struct msqid_ds *m,
+			       struct compat_msqid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
+	err |= __put_user(m->msg_stime, &up->msg_stime);
+	err |= __put_user(m->msg_rtime, &up->msg_rtime);
+	err |= __put_user(m->msg_ctime, &up->msg_ctime);
+	err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
+	err |= __put_user(m->msg_qnum, &up->msg_qnum);
+	err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
+	err |= __put_user(m->msg_lspid, &up->msg_lspid);
+	err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
+	return err;
+}
+
+static inline int do_msgctl(int first, int second, void __user *buf)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_msgctl(first, second, buf);
+	set_fs(old_fs);
+
+	return err;
+}
+
+long compat_sys_msgctl(int first, int second, void __user *uptr)
+{
+	int err, err2;
+	struct msqid_ds m;
+	struct msqid64_ds m64;
+	int version = compat_ipc_parse_version(&second);
+
+	switch (second & (~IPC_64)) {
+	case IPC_INFO:
+	case IPC_RMID:
+	case MSG_INFO:
+		err = sys_msgctl(first, second, uptr);
+		break;
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_msqid64(&m64, uptr);
+			if (err)
+				break;
+			err = do_msgctl(first, second, &m64);
+		} else {
+			err = get_compat_msqid(&m, uptr);
+			if (err)
+				break;
+			err = do_msgctl(first, second, &m);
+		}
+		break;
+
+	case IPC_STAT:
+	case MSG_STAT:
+		if (version == IPC_64) {
+			err = do_msgctl(first, second, &m64);
+			if (err < 0)
+				break;
+			err2 = put_compat_msqid64_ds(&m64, uptr);
+		} else {
+			err = do_msgctl(first, second, &m);
+			if (err < 0)
+				break;
+			err2 = put_compat_msqid_ds(&m, uptr);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
+			void __user *uptr)
+{
+	int err;
+	unsigned long raddr;
+	compat_ulong_t __user *uaddr;
+
+	if (version == 1)
+		return -EINVAL;
+	err = sys_shmat(first, uptr, second, &raddr);
+	if (err < 0)
+		return err;
+	uaddr = compat_ptr(third);
+	return put_user(raddr, uaddr);
+}
+
+static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
+				 struct compat_shmid64_ds __user *up64)
+{
+	if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
+		return -EFAULT;
+	return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
+}
+
+static inline int get_compat_shmid_ds(struct shmid_ds *s,
+			       struct compat_shmid_ds __user *up)
+{
+	if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+		return -EFAULT;
+	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
+}
+
+static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
+				 struct compat_shmid64_ds __user *up64)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
+		return -EFAULT;
+	err  = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
+	err |= __put_user(s64->shm_atime, &up64->shm_atime);
+	err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
+	err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
+	err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
+	err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
+	err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
+	err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
+	return err;
+}
+
+static inline int put_compat_shmid_ds(struct shmid_ds *s,
+			       struct compat_shmid_ds __user *up)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+		return -EFAULT;
+	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
+	err |= __put_user(s->shm_atime, &up->shm_atime);
+	err |= __put_user(s->shm_dtime, &up->shm_dtime);
+	err |= __put_user(s->shm_ctime, &up->shm_ctime);
+	err |= __put_user(s->shm_segsz, &up->shm_segsz);
+	err |= __put_user(s->shm_nattch, &up->shm_nattch);
+	err |= __put_user(s->shm_cpid, &up->shm_cpid);
+	err |= __put_user(s->shm_lpid, &up->shm_lpid);
+	return err;
+}
+
+static inline int put_compat_shm_info(struct shm_info *si,
+			       struct compat_shm_info __user *uip)
+{
+	int err;
+
+	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)))
+		return -EFAULT;
+	err  = __put_user(si->used_ids, &uip->used_ids);
+	err |= __put_user(si->shm_tot, &uip->shm_tot);
+	err |= __put_user(si->shm_rss, &uip->shm_rss);
+	err |= __put_user(si->shm_swp, &uip->shm_swp);
+	err |= __put_user(si->swap_attempts, &uip->swap_attempts);
+	err |= __put_user(si->swap_successes, &uip->swap_successes);
+	return err;
+}
+
+static inline int do_shmctl(int shmid, int cmd, void *buf)
+{
+	mm_segment_t old_fs;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_shmctl(shmid, cmd, buf);
+	set_fs(old_fs);
+
+	return err;
+}
+
+long compat_sys_shmctl(int first, int second, void __user *uptr)
+{
+	struct shmid_ds s;
+	struct shmid64_ds s64;
+	struct shm_info si;
+	int err, err2;
+	int version = compat_ipc_parse_version(&second);
+
+	switch (second & (~IPC_64)) {
+	case IPC_INFO:
+		second &= ~IPC_64;  /* So that we don't have to translate it */
+	case IPC_RMID:
+	case SHM_LOCK:
+	case SHM_UNLOCK:
+		err = sys_shmctl(first, second, uptr);
+		break;
+
+	case IPC_SET:
+		if (version == IPC_64) {
+			err = get_compat_shmid64_ds(&s64, uptr);
+			if (err)
+				break;
+			err = do_shmctl(first, second, &s64);
+		} else {
+			err = get_compat_shmid_ds(&s, uptr);
+			if (err)
+				break;
+			err = do_shmctl(first, second, &s);
+		}
+		break;
+
+	case IPC_STAT:
+	case SHM_STAT:
+		if (version == IPC_64) {
+			err = do_shmctl(first, second, &s64);
+			if (err < 0)
+				break;
+			err2 = put_compat_shmid64_ds(&s64, uptr);
+		} else {
+			err = do_shmctl(first, second, &s);
+			if (err < 0)
+				break;
+			err2 = put_compat_shmid_ds(&s, uptr);
+		}
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	case SHM_INFO:
+		err = do_shmctl(first, second, &si);
+		if (err < 0)
+			break;
+		err2 = put_compat_shm_info(&si, uptr);
+		if (err2)
+			err = -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
+		unsigned nsops, const struct compat_timespec __user *timeout)
+{
+	struct timespec ts, __user *ts64;
+
+	/* parameter checking precedence should mirror sys_semtimedop() */
+	if (nsops < 1 || semid < 0)
+		return -EINVAL;
+	if (nsops > sc_semopm)
+		return -E2BIG;
+	if (!access_ok(VERIFY_READ, tsems, nsops * sizeof(struct sembuf)))
+		return -EFAULT;
+	if (!timeout)
+		return sys_semtimedop(semid, tsems, nsops, 0);
+
+	ts64 = compat_alloc_user_space(sizeof(*ts64));
+	if (get_compat_timespec(&ts, timeout))
+		return -EFAULT;
+	if (copy_to_user(ts64, &ts, sizeof(ts)))
+		return -EFAULT;
+
+	return sys_semtimedop(semid, tsems, nsops, ts64);
+}
--- diff/kernel/compat_signal.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/compat_signal.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (C) 2003 Carlos O'Donell
+ *
+ *  2003-12-20  Carlos O'Donell
+ *              Copied linux/kernel/compat_signal.c (copy_siginfo_to_user)
+ *              and modified to use compat_siginfo_t for thunking down to
+ *              32-bit userspace from a 64-bit kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/compat_siginfo.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+#include <asm/siginfo.h>
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO_TO_USER
+
+int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, siginfo_t *from)
+{
+	int err;
+	compat_siginfo_t compat_from;
+
+	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+		return -EFAULT;
+
+	/*
+	 * If you change compat_siginfo_t structure *or* siginfo_t,
+	 * please be sure this code is fixed accordingly.
+	 * It should never copy any pad contained in the structure
+	 * to avoid security leaks, but must copy the generic
+	 * 3 ints plus the relevant union member.
+	 */
+
+	/* Convert structure, don't leak anything in the copy */
+	memset(&compat_from,'\0',sizeof(compat_siginfo_t));
+	compat_from.si_signo = (compat_int_t)(from->si_signo);
+	compat_from.si_errno = (compat_int_t)(from->si_errno);
+	compat_from.si_code = (compat_int_t)(from->si_code);
+
+	if (from->si_code < 0)
+		return __copy_to_user(to, &compat_from, sizeof(compat_siginfo_t))
+			? -EFAULT : 0;
+
+	err = __put_user(compat_from.si_signo, &to->si_signo);
+	err |= __put_user(compat_from.si_errno, &to->si_errno);
+	err |= __put_user(compat_from.si_code, &to->si_code);
+
+	switch (from->si_code & __SI_MASK) {
+	case __SI_KILL:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	case __SI_TIMER:
+		compat_from.si_pid = (compat_timer_t)(from->si_tid);
+		compat_from.si_overrun = (compat_int_t)(from->si_overrun);
+		compat_from.si_ptr = (compat_uptr_t)((u64)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_tid, &to->si_tid);
+		err |= __put_user(compat_from.si_overrun, &to->si_overrun);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	case __SI_POLL:
+		compat_from.si_band = (__ARCH_SI_COMPAT_BAND_T)(from->si_band);
+		compat_from.si_fd = (compat_int_t)(from->si_fd);
+		err |= __put_user(compat_from.si_band, &to->si_band);
+		err |= __put_user(compat_from.si_fd, &to->si_fd);
+		break;
+	case __SI_FAULT:
+		compat_from.si_addr = (compat_uptr_t)((u64)(from->si_addr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_addr, &to->si_addr);
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+		compat_from.si_trapno = (compat_int_t)(from->si_addr);
+		err |= __put_user(compat_from.si_trapno, &to->si_trapno);
+#endif
+		break;
+	case __SI_CHLD:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_status = (compat_int_t)(from->si_status);
+		compat_from.si_utime = (compat_clock_t)(from->si_utime);
+		compat_from.si_stime = (compat_clock_t)(from->si_stime);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_status, &to->si_status);
+		err |= __put_user(compat_from.si_utime, &to->si_utime);
+		err |= __put_user(compat_from.si_stime, &to->si_stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_int = (compat_int_t)(from->si_int);
+		compat_from.si_ptr = (compat_uptr_t)((u64)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_int, &to->si_int);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	default: /* this is just in case for now ... */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	}
+	return err;
+}
+
+#endif
--- diff/kernel/kthread.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/kthread.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,163 @@
+/* Kernel thread helper functions.
+ *   Copyright (C) 2004 IBM Corporation, Rusty Russell.
+ *
+ * Creation is done via keventd, so that we get a clean environment
+ * even if we're invoked from userspace (think modprobe, hotplug cpu,
+ * etc.).
+ */
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/unistd.h>
+#include <asm/semaphore.h>
+
+struct kthread_create_info
+{
+	/* Information passed to kthread() from keventd. */
+	int (*threadfn)(void *data);
+	void *data;
+	struct completion started;
+
+	/* Result passed back to kthread_create() from keventd. */
+	struct task_struct *result;
+	struct completion done;
+};
+
+struct kthread_stop_info
+{
+	struct task_struct *k;
+	int err;
+	struct completion done;
+};
+
+/* Thread stopping is done by setthing this var: lock serializes
+ * multiple kthread_stop calls. */
+static DECLARE_MUTEX(kthread_stop_lock);
+static struct kthread_stop_info kthread_stop_info;
+
+int kthread_should_stop(void)
+{
+	return (kthread_stop_info.k == current);
+}
+
+static int kthread(void *_create)
+{
+	struct kthread_create_info *create = _create;
+	int (*threadfn)(void *data);
+	void *data;
+	sigset_t blocked;
+	int ret = -EINTR;
+	cpumask_t mask = CPU_MASK_ALL;
+
+	/* Copy data: it's on keventd's stack */
+	threadfn = create->threadfn;
+	data = create->data;
+
+	/* Block and flush all signals (in case we're not from keventd). */
+	sigfillset(&blocked);
+	sigprocmask(SIG_BLOCK, &blocked, NULL);
+	flush_signals(current);
+
+	/* By default we can run anywhere, unlike keventd. */
+	set_cpus_allowed(current, mask);
+
+	/* OK, tell user we're spawned, wait for stop or wakeup */
+	__set_current_state(TASK_INTERRUPTIBLE);
+	complete(&create->started);
+	schedule();
+
+	if (!kthread_should_stop())
+		ret = threadfn(data);
+
+	/* It might have exited on its own, w/o kthread_stop.  Check. */
+	if (kthread_should_stop()) {
+		kthread_stop_info.err = ret;
+		complete(&kthread_stop_info.done);
+	}
+	return 0;
+}
+
+/* We are keventd: create a thread. */
+static void keventd_create_kthread(void *_create)
+{
+	struct kthread_create_info *create = _create;
+	int pid;
+
+	/* We want our own signal handler (we take no signals by default). */
+	pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
+	if (pid < 0) {
+		create->result = ERR_PTR(pid);
+	} else {
+		wait_for_completion(&create->started);
+		create->result = find_task_by_pid(pid);
+		wait_task_inactive(create->result);
+	}
+	complete(&create->done);
+}
+
+struct task_struct *kthread_create(int (*threadfn)(void *data),
+				   void *data,
+				   const char namefmt[],
+				   ...)
+{
+	struct kthread_create_info create;
+	DECLARE_WORK(work, keventd_create_kthread, &create);
+
+	create.threadfn = threadfn;
+	create.data = data;
+	init_completion(&create.started);
+	init_completion(&create.done);
+
+	/* If we're being called to start the first workqueue, we
+	 * can't use keventd. */
+	if (!keventd_up())
+		work.func(work.data);
+	else {
+		schedule_work(&work);
+		wait_for_completion(&create.done);
+	}
+	if (!IS_ERR(create.result)) {
+		va_list args;
+		va_start(args, namefmt);
+		vsnprintf(create.result->comm, sizeof(create.result->comm),
+			  namefmt, args);
+		va_end(args);
+	}
+
+	return create.result;
+}
+
+void kthread_bind(struct task_struct *k, unsigned int cpu)
+{
+	BUG_ON(k->state != TASK_INTERRUPTIBLE);
+	k->thread_info->cpu = cpu;
+	k->cpus_allowed = cpumask_of_cpu(cpu);
+}
+
+int kthread_stop(struct task_struct *k)
+{
+	int ret;
+
+	down(&kthread_stop_lock);
+
+	/* It could exit after stop_info.k set, but before wake_up_process. */
+	get_task_struct(k);
+
+	/* Must init completion *before* thread sees kthread_stop_info.k */
+	init_completion(&kthread_stop_info.done);
+	wmb();
+
+	/* Now set kthread_should_stop() to true, and wake it up. */
+	kthread_stop_info.k = k;
+	wake_up_process(k);
+	put_task_struct(k);
+
+	/* Once it dies, reset stop ptr, gather result and we're done. */
+	wait_for_completion(&kthread_stop_info.done);
+	kthread_stop_info.k = NULL;
+	ret = kthread_stop_info.err;
+	up(&kthread_stop_lock);
+
+	return ret;
+}
--- diff/kernel/lockmeter.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/lockmeter.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,1178 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.c by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/lockmeter.h>
+
+#define ASSERT(cond)
+#define bzero(loc,size)		memset(loc,0,size)
+
+/*<---------------------------------------------------*/
+/*              lockmeter.c                           */
+/*>---------------------------------------------------*/
+
+static lstat_control_t lstat_control __cacheline_aligned =
+	{ LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	  19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 };
+
+static ushort lstat_make_dir_entry(void *, void *);
+
+/*
+ * lstat_lookup
+ *
+ * Given a RA, locate the directory entry for the lock.
+ */
+static ushort
+lstat_lookup(void *lock_ptr, void *caller_ra)
+{
+	ushort index;
+	lstat_directory_entry_t *dirp;
+
+	dirp = lstat_control.dir;
+
+	index = lstat_control.hashtab[DIRHASH(caller_ra)];
+	while (dirp[index].caller_ra != caller_ra) {
+		if (index == 0) {
+			return lstat_make_dir_entry(lock_ptr, caller_ra);
+		}
+		index = dirp[index].next_stat_index;
+	}
+
+	if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) {
+		dirp[index].lock_ptr = NULL;
+	}
+
+	return index;
+}
+
+/*
+ * lstat_make_dir_entry
+ * Called to add a new lock to the lock directory.
+ */
+static ushort
+lstat_make_dir_entry(void *lock_ptr, void *caller_ra)
+{
+	lstat_directory_entry_t *dirp;
+	ushort index, hindex;
+	unsigned long flags;
+
+	/* lock the table without recursively reentering this metering code */
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	hindex = DIRHASH(caller_ra);
+	index = lstat_control.hashtab[hindex];
+	dirp = lstat_control.dir;
+	while (index && dirp[index].caller_ra != caller_ra)
+		index = dirp[index].next_stat_index;
+
+	if (index == 0) {
+		if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) {
+			index = lstat_control.next_free_dir_index++;
+			lstat_control.dir[index].caller_ra = caller_ra;
+			lstat_control.dir[index].lock_ptr = lock_ptr;
+			lstat_control.dir[index].next_stat_index =
+				lstat_control.hashtab[hindex];
+			lstat_control.hashtab[hindex] = index;
+		} else {
+			lstat_control.dir_overflow++;
+		}
+	}
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+int
+lstat_update(void *lock_ptr, void *caller_ra, int action)
+{
+	int index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+int
+lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks)
+{
+	ushort index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks;
+	if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks)
+		(*lstat_control.counts[cpu])[index].max_wait_ticks = ticks;
+
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+void
+_metered_spin_lock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_spin_lock(lock_ptr);	/* do the real lock */
+		PUT_INDEX(lock_ptr, 0);	/* clean index in case lockmetering  */
+		/* gets turned on before unlock */
+	} else {
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+		int index;
+
+		if (_raw_spin_trylock(lock_ptr)) {
+			index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+		} else {
+			uint32_t start_cycles = get_cycles();
+			_raw_spin_lock(lock_ptr);	/* do the real lock */
+			index = lstat_update_time(lock_ptr, this_pc,
+				LSTAT_ACT_SPIN, get_cycles() - start_cycles);
+		}
+		/* save the index in the lock itself for use in spin unlock */
+		PUT_INDEX(lock_ptr, index);
+	}
+}
+
+int
+_metered_spin_trylock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		return _raw_spin_trylock(lock_ptr);
+	} else {
+		int retval;
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+
+		if ((retval = _raw_spin_trylock(lock_ptr))) {
+			int index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+			/*
+			 * save the index in the lock itself for use in spin
+			 * unlock
+			 */
+			PUT_INDEX(lock_ptr, index);
+		} else {
+			lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT);
+		}
+
+		return retval;
+	}
+}
+
+void
+_metered_spin_unlock(spinlock_t * lock_ptr)
+{
+	int index = -1;
+
+	if (lstat_control.state != LSTAT_OFF) {
+		index = GET_INDEX(lock_ptr);
+		/*
+		 * If statistics were turned off when we set the lock,
+		 * then the index can be zero.  If that is the case,
+		 * then collect no stats on this call.
+		 */
+		if (index > 0) {
+			uint32_t hold_time;
+			int cpu = THIS_CPU_NUMBER;
+			hold_time = get_cycles() -
+			 (*lstat_control.counts[cpu])[index].acquire_time;
+			(*lstat_control.counts[cpu])[index].cum_hold_ticks +=
+				(uint64_t) hold_time;
+			if ((*lstat_control.counts[cpu])[index].max_hold_ticks <
+			    hold_time)
+				(*lstat_control.counts[cpu])[index].
+				    max_hold_ticks = hold_time;
+		}
+	}
+
+	/* make sure we don't have a stale index value saved */
+	PUT_INDEX(lock_ptr, 0);
+	_raw_spin_unlock(lock_ptr);	/* do the real unlock */
+}
+
+/*
+ * allocate the next global read lock structure and store its index
+ * in the rwlock at "lock_ptr".
+ */
+uint32_t
+alloc_rwlock_struct(rwlock_t * rwlock_ptr)
+{
+	int index;
+	unsigned long flags;
+	int cpu = THIS_CPU_NUMBER;
+
+	/* If we've already overflowed, then do a quick exit */
+	if (lstat_control.next_free_read_lock_index >
+			LSTAT_MAX_READ_LOCK_INDEX) {
+		lstat_control.rwlock_overflow++;
+		return 0;
+	}
+
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	/* It is possible this changed while we were waiting for the directory_lock */
+	if (lstat_control.state == LSTAT_OFF) {
+		index = 0;
+		goto unlock;
+	}
+
+	/* It is possible someone else got here first and set the index */
+	if ((index = GET_RWINDEX(rwlock_ptr)) == 0) {
+		/*
+		 * we can't turn on read stats for this lock while there are
+		 * readers (this would mess up the running hold time sum at
+		 * unlock time)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) != 0) {
+			index = 0;
+			goto unlock;
+		}
+
+		/*
+		 * if stats are turned on after being off, we may need to
+		 * return an old index from when the statistics were on last
+		 * time.
+		 */
+		for (index = 1; index < lstat_control.next_free_read_lock_index;
+				index++)
+			if ((*lstat_control.read_lock_counts[cpu])[index].
+					lock_ptr == rwlock_ptr)
+				goto put_index_and_unlock;
+
+		/* allocate the next global read lock structure */
+		if (lstat_control.next_free_read_lock_index >=
+		    LSTAT_MAX_READ_LOCK_INDEX) {
+			lstat_control.rwlock_overflow++;
+			index = 0;
+			goto unlock;
+		}
+		index = lstat_control.next_free_read_lock_index++;
+
+		/*
+		 * initialize the global read stats data structure for each
+		 * cpu
+		 */
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			(*lstat_control.read_lock_counts[cpu])[index].lock_ptr =
+				rwlock_ptr;
+		}
+put_index_and_unlock:
+		/* store the index for the read lock structure into the lock */
+		PUT_RWINDEX(rwlock_ptr, index);
+	}
+
+unlock:
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+void
+_metered_read_lock(rwlock_t * rwlock_ptr)
+{
+	void *this_pc;
+	uint32_t start_cycles;
+	int index;
+	int cpu;
+	unsigned long flags;
+	int readers_before, readers_after;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_READ);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0)
+		index = alloc_rwlock_struct(rwlock_ptr);
+
+	readers_before = RWLOCK_READERS(rwlock_ptr);
+	if (_raw_read_trylock(rwlock_ptr)) {
+		/*
+		 * We have decremented the lock to count a new reader,
+		 * and have confirmed that no writer has it locked.
+		 */
+		/* update statistics if enabled */
+		if (index > 0) {
+			local_irq_save(flags);
+			lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+			/* preserve value of TSC so cum_hold_ticks and start_busy use same value */
+			cycles64 = get_cycles64();
+			(*lstat_control.read_lock_counts[cpu])[index].
+				cum_hold_ticks -= cycles64;
+
+			/* record time and cpu of start of busy period */
+			/* this is not perfect (some race conditions are possible) */
+			if (readers_before == 0) {
+				(*lstat_control.read_lock_counts[cpu])[index].
+					start_busy = cycles64;
+				PUT_RW_CPU(rwlock_ptr, cpu);
+			}
+			readers_after = RWLOCK_READERS(rwlock_ptr);
+			if (readers_after >
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers)
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers = readers_after;
+			local_irq_restore(flags);
+		}
+
+		return;
+	}
+	/* If we get here, then we could not quickly grab the read lock */
+
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	/* Now spin until read_lock is successful */
+	_raw_read_lock(rwlock_ptr);
+
+	lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN,
+			  get_cycles() - start_cycles);
+
+	/* update statistics if they are enabled for this lock */
+	if (index > 0) {
+		local_irq_save(flags);
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -=
+				cycles64;
+
+		/* this is not perfect (some race conditions are possible) */
+		if (readers_before == 0) {
+			(*lstat_control.read_lock_counts[cpu])[index].
+				start_busy = cycles64;
+			PUT_RW_CPU(rwlock_ptr, cpu);
+		}
+		readers_after = RWLOCK_READERS(rwlock_ptr);
+		if (readers_after >
+		    (*lstat_control.read_lock_counts[cpu])[index].max_readers)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				max_readers = readers_after;
+		local_irq_restore(flags);
+	}
+}
+
+void
+_metered_read_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	unsigned long flags;
+	uint64_t busy_length;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_unlock(rwlock_ptr);
+		return;
+	}
+
+	index = GET_RWINDEX(rwlock_ptr);
+	cpu = THIS_CPU_NUMBER;
+
+	if (index > 0) {
+		local_irq_save(flags);
+		/*
+		 * preserve value of TSC so cum_hold_ticks and busy_ticks are
+		 * consistent.
+		 */
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks +=
+			cycles64;
+		(*lstat_control.read_lock_counts[cpu])[index].read_lock_count++;
+
+		/*
+		 * once again, this is not perfect (some race conditions are
+		 * possible)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) == 1) {
+			int cpu1 = GET_RW_CPU(rwlock_ptr);
+			uint64_t last_start_busy =
+				(*lstat_control.read_lock_counts[cpu1])[index].
+					start_busy;
+			(*lstat_control.read_lock_counts[cpu])[index].
+				busy_periods++;
+			if (cycles64 > last_start_busy) {
+				busy_length = cycles64 - last_start_busy;
+				(*lstat_control.read_lock_counts[cpu])[index].
+					busy_ticks += busy_length;
+				if (busy_length >
+					(*lstat_control.
+						read_lock_counts[cpu])[index].
+							max_busy)
+					(*lstat_control.
+					 read_lock_counts[cpu])[index].
+						max_busy = busy_length;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	_raw_read_unlock(rwlock_ptr);
+}
+
+void
+_metered_write_lock(rwlock_t * rwlock_ptr)
+{
+	uint32_t start_cycles;
+	void *this_pc;
+	uint32_t spin_ticks = 0; /* in anticipation of a potential wait */
+	int index;
+	int write_index = 0;
+	int cpu;
+	enum {
+		writer_writer_conflict,
+		writer_reader_conflict
+	} why_wait = writer_writer_conflict;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0) {
+		index = alloc_rwlock_struct(rwlock_ptr);
+	}
+
+	if (_raw_write_trylock(rwlock_ptr)) {
+		/* We acquired the lock on the first try */
+		write_index = lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+		/* save the write_index for use in unlock if stats enabled */
+		if (index > 0)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				write_index = write_index;
+		return;
+	}
+
+	/* If we get here, then we could not quickly grab the write lock */
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	why_wait = RWLOCK_READERS(rwlock_ptr) ?
+			writer_reader_conflict : writer_writer_conflict;
+
+	/* Now set the lock and wait for conflicts to disappear */
+	_raw_write_lock(rwlock_ptr);
+
+	spin_ticks = get_cycles() - start_cycles;
+
+	/* update stats -- if enabled */
+	if (index > 0 && spin_ticks) {
+		if (why_wait == writer_reader_conflict) {
+			/* waited due to a reader holding the lock */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+					this_pc, LSTAT_ACT_SPIN, spin_ticks);
+		} else {
+			/*
+			 * waited due to another writer holding the lock
+			 */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+				this_pc, LSTAT_ACT_WW_SPIN, spin_ticks);
+			(*lstat_control.counts[cpu])[write_index].
+				cum_wait_ww_ticks += spin_ticks;
+			if (spin_ticks >
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks) {
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks = spin_ticks;
+			}
+		}
+
+		/* save the directory index for use on write_unlock */
+		(*lstat_control.read_lock_counts[cpu])[index].
+			write_index = write_index;
+	}
+}
+
+void
+_metered_write_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	int write_index;
+	uint32_t hold_time;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_unlock(rwlock_ptr);
+		return;
+	}
+
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* update statistics if stats enabled for this lock */
+	if (index > 0) {
+		write_index =
+		    (*lstat_control.read_lock_counts[cpu])[index].write_index;
+
+		hold_time = get_cycles() -
+			(*lstat_control.counts[cpu])[write_index].acquire_time;
+		(*lstat_control.counts[cpu])[write_index].cum_hold_ticks +=
+			(uint64_t) hold_time;
+		if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks <
+				hold_time)
+			(*lstat_control.counts[cpu])[write_index].
+				max_hold_ticks = hold_time;
+	}
+	_raw_write_unlock(rwlock_ptr);
+}
+
+int
+_metered_write_trylock(rwlock_t * rwlock_ptr)
+{
+	int retval;
+	void *this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+
+	if ((retval = _raw_write_trylock(rwlock_ptr))) {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT);
+	} else {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT);
+	}
+
+	return retval;
+}
+
+static void
+init_control_space(void)
+{
+	/* Set all control space pointers to null and indices to "empty" */
+	int cpu;
+
+	/*
+	 * Access CPU_CYCLE_FREQUENCY at the outset, which in some
+	 * architectures may trigger a runtime calculation that uses a
+	 * spinlock.  Let's do this before lockmetering is turned on.
+	 */
+	if (CPU_CYCLE_FREQUENCY == 0)
+		BUG();
+
+	lstat_control.hashtab = NULL;
+	lstat_control.dir = NULL;
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		lstat_control.counts[cpu] = NULL;
+		lstat_control.read_lock_counts[cpu] = NULL;
+	}
+}
+
+static int
+reset_lstat_data(void)
+{
+	int cpu, flags;
+
+	flags = 0;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+	lstat_control.dir_overflow = 0;
+	lstat_control.rwlock_overflow = 0;
+
+	lstat_control.started_cycles64 = 0;
+	lstat_control.ending_cycles64 = 0;
+	lstat_control.enabled_cycles64 = 0;
+	lstat_control.first_started_time = 0;
+	lstat_control.started_time = 0;
+	lstat_control.ending_time = 0;
+	lstat_control.intervals = 0;
+
+	/*
+	 * paranoia -- in case someone does a "lockstat reset" before
+	 * "lockstat on"
+	 */
+	if (lstat_control.hashtab) {
+		bzero(lstat_control.hashtab,
+			LSTAT_HASH_TABLE_SIZE * sizeof (short));
+		bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX *
+				sizeof (lstat_directory_entry_t));
+
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			bzero(lstat_control.counts[cpu],
+				sizeof (lstat_cpu_counts_t));
+			bzero(lstat_control.read_lock_counts[cpu],
+				sizeof (lstat_read_lock_cpu_counts_t));
+		}
+	}
+#ifdef NOTDEF
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+#endif
+	return 1;
+}
+
+static void
+release_control_space(void)
+{
+	/*
+	 * Called when either (1) allocation of kmem
+	 * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter.
+	 * Assume that all pointers have been initialized to zero,
+	 * i.e., nonzero pointers are valid addresses.
+	 */
+	int cpu;
+
+	if (lstat_control.hashtab) {
+		kfree(lstat_control.hashtab);
+		lstat_control.hashtab = NULL;
+	}
+
+	if (lstat_control.dir) {
+		vfree(lstat_control.dir);
+		lstat_control.dir = NULL;
+	}
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		if (lstat_control.counts[cpu]) {
+			vfree(lstat_control.counts[cpu]);
+			lstat_control.counts[cpu] = NULL;
+		}
+		if (lstat_control.read_lock_counts[cpu]) {
+			kfree(lstat_control.read_lock_counts[cpu]);
+			lstat_control.read_lock_counts[cpu] = NULL;
+		}
+	}
+}
+
+int
+get_lockmeter_info_size(void)
+{
+	return sizeof (lstat_user_request_t)
+		+ num_online_cpus() * sizeof (lstat_cpu_counts_t)
+		+ num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t)
+		+ (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t));
+}
+
+ssize_t
+get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index)
+{
+	lstat_user_request_t req;
+	struct timeval tv;
+	ssize_t next_ret_bcount;
+	ssize_t actual_ret_bcount = 0;
+	int cpu;
+
+	*last_index = 0;	/* a one-shot read */
+
+	req.lstat_version = LSTAT_VERSION;
+	req.state = lstat_control.state;
+	req.maxcpus = num_online_cpus();
+	req.cycleval = CPU_CYCLE_FREQUENCY;
+#ifdef notyet
+	req.kernel_magic_addr = (void *) &_etext;
+	req.kernel_end_addr = (void *) &_etext;
+#endif
+	req.uts = system_utsname;
+	req.intervals = lstat_control.intervals;
+
+	req.first_started_time = lstat_control.first_started_time;
+	req.started_time = lstat_control.started_time;
+	req.started_cycles64 = lstat_control.started_cycles64;
+
+	req.next_free_dir_index = lstat_control.next_free_dir_index;
+	req.next_free_read_lock_index = lstat_control.next_free_read_lock_index;
+	req.dir_overflow = lstat_control.dir_overflow;
+	req.rwlock_overflow = lstat_control.rwlock_overflow;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		if (req.intervals == 0) {
+			/* mesasurement is off and no valid data present */
+			next_ret_bcount = sizeof (lstat_user_request_t);
+			req.enabled_cycles64 = 0;
+
+			if ((actual_ret_bcount + next_ret_bcount) > max_len)
+				return actual_ret_bcount;
+
+			copy_to_user(buffer, (void *) &req, next_ret_bcount);
+			actual_ret_bcount += next_ret_bcount;
+			return actual_ret_bcount;
+		} else {
+			/*
+			 * measurement is off but valid data present
+			 * fetch time info from lstat_control
+			 */
+			req.ending_time = lstat_control.ending_time;
+			req.ending_cycles64 = lstat_control.ending_cycles64;
+			req.enabled_cycles64 = lstat_control.enabled_cycles64;
+		}
+	} else {
+		/*
+		 * this must be a read while data active--use current time,
+		 * etc
+		 */
+		do_gettimeofday(&tv);
+		req.ending_time = tv.tv_sec;
+		req.ending_cycles64 = get_cycles64();
+		req.enabled_cycles64 = req.ending_cycles64 -
+			req.started_cycles64 + lstat_control.enabled_cycles64;
+	}
+
+	next_ret_bcount = sizeof (lstat_user_request_t);
+	if ((actual_ret_bcount + next_ret_bcount) > max_len)
+		return actual_ret_bcount;
+
+	copy_to_user(buffer, (void *) &req, next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	if (!lstat_control.counts[0])	/* not initialized? */
+		return actual_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if ((actual_ret_bcount + next_ret_bcount) > max_len)
+			return actual_ret_bcount;	/* leave early */
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.counts[cpu], next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	next_ret_bcount = LSTAT_MAX_STAT_INDEX *
+			sizeof (lstat_directory_entry_t);
+	if (((actual_ret_bcount + next_ret_bcount) > max_len)
+			|| !lstat_control.dir)
+		return actual_ret_bcount;	/* leave early */
+
+	copy_to_user(buffer + actual_ret_bcount, lstat_control.dir,
+			next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if (actual_ret_bcount + next_ret_bcount > max_len)
+			return actual_ret_bcount;
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.read_lock_counts[cpu],
+				next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	return actual_ret_bcount;
+}
+
+/*
+ *  Writing to the /proc lockmeter node enables or disables metering.
+ *  based upon the first byte of the "written" data.
+ *  The following values are defined:
+ *  LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement
+ *            subsequent calls just turn on measurement
+ *  LSTAT_OFF: turns off measurement
+ *  LSTAT_RESET: resets statistics
+ *  LSTAT_RELEASE: releases statistics storage
+ *
+ *  This allows one to accumulate statistics over several lockstat runs:
+ *
+ *  lockstat on
+ *  lockstat off
+ *  ...repeat above as desired...
+ *  lockstat get
+ *  ...now start a new set of measurements...
+ *  lockstat reset
+ *  lockstat on
+ *  ...
+ *
+ */
+ssize_t
+put_lockmeter_info(const char *buffer, size_t len)
+{
+	int error = 0;
+	int dirsize, countsize, read_lock_countsize, hashsize;
+	int cpu;
+	char put_char;
+	int i, read_lock_blocks;
+	unsigned long flags;
+	rwlock_t *lock_ptr;
+	struct timeval tv;
+
+	if (len <= 0)
+		return -EINVAL;
+
+	_raw_spin_lock(&lstat_control.control_lock);
+
+	get_user(put_char, buffer);
+	switch (put_char) {
+
+	case LSTAT_OFF:
+		if (lstat_control.state != LSTAT_OFF) {
+			/*
+			 * To avoid seeing read lock hold times in an
+			 * inconsisent state, we have to follow this protocol
+			 * to turn off statistics
+			 */
+			local_irq_save(flags);
+			/*
+			 * getting this lock will stop any read lock block
+			 * allocations
+			 */
+			_raw_spin_lock(&lstat_control.directory_lock);
+			/*
+			 * keep any more read lock blocks from being
+			 * allocated
+			 */
+			lstat_control.state = LSTAT_OFF;
+			/* record how may read lock blocks there are */
+			read_lock_blocks =
+				lstat_control.next_free_read_lock_index;
+			_raw_spin_unlock(&lstat_control.directory_lock);
+			/* now go through the list of read locks */
+			cpu = THIS_CPU_NUMBER;
+			for (i = 1; i < read_lock_blocks; i++) {
+				lock_ptr =
+				    (*lstat_control.read_lock_counts[cpu])[i].
+				    lock_ptr;
+				/* is this saved lock address still valid? */
+				if (GET_RWINDEX(lock_ptr) == i) {
+					/*
+					 * lock address appears to still be
+					 * valid because we only hold one lock
+					 * at a time, this can't cause a
+					 * deadlock unless this is a lock held
+					 * as part of the current system call
+					 * path. At the moment there
+					 * are no READ mode locks held to get
+					 * here from user space, so we solve
+					 * this by skipping locks held in
+					 * write mode.
+					 */
+					if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) {
+						PUT_RWINDEX(lock_ptr, 0);
+						continue;
+					}
+					/*
+					 * now we know there are no read
+					 * holders of this lock! stop
+					 * statistics collection for this
+					 * lock
+					 */
+					_raw_write_lock(lock_ptr);
+					PUT_RWINDEX(lock_ptr, 0);
+					_raw_write_unlock(lock_ptr);
+				}
+				/*
+				 * it may still be possible for the hold time
+				 * sum to be negative e.g. if a lock is
+				 * reallocated while "busy" we will have to fix
+				 * this up in the data reduction program.
+				 */
+			}
+			local_irq_restore(flags);
+			lstat_control.intervals++;
+			lstat_control.ending_cycles64 = get_cycles64();
+			lstat_control.enabled_cycles64 +=
+				lstat_control.ending_cycles64 -
+				lstat_control.started_cycles64;
+			do_gettimeofday(&tv);
+			lstat_control.ending_time = tv.tv_sec;
+			/*
+			 * don't deallocate the structures -- we may do a
+			 * lockstat on to add to the data that is already
+			 * there. Use LSTAT_RELEASE to release storage
+			 */
+		} else {
+			error = -EBUSY;	/* already OFF */
+		}
+		break;
+
+	case LSTAT_ON:
+		if (lstat_control.state == LSTAT_OFF) {
+#ifdef DEBUG_LOCKMETER
+			printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n",
+				THIS_CPU_NUMBER);
+#endif
+			lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+
+			dirsize = LSTAT_MAX_STAT_INDEX *
+					sizeof (lstat_directory_entry_t);
+			hashsize =
+				(1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+			countsize = sizeof (lstat_cpu_counts_t);
+			read_lock_countsize =
+				sizeof (lstat_read_lock_cpu_counts_t);
+#ifdef DEBUG_LOCKMETER
+			printk(" dirsize:%d", dirsize);
+			printk(" hashsize:%d", hashsize);
+			printk(" countsize:%d", countsize);
+			printk(" read_lock_countsize:%d\n",
+				read_lock_countsize);
+#endif
+#ifdef DEBUG_LOCKMETER
+			{
+				int secs;
+				unsigned long cycles;
+				uint64_t cycles64;
+
+				do_gettimeofday(&tv);
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles();
+				cycles64 = get_cycles64();
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles() - cycles;
+				cycles64 = get_cycles64() - cycles;
+				printk("lockmeter: cycleFrequency:%d "
+					"cycles:%d cycles64:%d\n",
+					CPU_CYCLE_FREQUENCY, cycles, cycles64);
+			}
+#endif
+
+			/*
+			 * if this is the first call, allocate storage and
+			 * initialize
+			 */
+			if (!lstat_control.hashtab) {
+
+				spin_lock_init(&lstat_control.directory_lock);
+
+				/* guarantee all pointers at zero */
+				init_control_space();
+
+				lstat_control.hashtab =
+				    kmalloc(hashsize, GFP_KERNEL);
+				if (!lstat_control.hashtab) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of hashtab\n");
+#endif
+				}
+				lstat_control.dir = vmalloc(dirsize);
+				if (!lstat_control.dir) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of dir\n");
+#endif
+				}
+
+				for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+					lstat_control.counts[cpu] =
+						vmalloc(countsize);
+					if (!lstat_control.counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error vmalloc of "
+							"counts[%d]\n", cpu);
+#endif
+					}
+					lstat_control.read_lock_counts[cpu] =
+						(lstat_read_lock_cpu_counts_t *)
+						kmalloc(read_lock_countsize,
+							GFP_KERNEL);
+					if (!lstat_control.
+							read_lock_counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error kmalloc of "
+						  "read_lock_counts[%d]\n",
+							cpu);
+#endif
+					}
+				}
+			}
+
+			if (error) {
+				/*
+				 * One or more kmalloc failures -- free
+				 * everything
+				 */
+				release_control_space();
+			} else {
+
+				if (!reset_lstat_data()) {
+					error = -EINVAL;
+					break;
+				};
+
+				/*
+				 * record starting and ending times and the
+				 * like
+				 */
+				if (lstat_control.intervals == 0) {
+					do_gettimeofday(&tv);
+					lstat_control.first_started_time =
+						tv.tv_sec;
+				}
+				lstat_control.started_cycles64 = get_cycles64();
+				do_gettimeofday(&tv);
+				lstat_control.started_time = tv.tv_sec;
+
+				lstat_control.state = LSTAT_ON;
+			}
+		} else {
+			error = -EBUSY;	/* already ON */
+		}
+		break;
+
+	case LSTAT_RESET:
+		if (lstat_control.state == LSTAT_OFF) {
+			if (!reset_lstat_data())
+				error = -EINVAL;
+		} else {
+			error = -EBUSY;	/* still on; can't reset */
+		}
+		break;
+
+	case LSTAT_RELEASE:
+		if (lstat_control.state == LSTAT_OFF) {
+			release_control_space();
+			lstat_control.intervals = 0;
+			lstat_control.enabled_cycles64 = 0;
+		} else {
+			error = -EBUSY;
+		}
+		break;
+
+	default:
+		error = -EINVAL;
+	}			/* switch */
+
+	_raw_spin_unlock(&lstat_control.control_lock);
+	return error ? error : len;
+}
+
+#ifdef USER_MODE_TESTING
+/* following used for user mode testing */
+void
+lockmeter_init()
+{
+	int dirsize, hashsize, countsize, read_lock_countsize, cpu;
+
+	printf("lstat_control is at %x size=%d\n", &lstat_control,
+		sizeof (lstat_control));
+	printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t));
+	lstat_control.state = LSTAT_ON;
+
+	lstat_control.directory_lock = SPIN_LOCK_UNLOCKED;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+
+	dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t);
+	hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+	countsize = sizeof (lstat_cpu_counts_t);
+	read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t);
+
+	lstat_control.hashtab = (ushort *) malloc(hashsize);
+
+	if (lstat_control.hashtab == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n",
+			__LINE__);
+		exit(0);
+	}
+
+	lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize);
+
+	if (lstat_control.dir == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n", cpu,
+			__LINE__);
+		exit(0);
+	}
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		int j, k;
+		j = (int) (lstat_control.counts[cpu] =
+			   (lstat_cpu_counts_t *) malloc(countsize));
+		k = (int) (lstat_control.read_lock_counts[cpu] =
+			   (lstat_read_lock_cpu_counts_t *)
+			   malloc(read_lock_countsize));
+		if (j * k == 0) {
+			printf("malloc failure for cpu=%d at line %d in "
+				"lockmeter.c\n", cpu, __LINE__);
+			exit(0);
+		}
+	}
+
+	memset(lstat_control.hashtab, 0, hashsize);
+	memset(lstat_control.dir, 0, dirsize);
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		memset(lstat_control.counts[cpu], 0, countsize);
+		memset(lstat_control.read_lock_counts[cpu], 0,
+			read_lock_countsize);
+	}
+}
+
+asm(" \
+.align	4 \
+.globl	__write_lock_failed \
+__write_lock_failed: \
+	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax) \
+1:	cmpl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jne	1b \
+\
+	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jnz	__write_lock_failed \
+	ret \
+\
+\
+.align	4 \
+.globl	__read_lock_failed \
+__read_lock_failed: \
+	lock ; incl	(%eax) \
+1:	cmpl	$1,(%eax) \
+	js	1b \
+\
+	lock ; decl	(%eax) \
+	js	__read_lock_failed \
+	ret \
+");
+#endif
+
+EXPORT_SYMBOL(_metered_spin_lock);
+EXPORT_SYMBOL(_metered_spin_unlock);
+EXPORT_SYMBOL(_metered_spin_trylock);
+EXPORT_SYMBOL(_metered_read_lock);
+EXPORT_SYMBOL(_metered_read_unlock);
+EXPORT_SYMBOL(_metered_write_lock);
+EXPORT_SYMBOL(_metered_write_unlock);
--- diff/kernel/stop_machine.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/stop_machine.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,200 @@
+#include <linux/stop_machine.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/syscalls.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+/* Since we effect priority and affinity (both of which are visible
+ * to, and settable by outside processes) we do indirection via a
+ * kthread. */
+
+/* Thread to stop each CPU in user context. */
+enum stopmachine_state {
+	STOPMACHINE_WAIT,
+	STOPMACHINE_PREPARE,
+	STOPMACHINE_DISABLE_IRQ,
+	STOPMACHINE_EXIT,
+};
+
+static enum stopmachine_state stopmachine_state;
+static unsigned int stopmachine_num_threads;
+static atomic_t stopmachine_thread_ack;
+static DECLARE_MUTEX(stopmachine_mutex);
+
+static int stopmachine(void *cpu)
+{
+	int irqs_disabled = 0;
+	int prepared = 0;
+
+	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
+
+	/* Ack: we are alive */
+	mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
+	atomic_inc(&stopmachine_thread_ack);
+
+	/* Simple state machine */
+	while (stopmachine_state != STOPMACHINE_EXIT) {
+		if (stopmachine_state == STOPMACHINE_DISABLE_IRQ
+		    && !irqs_disabled) {
+			local_irq_disable();
+			irqs_disabled = 1;
+			/* Ack: irqs disabled. */
+			mb(); /* Must read state first. */
+			atomic_inc(&stopmachine_thread_ack);
+		} else if (stopmachine_state == STOPMACHINE_PREPARE
+			   && !prepared) {
+			/* Everyone is in place, hold CPU. */
+			preempt_disable();
+			prepared = 1;
+			mb(); /* Must read state first. */
+			atomic_inc(&stopmachine_thread_ack);
+		}
+		cpu_relax();
+	}
+
+	/* Ack: we are exiting. */
+	mb(); /* Must read state first. */
+	atomic_inc(&stopmachine_thread_ack);
+
+	if (irqs_disabled)
+		local_irq_enable();
+	if (prepared)
+		preempt_enable();
+
+	return 0;
+}
+
+/* Change the thread state */
+static void stopmachine_set_state(enum stopmachine_state state)
+{
+	atomic_set(&stopmachine_thread_ack, 0);
+	wmb();
+	stopmachine_state = state;
+	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)
+		cpu_relax();
+}
+
+static int stop_machine(void)
+{
+	int i, ret = 0;
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+
+	/* One high-prio thread per cpu.  We'll do this one. */
+	sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);
+
+	atomic_set(&stopmachine_thread_ack, 0);
+	stopmachine_num_threads = 0;
+	stopmachine_state = STOPMACHINE_WAIT;
+
+	for_each_online_cpu(i) {
+		if (i == smp_processor_id())
+			continue;
+		ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
+		if (ret < 0)
+			break;
+		stopmachine_num_threads++;
+	}
+
+	/* Wait for them all to come to life. */
+	while (atomic_read(&stopmachine_thread_ack) != stopmachine_num_threads)
+		yield();
+
+	/* If some failed, kill them all. */
+	if (ret < 0) {
+		stopmachine_set_state(STOPMACHINE_EXIT);
+		up(&stopmachine_mutex);
+		return ret;
+	}
+
+	/* Don't schedule us away at this point, please. */
+	local_irq_disable();
+
+	/* Now they are all started, make them hold the CPUs, ready. */
+	stopmachine_set_state(STOPMACHINE_PREPARE);
+
+	/* Make them disable irqs. */
+	stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
+
+	return 0;
+}
+
+static void restart_machine(void)
+{
+	stopmachine_set_state(STOPMACHINE_EXIT);
+	local_irq_enable();
+}
+
+struct stop_machine_data
+{
+	int (*fn)(void *);
+	void *data;
+	struct completion done;
+};
+
+static int do_stop(void *_smdata)
+{
+	struct stop_machine_data *smdata = _smdata;
+	int ret;
+
+	ret = stop_machine();
+	if (ret == 0) {
+		ret = smdata->fn(smdata->data);
+		restart_machine();
+	}
+
+	/* We're done: you can kthread_stop us now */
+	complete(&smdata->done);
+
+	/* Wait for kthread_stop */
+	while (!signal_pending(current)) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	return ret;
+}
+
+struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
+				       unsigned int cpu)
+{
+	struct stop_machine_data smdata;
+	struct task_struct *p;
+
+	smdata.fn = fn;
+	smdata.data = data;
+	init_completion(&smdata.done);
+
+	down(&stopmachine_mutex);
+
+	/* If they don't care which CPU fn runs on, bind to any online one. */
+	if (cpu == NR_CPUS)
+		cpu = smp_processor_id();
+
+	p = kthread_create(do_stop, &smdata, "kstopmachine");
+	if (!IS_ERR(p)) {
+		kthread_bind(p, cpu);
+		wake_up_process(p);
+		wait_for_completion(&smdata.done);
+	}
+	up(&stopmachine_mutex);
+	return p;
+}
+
+int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
+{
+	struct task_struct *p;
+	int ret;
+
+	/* No CPUs can come up or down during this. */
+	lock_cpu_hotplug();
+	p = __stop_machine_run(fn, data, cpu);
+	if (!IS_ERR(p))
+		ret = kthread_stop(p);
+	else
+		ret = PTR_ERR(p);
+	unlock_cpu_hotplug();
+
+	return ret;
+}
--- diff/mm/usercopy.c	1970-01-01 01:00:00.000000000 +0100
+++ source/mm/usercopy.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,291 @@
+/*
+ * linux/mm/usercopy.c
+ *
+ * (C) Copyright 2003 Ingo Molnar
+ *
+ * Generic implementation of all the user-VM access functions, without
+ * relying on being able to access the VM directly.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/atomic_kmap.h>
+
+/*
+ * Get kernel address of the user page and pin it.
+ */
+static inline struct page *pin_page(unsigned long addr, int write)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+	struct page *page = NULL;
+	int ret;
+
+	/*
+	 * Do a quick atomic lookup first - this is the fastpath.
+	 */
+retry:
+	page = follow_page(mm, addr, write);
+	if (likely(page != NULL)) {
+		if (!PageReserved(page))
+			get_page(page);
+		return page;
+	}
+
+	/*
+	 * No luck - bad address or need to fault in the page:
+	 */
+
+	/* Release the lock so get_user_pages can sleep */
+	spin_unlock(&mm->page_table_lock);
+
+	/*
+	 * In the context of filemap_copy_from_user(), we are not allowed
+	 * to sleep.  We must fail this usercopy attempt and allow
+	 * filemap_copy_from_user() to recover: drop its atomic kmap and use
+	 * a sleeping kmap instead.
+	 */
+	if (in_atomic()) {
+		spin_lock(&mm->page_table_lock);
+		return NULL;
+	}
+
+	down_read(&mm->mmap_sem);
+	ret = get_user_pages(current, mm, addr, 1, write, 0, NULL, NULL);
+	up_read(&mm->mmap_sem);
+	spin_lock(&mm->page_table_lock);
+
+	if (ret <= 0)
+		return NULL;
+
+	/*
+	 * Go try the follow_page again.
+	 */
+	goto retry;
+}
+
+static inline void unpin_page(struct page *page)
+{
+	put_page(page);
+}
+
+/*
+ * Access another process' address space.
+ * Source/target buffer must be kernel space,
+ * Do not walk the page table directly, use get_user_pages
+ */
+static int rw_vm(unsigned long addr, void *buf, int len, int write)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+
+	if (!len)
+		return 0;
+
+	spin_lock(&mm->page_table_lock);
+
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		struct page *page = NULL;
+		int bytes, offset;
+		void *maddr;
+
+		page = pin_page(addr, write);
+		if (!page)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap_atomic(page, KM_USER_COPY);
+
+#define HANDLE_TYPE(type) \
+	case sizeof(type): *(type *)(maddr+offset) = *(type *)(buf); break;
+
+		if (write) {
+			switch (bytes) {
+			HANDLE_TYPE(char);
+			HANDLE_TYPE(int);
+			HANDLE_TYPE(long long);
+			default:
+				memcpy(maddr + offset, buf, bytes);
+			}
+		} else {
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(type) \
+	case sizeof(type): *(type *)(buf) = *(type *)(maddr+offset); break;
+			switch (bytes) {
+			HANDLE_TYPE(char);
+			HANDLE_TYPE(int);
+			HANDLE_TYPE(long long);
+			default:
+				memcpy(buf, maddr + offset, bytes);
+			}
+#undef HANDLE_TYPE
+		}
+		kunmap_atomic(maddr, KM_USER_COPY);
+		unpin_page(page);
+		len -= bytes;
+		buf += bytes;
+		addr += bytes;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	return len;
+}
+
+static int str_vm(unsigned long addr, void *buf0, int len, int copy)
+{
+	struct mm_struct *mm = current->mm ? : &init_mm;
+	struct page *page;
+	void *buf = buf0;
+
+	if (!len)
+		return len;
+
+	spin_lock(&mm->page_table_lock);
+
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, offset, left, copied;
+		char *maddr;
+
+		page = pin_page(addr, copy == 2);
+		if (!page) {
+			spin_unlock(&mm->page_table_lock);
+			return -EFAULT;
+		}
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap_atomic(page, KM_USER_COPY);
+		if (copy == 2) {
+			memset(maddr + offset, 0, bytes);
+			copied = bytes;
+			left = 0;
+		} else if (copy == 1) {
+			left = strncpy_count(buf, maddr + offset, bytes);
+			copied = bytes - left;
+		} else {
+			copied = strnlen(maddr + offset, bytes);
+			left = bytes - copied;
+		}
+		BUG_ON(bytes < 0 || copied < 0);
+		kunmap_atomic(maddr, KM_USER_COPY);
+		unpin_page(page);
+		len -= copied;
+		buf += copied;
+		addr += copied;
+		if (left)
+			break;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	return len;
+}
+
+/*
+ * Copies memory from userspace (ptr) into kernelspace (val).
+ *
+ * returns # of bytes not copied.
+ */
+int get_user_size(unsigned int size, void *val, const void *ptr)
+{
+	int ret;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
+		ret = __direct_copy_from_user(val, ptr, size);
+	else
+		ret = rw_vm((unsigned long)ptr, val, size, 0);
+	if (ret)
+		/*
+		 * Zero the rest:
+		 */
+		memset(val + size - ret, 0, ret);
+	return ret;
+}
+
+/*
+ * Copies memory from kernelspace (val) into userspace (ptr).
+ *
+ * returns # of bytes not copied.
+ */
+int put_user_size(unsigned int size, const void *val, void *ptr)
+{
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS)))
+		return __direct_copy_to_user(ptr, val, size);
+	else
+		return rw_vm((unsigned long)ptr, (void *)val, size, 1);
+}
+
+int copy_str_fromuser_size(unsigned int size, void *val, const void *ptr)
+{
+	int copied, left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		left = strncpy_count(val, ptr, size);
+		copied = size - left;
+		BUG_ON(copied < 0);
+
+		return copied;
+	}
+	left = str_vm((unsigned long)ptr, val, size, 1);
+	if (left < 0)
+		return left;
+	copied = size - left;
+	BUG_ON(copied < 0);
+
+	return copied;
+}
+
+int strlen_fromuser_size(unsigned int size, const void *ptr)
+{
+	int copied, left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		copied = strnlen(ptr, size) + 1;
+		BUG_ON(copied < 0);
+
+		return copied;
+	}
+	left = str_vm((unsigned long)ptr, NULL, size, 0);
+	if (left < 0)
+		return 0;
+	copied = size - left + 1;
+	BUG_ON(copied < 0);
+
+	return copied;
+}
+
+int zero_user_size(unsigned int size, void *ptr)
+{
+	int left;
+
+	if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
+		memset(ptr, 0, size);
+		return 0;
+	}
+	left = str_vm((unsigned long)ptr, NULL, size, 2);
+	if (left < 0)
+		return size;
+	return left;
+}
+
+EXPORT_SYMBOL(get_user_size);
+EXPORT_SYMBOL(put_user_size);
+EXPORT_SYMBOL(zero_user_size);
+EXPORT_SYMBOL(copy_str_fromuser_size);
+EXPORT_SYMBOL(strlen_fromuser_size);
+
--- diff/net/core/netpoll.c	1970-01-01 01:00:00.000000000 +0100
+++ source/net/core/netpoll.c	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,651 @@
+/*
+ * Common framework for low-level network console, dump, and debugger code
+ *
+ * Sep 8 2003  Matt Mackall <mpm@selenic.com>
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/string.h>
+#include <linux/inetdevice.h>
+#include <linux/inet.h>
+#include <linux/interrupt.h>
+#include <linux/netpoll.h>
+#include <linux/sched.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+/*
+ * We maintain a small pool of fully-sized skbs, to make sure the
+ * message gets out even in extreme OOM situations.
+ */
+
+#define MAX_SKBS 32
+#define MAX_UDP_CHUNK 1460
+
+static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED;
+static int nr_skbs;
+static struct sk_buff *skbs;
+
+static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(rx_list);
+
+static int trapped;
+
+#define MAX_SKB_SIZE \
+		(MAX_UDP_CHUNK + sizeof(struct udphdr) + \
+				sizeof(struct iphdr) + sizeof(struct ethhdr))
+
+static void zap_completion_queue(void);
+
+static int checksum_udp(struct sk_buff *skb, struct udphdr *uh,
+			     unsigned short ulen, u32 saddr, u32 daddr)
+{
+	if (uh->check == 0)
+		return 0;
+
+	if (skb->ip_summed == CHECKSUM_HW)
+		return csum_tcpudp_magic(
+			saddr, daddr, ulen, IPPROTO_UDP, skb->csum);
+
+	skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+
+	return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+}
+
+void netpoll_poll(struct netpoll *np)
+{
+	int budget = 1;
+
+	if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
+		return;
+
+	/* Process pending work on NIC */
+	np->dev->poll_controller(np->dev);
+
+	/* If scheduling is stopped, tickle NAPI bits */
+	if(trapped && np->dev->poll &&
+	   test_bit(__LINK_STATE_RX_SCHED, &np->dev->state))
+		np->dev->poll(np->dev, &budget);
+	zap_completion_queue();
+}
+
+static void refill_skbs(void)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&skb_list_lock, flags);
+	while (nr_skbs < MAX_SKBS) {
+		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
+		if (!skb)
+			break;
+
+		skb->next = skbs;
+		skbs = skb;
+		nr_skbs++;
+	}
+	spin_unlock_irqrestore(&skb_list_lock, flags);
+}
+
+static void zap_completion_queue(void)
+{
+	unsigned long flags;
+	struct softnet_data *sd = &get_cpu_var(softnet_data);
+
+	if (sd->completion_queue) {
+		struct sk_buff *clist;
+
+		local_irq_save(flags);
+		clist = sd->completion_queue;
+		sd->completion_queue = NULL;
+		local_irq_restore(flags);
+
+		while (clist != NULL) {
+			struct sk_buff *skb = clist;
+			clist = clist->next;
+			__kfree_skb(skb);
+		}
+	}
+
+	put_cpu_var(softnet_data);
+}
+
+static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve)
+{
+	int once = 1, count = 0;
+	unsigned long flags;
+	struct sk_buff *skb = NULL;
+
+	zap_completion_queue();
+repeat:
+	if (nr_skbs < MAX_SKBS)
+		refill_skbs();
+
+	skb = alloc_skb(len, GFP_ATOMIC);
+
+	if (!skb) {
+		spin_lock_irqsave(&skb_list_lock, flags);
+		skb = skbs;
+		if (skb)
+			skbs = skb->next;
+		skb->next = NULL;
+		nr_skbs--;
+		spin_unlock_irqrestore(&skb_list_lock, flags);
+	}
+
+	if(!skb) {
+		count++;
+		if (once && (count == 1000000)) {
+			printk("out of netpoll skbs!\n");
+			once = 0;
+		}
+		netpoll_poll(np);
+		goto repeat;
+	}
+
+	atomic_set(&skb->users, 1);
+	skb_reserve(skb, reserve);
+	return skb;
+}
+
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+{
+	int status;
+
+repeat:
+	if(!np || !np->dev || !netif_running(np->dev)) {
+		__kfree_skb(skb);
+		return;
+	}
+
+	spin_lock(&np->dev->xmit_lock);
+	np->dev->xmit_lock_owner = smp_processor_id();
+
+	if (netif_queue_stopped(np->dev)) {
+		np->dev->xmit_lock_owner = -1;
+		spin_unlock(&np->dev->xmit_lock);
+
+		netpoll_poll(np);
+		goto repeat;
+	}
+
+	status = np->dev->hard_start_xmit(skb, np->dev);
+	np->dev->xmit_lock_owner = -1;
+	spin_unlock(&np->dev->xmit_lock);
+
+	/* transmit busy */
+	if(status)
+		goto repeat;
+}
+
+void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+{
+	int total_len, eth_len, ip_len, udp_len;
+	struct sk_buff *skb;
+	struct udphdr *udph;
+	struct iphdr *iph;
+	struct ethhdr *eth;
+
+	udp_len = len + sizeof(*udph);
+	ip_len = eth_len = udp_len + sizeof(*iph);
+	total_len = eth_len + ETH_HLEN;
+
+	skb = find_skb(np, total_len, total_len - len);
+	if (!skb)
+		return;
+
+	memcpy(skb->data, msg, len);
+	skb->len += len;
+
+	udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+	udph->source = htons(np->local_port);
+	udph->dest = htons(np->remote_port);
+	udph->len = htons(udp_len);
+	udph->check = 0;
+
+	iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+
+	iph->version  = 4;
+	iph->ihl      = 5;
+	iph->tos      = 0;
+	iph->tot_len  = htons(ip_len);
+	iph->id       = 0;
+	iph->frag_off = 0;
+	iph->ttl      = 64;
+	iph->protocol = IPPROTO_UDP;
+	iph->check    = 0;
+	iph->saddr    = htonl(np->local_ip);
+	iph->daddr    = htonl(np->remote_ip);
+	iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	eth->h_proto = htons(ETH_P_IP);
+	memcpy(eth->h_source, np->local_mac, 6);
+	memcpy(eth->h_dest, np->remote_mac, 6);
+
+	netpoll_send_skb(np, skb);
+}
+
+static void arp_reply(struct sk_buff *skb)
+{
+	struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr;
+	struct arphdr *arp;
+	unsigned char *arp_ptr, *sha, *tha;
+	int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
+	u32 sip, tip;
+	struct sk_buff *send_skb;
+	unsigned long flags;
+	struct list_head *p;
+	struct netpoll *np = 0;
+
+	spin_lock_irqsave(&rx_list_lock, flags);
+	list_for_each(p, &rx_list) {
+		np = list_entry(p, struct netpoll, rx_list);
+		if ( np->dev == skb->dev )
+			break;
+		np = 0;
+	}
+	spin_unlock_irqrestore(&rx_list_lock, flags);
+
+	if (!np) return;
+
+	/* No arp on this interface */
+	if (!in_dev || skb->dev->flags & IFF_NOARP)
+		return;
+
+	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+				 (2 * skb->dev->addr_len) +
+				 (2 * sizeof(u32)))))
+		return;
+
+	skb->h.raw = skb->nh.raw = skb->data;
+	arp = skb->nh.arph;
+
+	if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+	     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+	    arp->ar_pro != htons(ETH_P_IP) ||
+	    arp->ar_op != htons(ARPOP_REQUEST))
+		return;
+
+	arp_ptr= (unsigned char *)(arp+1);
+	sha = arp_ptr;
+	arp_ptr += skb->dev->addr_len;
+	memcpy(&sip, arp_ptr, 4);
+	arp_ptr += 4;
+	tha = arp_ptr;
+	arp_ptr += skb->dev->addr_len;
+	memcpy(&tip, arp_ptr, 4);
+
+	/* Should we ignore arp? */
+	if (tip != in_dev->ifa_list->ifa_address ||
+	    LOOPBACK(tip) || MULTICAST(tip))
+		return;
+
+
+	size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4);
+	send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
+			    LL_RESERVED_SPACE(np->dev));
+
+	if (!send_skb)
+		return;
+
+	send_skb->nh.raw = send_skb->data;
+	arp = (struct arphdr *) skb_put(send_skb, size);
+	send_skb->dev = skb->dev;
+	send_skb->protocol = htons(ETH_P_ARP);
+
+	/* Fill the device header for the ARP frame */
+
+	if (np->dev->hard_header &&
+	    np->dev->hard_header(send_skb, skb->dev, ptype,
+				       np->remote_mac, np->local_mac,
+				       send_skb->len) < 0) {
+		kfree_skb(send_skb);
+		return;
+	}
+
+	/*
+	 * Fill out the arp protocol part.
+	 *
+	 * we only support ethernet device type,
+	 * which (according to RFC 1390) should always equal 1 (Ethernet).
+	 */
+
+	arp->ar_hrd = htons(np->dev->type);
+	arp->ar_pro = htons(ETH_P_IP);
+	arp->ar_hln = np->dev->addr_len;
+	arp->ar_pln = 4;
+	arp->ar_op = htons(type);
+
+	arp_ptr=(unsigned char *)(arp + 1);
+	memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+	arp_ptr += np->dev->addr_len;
+	memcpy(arp_ptr, &tip, 4);
+	arp_ptr += 4;
+	memcpy(arp_ptr, np->local_mac, np->dev->addr_len);
+	arp_ptr += np->dev->addr_len;
+	memcpy(arp_ptr, &sip, 4);
+
+	netpoll_send_skb(np, send_skb);
+}
+
+int netpoll_rx(struct sk_buff *skb)
+{
+	int proto, len, ulen;
+	struct iphdr *iph;
+	struct udphdr *uh;
+	struct netpoll *np;
+	struct list_head *p;
+	unsigned long flags;
+
+	if (skb->dev->type != ARPHRD_ETHER)
+		goto out;
+
+	/* check if netpoll clients need ARP */
+	if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) {
+		arp_reply(skb);
+		return 1;
+	}
+
+	proto = ntohs(skb->mac.ethernet->h_proto);
+	if (proto != ETH_P_IP)
+		goto out;
+	if (skb->pkt_type == PACKET_OTHERHOST)
+		goto out;
+	if (skb_shared(skb))
+		goto out;
+
+	iph = (struct iphdr *)skb->data;
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto out;
+	if (iph->ihl < 5 || iph->version != 4)
+		goto out;
+	if (!pskb_may_pull(skb, iph->ihl*4))
+		goto out;
+	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+		goto out;
+
+	len = ntohs(iph->tot_len);
+	if (skb->len < len || len < iph->ihl*4)
+		goto out;
+
+	if (iph->protocol != IPPROTO_UDP)
+		goto out;
+
+	len -= iph->ihl*4;
+	uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
+	ulen = ntohs(uh->len);
+
+	if (ulen != len)
+		goto out;
+	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0)
+		goto out;
+
+	spin_lock_irqsave(&rx_list_lock, flags);
+	list_for_each(p, &rx_list) {
+		np = list_entry(p, struct netpoll, rx_list);
+		if (np->dev && np->dev != skb->dev)
+			continue;
+		if (np->local_ip && np->local_ip != ntohl(iph->daddr))
+			continue;
+		if (np->remote_ip && np->remote_ip != ntohl(iph->saddr))
+			continue;
+		if (np->local_port && np->local_port != ntohs(uh->dest))
+			continue;
+
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+
+		if (np->rx_hook)
+			np->rx_hook(np, ntohs(uh->source),
+				    (char *)(uh+1),
+				    ulen - sizeof(struct udphdr));
+
+		return 1;
+	}
+	spin_unlock_irqrestore(&rx_list_lock, flags);
+
+out:
+	return trapped;
+}
+
+int netpoll_parse_options(struct netpoll *np, char *opt)
+{
+	char *cur=opt, *delim;
+
+	if(*cur != '@') {
+		if ((delim = strchr(cur, '@')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->local_port=simple_strtol(cur, 0, 10);
+		cur=delim;
+	}
+	cur++;
+	printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port);
+
+	if(*cur != '/') {
+		if ((delim = strchr(cur, '/')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->local_ip=ntohl(in_aton(cur));
+		cur=delim;
+
+		printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->local_ip));
+	}
+	cur++;
+
+	if ( *cur != ',') {
+		/* parse out dev name */
+		if ((delim = strchr(cur, ',')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		strlcpy(np->dev_name, cur, sizeof(np->dev_name));
+		cur=delim;
+	}
+	cur++;
+
+	printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name);
+
+	if ( *cur != '@' ) {
+		/* dst port */
+		if ((delim = strchr(cur, '@')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_port=simple_strtol(cur, 0, 10);
+		cur=delim;
+	}
+	cur++;
+	printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port);
+
+	/* dst ip */
+	if ((delim = strchr(cur, '/')) == NULL)
+		goto parse_failed;
+	*delim=0;
+	np->remote_ip=ntohl(in_aton(cur));
+	cur=delim+1;
+
+	printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->remote_ip));
+
+	if( *cur != 0 )
+	{
+		/* MAC address */
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[0]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[1]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[2]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[3]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		if ((delim = strchr(cur, ':')) == NULL)
+			goto parse_failed;
+		*delim=0;
+		np->remote_mac[4]=simple_strtol(cur, 0, 16);
+		cur=delim+1;
+		np->remote_mac[5]=simple_strtol(cur, 0, 16);
+	}
+
+	printk(KERN_INFO "%s: remote ethernet address "
+	       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       np->name,
+	       np->remote_mac[0],
+	       np->remote_mac[1],
+	       np->remote_mac[2],
+	       np->remote_mac[3],
+	       np->remote_mac[4],
+	       np->remote_mac[5]);
+
+	return 0;
+
+ parse_failed:
+	printk(KERN_INFO "%s: couldn't parse config at %s!\n",
+	       np->name, cur);
+	return -1;
+}
+
+int netpoll_setup(struct netpoll *np)
+{
+	struct net_device *ndev = NULL;
+	struct in_device *in_dev;
+
+	if (np->dev_name)
+		ndev = dev_get_by_name(np->dev_name);
+	if (!ndev) {
+		printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
+		       np->name, np->dev_name);
+		return -1;
+	}
+	if (!ndev->poll_controller) {
+		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
+		       np->name, np->dev_name);
+		goto release;
+	}
+
+	if (!(ndev->flags & IFF_UP)) {
+		unsigned short oflags;
+		unsigned long atmost, atleast;
+
+		printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
+		       np->name, np->dev_name);
+
+		oflags = ndev->flags;
+
+		rtnl_shlock();
+		if (dev_change_flags(ndev, oflags | IFF_UP) < 0) {
+			printk(KERN_ERR "%s: failed to open %s\n",
+			       np->name, np->dev_name);
+			rtnl_shunlock();
+			goto release;
+		}
+		rtnl_shunlock();
+
+		atleast = jiffies + HZ/10;
+ 		atmost = jiffies + 10*HZ;
+		while (!netif_carrier_ok(ndev)) {
+			if (time_after(jiffies, atmost)) {
+				printk(KERN_NOTICE
+				       "%s: timeout waiting for carrier\n",
+				       np->name);
+				break;
+			}
+			cond_resched();
+		}
+
+		if (time_before(jiffies, atleast)) {
+			printk(KERN_NOTICE "%s: carrier detect appears flaky,"
+			       " waiting 10 seconds\n",
+			       np->name);
+			while (time_before(jiffies, atmost))
+				cond_resched();
+		}
+	}
+
+	if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr)
+		memcpy(np->local_mac, ndev->dev_addr, 6);
+
+	if (!np->local_ip) {
+		in_dev = in_dev_get(ndev);
+
+		if (!in_dev) {
+			printk(KERN_ERR "%s: no IP address for %s, aborting\n",
+			       np->name, np->dev_name);
+			goto release;
+		}
+
+		np->local_ip = ntohl(in_dev->ifa_list->ifa_local);
+		in_dev_put(in_dev);
+		printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
+		       np->name, HIPQUAD(np->local_ip));
+	}
+
+	np->dev = ndev;
+
+	if(np->rx_hook) {
+		unsigned long flags;
+
+#ifdef CONFIG_NETPOLL_RX
+		np->dev->netpoll_rx = 1;
+#endif
+
+		spin_lock_irqsave(&rx_list_lock, flags);
+		list_add(&np->rx_list, &rx_list);
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+	}
+
+	return 0;
+ release:
+	dev_put(ndev);
+	return -1;
+}
+
+void netpoll_cleanup(struct netpoll *np)
+{
+	if(np->rx_hook) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&rx_list_lock, flags);
+		list_del(&np->rx_list);
+#ifdef CONFIG_NETPOLL_RX
+		np->dev->netpoll_rx = 0;
+#endif
+		spin_unlock_irqrestore(&rx_list_lock, flags);
+	}
+
+	dev_put(np->dev);
+	np->dev = 0;
+}
+
+int netpoll_trap()
+{
+	return trapped;
+}
+
+void netpoll_set_trap(int trap)
+{
+	trapped = trap;
+}
+
+EXPORT_SYMBOL(netpoll_set_trap);
+EXPORT_SYMBOL(netpoll_trap);
+EXPORT_SYMBOL(netpoll_parse_options);
+EXPORT_SYMBOL(netpoll_setup);
+EXPORT_SYMBOL(netpoll_cleanup);
+EXPORT_SYMBOL(netpoll_send_skb);
+EXPORT_SYMBOL(netpoll_send_udp);
+EXPORT_SYMBOL(netpoll_poll);
--- diff/scripts/gcc-version.sh	1970-01-01 01:00:00.000000000 +0100
+++ source/scripts/gcc-version.sh	2004-02-18 09:04:03.000000000 +0000
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# gcc-version gcc-command
+#
+# Prints the gcc version of `gcc-command' in a canonical 4-digit form
+# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc.
+#
+
+compiler="$*"
+
+MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
+MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
+printf "%02d%02d\\n" $MAJOR $MINOR
+
--- diff/drivers/input/misc/gsc_ps2.c	2003-07-22 18:54:27.000000000 +0100
+++ source/drivers/input/misc/gsc_ps2.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,712 +0,0 @@
-/*
- * drivers/input/misc/gsc_ps2.c
- *
- * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
- * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
- *
- * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
- * 	Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
- *	Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
- *	Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
- *	Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
- *
- * HP PS/2 Keyboard, found in PA/RISC Workstations
- * very similar to AT keyboards, but without i8042
- *
- * 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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * 
- * STATUS:
- * 11/09: lc: Only basic keyboard is supported, mouse still needs to be done.
- * 11/12: tv: switching iomapping; cleaning code; improving module stuff.
- * 11/13: lc & tv: leds aren't working. auto_repeat/meta are. Generaly good behavior.
- * 11/15: tv: 2AM: leds ARE working !
- * 11/16: tv: 3AM: escaped keycodes emulation *handled*, some keycodes are
- *	  still deliberately ignored (18), what are they used for ?
- * 11/21: lc: mouse is now working
- * 11/29: tv: first try for error handling in init sequence
- *
- * TODO:
- * Error handling in init sequence
- * SysRq handling
- * Pause key handling
- * Intellimouse & other rodents handling (at least send an error when
- * such a mouse is plugged : it will totally fault)
- * Mouse: set scaling / Dino testing
- * Bug chasing...
- *
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>       /* interrupt.h wants struct pt_regs defined */
-#include <linux/interrupt.h>
-#include <linux/sched.h>        /* for request_irq/free_irq */        
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kd.h>
-#include <linux/pci_ids.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/parisc-device.h>
-
-/* Debugging stuff */
-#undef KBD_DEBUG
-#ifdef KBD_DEBUG
-	#define DPRINTK(fmt,args...) printk(KERN_DEBUG __FILE__ ":" fmt, ##args)
-#else 
-	#define DPRINTK(x,...)
-#endif
-
-
-/* 
- * Driver constants
- */
-
-/* PS/2 keyboard and mouse constants */
-#define AUX_RECONNECT		0xAA	/* PS/2 Mouse end of test successful */
-#define AUX_REPLY_ACK		0xFA
-#define AUX_ENABLE_DEV		0xF4	/* Enables aux device */
-
-/* Order of the mouse bytes coming to the host */
-#define PACKET_X		1
-#define PACKET_Y		2
-#define PACKET_CTRL		0
-
-#define GSC_MOUSE_OFFSET	0x0100	/* offset from keyboard to mouse port */
-#define GSC_DINO_OFFSET		0x800	/* offset for DINO controller versus LASI one */
-
-#define GSC_ID			0x00	/* ID and reset port offsets */
-#define GSC_RESET		0x00
-#define GSC_RCVDATA		0x04	/* receive and transmit port offsets */
-#define GSC_XMTDATA		0x04
-#define GSC_CONTROL		0x08	/* see: control register bits */
-#define GSC_STATUS		0x0C	/* see: status register bits */
-
-/* Control register bits */
-#define GSC_CTRL_ENBL		0x01	/* enable interface */
-#define GSC_CTRL_LPBXR		0x02	/* loopback operation */
-#define GSC_CTRL_DIAG		0x20	/* directly control clock/data line */
-#define GSC_CTRL_DATDIR		0x40	/* data line direct control */
-#define GSC_CTRL_CLKDIR		0x80	/* clock line direct control */
-
-/* Status register bits */
-#define GSC_STAT_RBNE		0x01	/* Receive Buffer Not Empty */
-#define GSC_STAT_TBNE		0x02	/* Transmit Buffer Not Empty */
-#define GSC_STAT_TERR		0x04	/* Timeout Error */
-#define GSC_STAT_PERR		0x08	/* Parity Error */
-#define GSC_STAT_CMPINTR	0x10	/* Composite Interrupt */
-#define GSC_STAT_DATSHD		0x40	/* Data Line Shadow */
-#define GSC_STAT_CLKSHD		0x80	/* Clock Line Shadow */
-
-/* Keycode map */
-#define KBD_ESCAPE0		0xe0
-#define KBD_ESCAPE1		0xe1
-#define KBD_RELEASE		0xf0
-#define KBD_ACK			0xfa
-#define KBD_RESEND		0xfe
-#define KBD_UNKNOWN		0
-
-#define KBD_TBLSIZE		512
-
-/* Mouse */
-#define MOUSE_LEFTBTN		0x1
-#define MOUSE_MIDBTN		0x4
-#define MOUSE_RIGHTBTN		0x2
-#define MOUSE_ALWAYS1		0x8
-#define MOUSE_XSIGN		0x10
-#define MOUSE_YSIGN		0x20
-#define MOUSE_XOVFLOW		0x40
-#define MOUSE_YOVFLOW		0x80
-
-/* Remnant of pc_keyb.h */
-#define KBD_CMD_SET_LEDS	0xED	/* Sets keyboard leds */
-#define KBD_CMD_SET_RATE	0xF3	/* Sets typematic rate */
-#define KBD_CMD_ENABLE		0xF4	/* Enables scanning */
-#define KBD_CMD_DISABLE		0xF5
-#define KBD_CMD_RESET		0xFF
-
-static unsigned char hpkeyb_keycode[KBD_TBLSIZE] =
-{
-	/* 00 */  KBD_UNKNOWN,  KEY_F9,        KBD_UNKNOWN,   KEY_F5,        KEY_F3,        KEY_F1,       KEY_F2,        KEY_F12,
-	/* 08 */  KBD_UNKNOWN,  KEY_F10,       KEY_F8,        KEY_F6,        KEY_F4,        KEY_TAB,      KEY_GRAVE,     KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_LEFTALT,   KEY_LEFTSHIFT, KBD_UNKNOWN,   KEY_LEFTCTRL,  KEY_Q,        KEY_1,         KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_Z,         KEY_S,         KEY_A,         KEY_W,        KEY_2,         KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KEY_C,         KEY_X,         KEY_D,         KEY_E,         KEY_4,        KEY_3,         KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KEY_SPACE,     KEY_V,         KEY_F,         KEY_T,         KEY_R,        KEY_5,         KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KEY_N,         KEY_B,         KEY_H,         KEY_G,         KEY_Y,        KEY_6,         KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_M,         KEY_J,         KEY_U,         KEY_7,        KEY_8,         KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KEY_COMMA,     KEY_K,         KEY_I,         KEY_O,         KEY_0,        KEY_9,         KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KEY_DOT,       KEY_SLASH,     KEY_L,         KEY_SEMICOLON, KEY_P,        KEY_MINUS,     KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_APOSTROPHE,KBD_UNKNOWN,   KEY_LEFTBRACE, KEY_EQUAL,    KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER,     KEY_RIGHTBRACE,KBD_UNKNOWN,   KEY_BACKSLASH,KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KEY_BACKSPACE, KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_KP1,       KBD_UNKNOWN,   KEY_KP4,       KEY_KP7,       KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-	/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_F7,        KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_ESCAPE0,  KBD_ESCAPE1,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_RELEASE,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_ACK,       KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_RESEND,    KBD_UNKNOWN,
-/* These are offset for escaped keycodes */
-	/* 00 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 08 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 10 */  KBD_UNKNOWN,  KEY_RIGHTALT,  KBD_UNKNOWN,   KBD_UNKNOWN,   KEY_RIGHTCTRL, KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 18 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 20 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 28 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 30 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 38 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 40 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 48 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPSLASH,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 50 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 58 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_KPENTER,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 60 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 68 */  KBD_UNKNOWN,  KEY_END,       KBD_UNKNOWN,   KEY_LEFT,      KEY_HOME,      KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 70 */  KEY_INSERT,   KEY_DELETE,    KEY_DOWN,      KBD_UNKNOWN,   KEY_RIGHT,     KEY_UP,       KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 78 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KEY_PAGEDOWN,  KBD_UNKNOWN,   KEY_SYSRQ,     KEY_PAGEUP,   KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 80 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 88 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 90 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* 98 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* a8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* b8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* c8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* d8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e0 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* e8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f0 */  KBD_RELEASE,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,
-	/* f8 */  KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,   KBD_UNKNOWN,  KBD_UNKNOWN,   KBD_UNKNOWN
-};
-
-
-/* Keyboard struct */
-static struct {
-	struct input_dev dev;
-	char * addr;
-	unsigned int irq;
-	unsigned int scancode;
-	unsigned int escaped;
-	unsigned int released;
-	unsigned int initialized;
-}
-hpkeyb = {
-	.escaped = 0,
-	.released = 0,
-	.initialized = 0
-};
-
-/* Mouse struct */
-static struct {
-   	struct input_dev dev;
-	char * addr;
-	unsigned long irq;
-	unsigned long initialized;
-	int nbread;
-	unsigned char bytes[3];
-	unsigned long last;
-}
-hpmouse = {
-	.initialized = 0,
-	.nbread = 0
-};
-
-static spinlock_t gscps2_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*
- * Various HW level routines
- */
-
-#define gscps2_readb_input(x)		readb(x+GSC_RCVDATA)
-#define gscps2_readb_control(x)		readb(x+GSC_CONTROL)
-#define gscps2_readb_status(x)		readb(x+GSC_STATUS)
-#define gscps2_writeb_control(x, y)	writeb(x, y+GSC_CONTROL)
-
-static inline void gscps2_writeb_output(u8 val, char * addr)
-{
-	int wait = 250;			/* Keyboard is expected to react within 250ms */
-
-	while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
-		if (!--wait)
-			return;		/* This should not happen */
-		mdelay(1);
-	}
-	writeb(val, addr+GSC_XMTDATA);
-}
-
-static inline unsigned char gscps2_wait_input(char * addr)
-{
-	int wait = 250;			/* Keyboard is expected to react within 250ms */
-
-	while (!(gscps2_readb_status(addr) & GSC_STAT_RBNE)) {
-		if (!--wait)
-			return 0;	/* This should not happen */
-		mdelay(1);
-	}
-	return gscps2_readb_input(addr);
-}
-
-static int gscps2_writeb_safe_output(u8 val)
-{
-	/* This function waits for keyboard's ACK */
-	u8 scanread = KBD_UNKNOWN;
-	int loop = 5;
-	
-	while (hpkeyb_keycode[scanread]!=KBD_ACK && --loop > 0) {	
-		gscps2_writeb_output(val, hpkeyb.addr);
-		mdelay(5);
-		scanread = gscps2_wait_input(hpkeyb.addr);
-	}
-	
-	if (loop <= 0)
-		return -1;
-	
-	return 0;
-}
-
-/* Reset the PS2 port */
-static void __init gscps2_reset(char * addr)
-{
-	/* reset the interface */
-	writeb(0xff, addr+GSC_RESET);
-	writeb(0x0 , addr+GSC_RESET);
-
-	/* enable it */
-	gscps2_writeb_control(gscps2_readb_control(addr) | GSC_CTRL_ENBL, addr);
-}
-
-
-/**
- * gscps2_kbd_docode() - PS2 Keyboard basic handler
- *
- * Receives a keyboard scancode, analyses it and sends it to the input layer.
- */
-
-static void gscps2_kbd_docode(struct pt_regs *regs)
-{
-	int scancode = gscps2_readb_input(hpkeyb.addr);
-	DPRINTK("rel=%d scancode=%d, esc=%d ", hpkeyb.released, scancode, hpkeyb.escaped);
-
-	/* Handle previously escaped scancodes */
-	if (hpkeyb.escaped == KBD_ESCAPE0)
-		scancode |= 0x100;	/* jump to the next 256 chars of the table */
-		
-	switch (hpkeyb_keycode[scancode]) {
-		case KBD_RELEASE:
-			DPRINTK("release\n");
-			hpkeyb.released = 1;
-			break;
-		case KBD_RESEND:
-			DPRINTK("resend request\n");
-			break;
-		case KBD_ACK:
-			DPRINTK("ACK\n");
-			break;
-		case KBD_ESCAPE0:
-		case KBD_ESCAPE1:
-			DPRINTK("escape code %d\n", hpkeyb_keycode[scancode]);
-			hpkeyb.escaped = hpkeyb_keycode[scancode];
-			break;
-		case KBD_UNKNOWN:
-			DPRINTK("received unknown scancode %d, escape %d.\n",
-				scancode, hpkeyb.escaped);	/* This is a DPRINTK atm since we do not handle escaped scancodes cleanly */
-			if (hpkeyb.escaped)
-			hpkeyb.escaped = 0;
-			if (hpkeyb.released)
-				hpkeyb.released = 0;
-			return;
-		default:
-			hpkeyb.scancode = scancode;
-			DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released);
-			/*input_regs(regs);*/
-			input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released);
-			input_sync(&hpkeyb.dev);
-			if (hpkeyb.escaped)
-				hpkeyb.escaped = 0;
-			if (hpkeyb.released) 
-				hpkeyb.released = 0;
-			break;	
-	}
-}
-
-
-/**
- * gscps2_mouse_docode() - PS2 Mouse basic handler
- *
- * Receives mouse codes, processes them by packets of three, and sends
- * correct events to the input layer.
- */
-
-static void gscps2_mouse_docode(struct pt_regs *regs)
-{
-	int xrel, yrel;
-
-	/* process BAT (end of basic tests) command */
-	if ((hpmouse.nbread == 1) && (hpmouse.bytes[0] == AUX_RECONNECT))
-		hpmouse.nbread--;
-
-	/* stolen from psmouse.c */
-	if (hpmouse.nbread && time_after(jiffies, hpmouse.last + HZ/2)) {
-		printk(KERN_DEBUG "%s:%d : Lost mouse synchronization, throwing %d bytes away.\n", __FILE__, __LINE__,
-				hpmouse.nbread);
-		hpmouse.nbread = 0;
-	}
-
-	hpmouse.last = jiffies;
-	hpmouse.bytes[hpmouse.nbread++] = gscps2_readb_input(hpmouse.addr);
-	
-	/* process packet */
-	if (hpmouse.nbread == 3) {
-		
-		if (!(hpmouse.bytes[PACKET_CTRL] & MOUSE_ALWAYS1))
-			DPRINTK("Mouse: error on packet always1 bit checking\n");
-			/* XXX should exit now, bad data on the line! */
-		
-		if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW)))
-			DPRINTK("Mouse: position overflow\n");
-		
-		/*input_regs(regs);*/
-
-		input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN);
-		input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN);
-		input_report_key(&hpmouse.dev, BTN_RIGHT, hpmouse.bytes[PACKET_CTRL] & MOUSE_RIGHTBTN);
-		
-		xrel = hpmouse.bytes[PACKET_X];
-		yrel = hpmouse.bytes[PACKET_Y];
-		
-		/* Data sent by mouse are 9-bit signed, the sign bit is in the control packet */
-		if (xrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_XSIGN))
-			xrel = xrel - 0x100;
-		if (yrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_YSIGN))
-			yrel = yrel - 0x100;
-		
-		input_report_rel(&hpmouse.dev, REL_X, xrel);
-		input_report_rel(&hpmouse.dev, REL_Y, -yrel);	/* Y axis is received upside-down */
-		
-		input_sync(&hpmouse.dev);
-		
-		hpmouse.nbread = 0;
-	}
-}
-
-
-/**
- * gscps2_interrupt() - Interruption service routine
- *
- * This processes the list of scancodes queued and sends appropriate
- * key value to the system.
- */
-
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *reg)
-{
-	/* process mouse actions */
-	while (gscps2_readb_status(hpmouse.addr) & GSC_STAT_RBNE)
-		gscps2_mouse_docode(reg);
-	
-	/* process keyboard scancode */
-	while (gscps2_readb_status(hpkeyb.addr) & GSC_STAT_RBNE)
-		gscps2_kbd_docode(reg);
-
-	return IRQ_HANDLED;
-}
-
-
-/**
- * gscps2_hpkeyb_event() - Event handler
- * @return: success/error report
- *
- * Currently only updates leds on keyboard
- */
-
-int gscps2_hpkeyb_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	DPRINTK("Calling %s, type=%d, code=%d, value=%d\n",
-			__FUNCTION__, type, code, value);
-
-	if (!hpkeyb.initialized)
-		return -1;
-
-	if (type == EV_LED) {
-		u8 leds[2];
-
-		if (gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("KBD_CMD_SET_LEDS\n");
-
-		*leds = (test_bit(LED_SCROLLL, dev->led) ? LED_SCR : 0)
-			| (test_bit(LED_NUML,    dev->led) ? LED_NUM : 0)
-			| (test_bit(LED_CAPSL,   dev->led) ? LED_CAP : 0);
-		DPRINTK("Sending leds=%x\n", *leds);
-		
-		if (gscps2_writeb_safe_output(*leds)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("leds sent\n");
-		
-		if (gscps2_writeb_safe_output(KBD_CMD_ENABLE)) {
-			printk(KERN_ERR "gsckbd_leds: timeout\n");
-			return -1;
-		}
-		DPRINTK("End\n");
-
-		return 0;
-
-	}
-	return -1;
-}
-
-
-/**
- * gscps2_kbd_probe() - Probes keyboard device and init input_dev structure
- * @return: number of device initialized (1, 0 on error)
- */
-
-static int __init gscps2_kbd_probe(void)
-{
-	int i, res = 0;
-	unsigned long flags;
-
-	if (hpkeyb.initialized) {
-		printk(KERN_ERR "GSC PS/2 keyboard driver already registered\n");
-		return 0;
-	}
-	
-	spin_lock_irqsave(&gscps2_lock, flags);
- 
-	if (!gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)	&&
-	    !gscps2_writeb_safe_output(0)			&&
-	    !gscps2_writeb_safe_output(KBD_CMD_ENABLE))
-		res = 1;
- 
-	spin_unlock_irqrestore(&gscps2_lock, flags);
-
-	if (!res)
-		printk(KERN_ERR "Keyboard initialization sequence failled\n");
-	
-	init_input_dev(&hpkeyb.dev);
-	
-	for (i = 0; i < KBD_TBLSIZE; i++)
-		if (hpkeyb_keycode[i] != KBD_UNKNOWN)
-			set_bit(hpkeyb_keycode[i], hpkeyb.dev.keybit);
-		
-	hpkeyb.dev.evbit[0]	= BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
-	hpkeyb.dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	hpkeyb.dev.keycode	= hpkeyb_keycode;
-	hpkeyb.dev.keycodesize	= sizeof(unsigned char);
-	hpkeyb.dev.keycodemax	= KBD_TBLSIZE;
-	hpkeyb.dev.name		= "GSC Keyboard";
-	hpkeyb.dev.phys		= "hpkbd/input0";
-
-	hpkeyb.dev.event	= gscps2_hpkeyb_event;
-	
-	/* TODO These need some adjustement, are they really useful ? */
-	hpkeyb.dev.id.bustype	= BUS_GSC;
-	hpkeyb.dev.id.vendor	= PCI_VENDOR_ID_HP;
-	hpkeyb.dev.id.product	= 0x0001;
-	hpkeyb.dev.id.version	= 0x0010;
-	hpkeyb.initialized	= 1;
-
-	return 1;
-}
-
-
-/**
- * gscps2_mouse_probe() - Probes mouse device and init input_dev structure
- * @return: number of device initialized (1, 0 on error)
- *
- * Currently no check on initialization is performed
- */
-
-static int __init gscps2_mouse_probe(void)
-{
-	if (hpmouse.initialized) {
-		printk(KERN_ERR "GSC PS/2 Mouse driver already registered\n");
-		return 0;
-	}
-	
-	init_input_dev(&hpmouse.dev);
-	
-	hpmouse.dev.name	= "GSC Mouse";
-	hpmouse.dev.phys	= "hpmouse/input0";
-   	hpmouse.dev.evbit[0] 	= BIT(EV_KEY) | BIT(EV_REL);
-	hpmouse.dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-	hpmouse.dev.relbit[0] 	= BIT(REL_X) | BIT(REL_Y);
-	hpmouse.last 		= 0;
-
-	gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr);
-	/* Try it a second time, this will give status if the device is available */
-	gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr);
-	
-	/* TODO These need some adjustement, are they really useful ? */
-	hpmouse.dev.id.bustype	= BUS_GSC;
-	hpmouse.dev.id.vendor	= 0x0001;
-	hpmouse.dev.id.product	= 0x0001;
-	hpmouse.dev.id.version	= 0x0010;
-	hpmouse.initialized = 1;
-	return 1;	/* XXX: we don't check if initialization failed */
-}
-
-
-/**
- * gscps2_probe() - Probes PS2 devices
- * @return: success/error report
- */
-
-static int __init gscps2_probe(struct parisc_device *dev)
-{
-	u8 id;
-	char *addr, *name;
-	int ret = 0, device_found = 0;
-	unsigned long hpa = dev->hpa;
-
-	if (!dev->irq)
-		goto fail_pitifully;
-	
-	/* Offset for DINO PS/2. Works with LASI even */
-	if (dev->id.sversion == 0x96)
-		hpa += GSC_DINO_OFFSET;
-
-	addr = ioremap(hpa, 256);
-	
-	if (!hpmouse.initialized || !hpkeyb.initialized)
-		gscps2_reset(addr);
-
-	ret = -EINVAL;
-	id = readb(addr+GSC_ID) & 0x0f;
-	switch (id) {
-		case 0:				/* keyboard */
-			hpkeyb.addr = addr;
-			name = "keyboard";
-			device_found = gscps2_kbd_probe();
-			break;
-		case 1:				/* mouse */
-			hpmouse.addr = addr;
-			name = "mouse";
-			device_found = gscps2_mouse_probe();
-			break;
-		default:
-			printk(KERN_WARNING "%s: Unsupported PS/2 port (id=%d) ignored\n",
-		    		__FUNCTION__, id);
-			goto fail_miserably;
-	}
-
-	/* No valid device found */
-	ret = -ENODEV;
-	if (!device_found)
-		goto fail_miserably;
-
-	/* Here we claim only if we have a device attached */
-	/* Allocate the irq and memory region for that device */
-	ret = -EBUSY;
-	if (request_irq(dev->irq, gscps2_interrupt, 0, name, NULL))
-		goto fail_miserably;
-
-	if (!request_mem_region(hpa, GSC_STATUS + 4, name))
-		goto fail_request_mem;
-	
-	/* Finalize input struct and register it */
-	switch (id) {
-		case 0:				/* keyboard */
-			hpkeyb.irq = dev->irq;
-			input_register_device(&hpkeyb.dev);	
-			break;
-		case 1:				/* mouse */
-			hpmouse.irq = dev->irq;
-			input_register_device(&hpmouse.dev);
-			break;
-		default:
-			break;
-	}
-
-	printk(KERN_INFO "input: PS/2 %s port at 0x%08lx (irq %d) found and attached\n",
-			name, hpa, dev->irq);
-
-	return 0;
-	
-fail_request_mem: free_irq(dev->irq, NULL);
-fail_miserably: iounmap(addr);
-fail_pitifully:	return ret;
-}
-
-
-
-static struct parisc_device_id gscps2_device_tbl[] = {
-	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */
-/*	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 },  DINO PS/2 (XXX Not yet tested) */
-	{ 0, }	/* 0 terminated list */
-};
-
-static struct parisc_driver gscps2_driver = {
-	.name		= "GSC PS2",
-	.id_table	= gscps2_device_tbl,
-	.probe		= gscps2_probe,
-};
-
-static int __init gscps2_init(void)
-{
-	if (register_parisc_driver(&gscps2_driver))
-		return -EBUSY;
-	return 0;
-}
-
-static void __exit gscps2_exit(void)
-{
-	/* TODO this is probably not very good and needs to be checked */
-	if (hpkeyb.initialized) {
-		free_irq(hpkeyb.irq, gscps2_interrupt);
-		iounmap(hpkeyb.addr);
-		hpkeyb.initialized = 0;
-		input_unregister_device(&hpkeyb.dev);
-	}
-	if (hpmouse.initialized) {
-		free_irq(hpmouse.irq, gscps2_interrupt);
-		iounmap(hpmouse.addr);
-		hpmouse.initialized = 0;
-		input_unregister_device(&hpmouse.dev);
-	}
-	unregister_parisc_driver(&gscps2_driver);
-}
-
-
-MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>");
-MODULE_DESCRIPTION("GSC PS/2 keyboard/mouse driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
-
-
-module_init(gscps2_init);
-module_exit(gscps2_exit);
--- diff/drivers/isdn/hisax/cert.c	2002-10-16 04:28:32.000000000 +0100
+++ source/drivers/isdn/hisax/cert.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,50 +0,0 @@
-/* $Id: cert.c,v 2.3.6.3 2001/09/23 22:24:47 kai Exp $
- *
- * Author       Karsten Keil
- * Copyright    by Karsten Keil      <keil@isdn4linux.de>
- * 
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * ../../../Documentation/isdn/HiSax.cert
- *
- */
- 
-#include <linux/kernel.h>
-
-int
-certification_check(int output) {
-
-#ifdef CERTIFICATION
-#if CERTIFICATION == 0
-	if (output) {
-		printk(KERN_INFO "HiSax: Approval certification valid\n");
-		printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n");
-		printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n");
-		printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n");
-		printk(KERN_INFO "HiSax: Approved with HFC-S PCI A based cards\n");
-	}
-	return(0);
-#endif
-#if CERTIFICATION == 1
-	if (output) {
-		printk(KERN_INFO "HiSax: Approval certification failed because of\n");
-		printk(KERN_INFO "HiSax: unauthorized source code changes\n");
-	}
-	return(1);
-#endif
-#if CERTIFICATION == 127
-	if (output) {
-		printk(KERN_INFO "HiSax: Approval certification not possible\n");
-		printk(KERN_INFO "HiSax: because \"md5sum\" is not available\n");
-	}
-	return(2);
-#endif
-#else
-	if (output) {
-		printk(KERN_INFO "HiSax: Certification not verified\n");
-	}
-	return(3);
-#endif
-}
--- diff/drivers/isdn/hisax/hisax_fcclassic.c	2003-06-09 14:18:18.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_fcclassic.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,385 +0,0 @@
-/*
- * Driver for AVM Fritz!classic (ISA) ISDN card
- *
- * Author       Kai Germaschewski
- * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- *              2001 by Karsten Keil       <keil@isdn4linux.de>
- * 
- * based upon Karsten Keil's original avm_a1.c driver
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include "hisax_fcclassic.h"
-
-// debugging cruft
-#define __debug_variable debug
-#include "hisax_debug.h"
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 0;
-MODULE_PARM(debug, "i");
-#endif
-
-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
-MODULE_DESCRIPTION("AVM Fritz!Card classic ISDN driver");
-
-static int protocol = 2;       /* EURO-ISDN Default */
-MODULE_PARM(protocol, "i");
-
-// ----------------------------------------------------------------------
-
-#define	 AVM_A1_STAT_ISAC	0x01
-#define	 AVM_A1_STAT_HSCX	0x02
-#define	 AVM_A1_STAT_TIMER	0x04
-
-// ----------------------------------------------------------------------
-
-static unsigned char
-fcclassic_read_isac(struct isac *isac, unsigned char offset)
-{
-	struct fritz_adapter *adapter = isac->priv;
-	unsigned char val;
-
-	val = inb(adapter->isac_base + offset);
-	DBG(0x1000, " port %#x, value %#x",
-	    offset, val);
-	return val;
-}
-
-static void
-fcclassic_write_isac(struct isac *isac, unsigned char offset,
-		     unsigned char value)
-{
-	struct fritz_adapter *adapter = isac->priv;
-
-	DBG(0x1000, " port %#x, value %#x",
-	    offset, value);
-	outb(value, adapter->isac_base + offset);
-}
-
-static void
-fcclassic_read_isac_fifo(struct isac *isac, unsigned char * data, int size)
-{
-	struct fritz_adapter *adapter = isac->priv;
-
-	insb(adapter->isac_fifo, data, size);
-}
-
-static void
-fcclassic_write_isac_fifo(struct isac *isac, unsigned char * data, int size)
-{
-	struct fritz_adapter *adapter = isac->priv;
-
-	outsb(adapter->isac_fifo, data, size);
-}
-
-static u8
-fcclassic_read_hscx(struct hscx *hscx, u8 offset)
-{
-	struct fritz_adapter *adapter = hscx->priv;
-
-	return inb(adapter->hscx_base[hscx->channel] + offset);
-}
-
-static void
-fcclassic_write_hscx(struct hscx *hscx, u8 offset, u8 value)
-{
-	struct fritz_adapter *adapter = hscx->priv;
-
-	outb(value, adapter->hscx_base[hscx->channel] + offset);
-}
-
-static void
-fcclassic_read_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
-{
-	struct fritz_adapter *adapter = hscx->priv;
-
-	insb(adapter->hscx_fifo[hscx->channel], data, size);
-}
-
-static void
-fcclassic_write_hscx_fifo(struct hscx *hscx, unsigned char * data, int size)
-{
-	struct fritz_adapter *adapter = hscx->priv;
-
-	outsb(adapter->hscx_fifo[hscx->channel], data, size);
-}
-
-// ----------------------------------------------------------------------
-
-static irqreturn_t
-fcclassic_irq(int intno, void *dev, struct pt_regs *regs)
-{
-	struct fritz_adapter *adapter = dev;
-	unsigned char sval;
-
-	DBG(2, "");
-	while ((sval = inb(adapter->cfg_reg) & 0xf) != 0x7) {
-		DBG(2, "sval %#x", sval);
-		if (!(sval & AVM_A1_STAT_TIMER)) {
-			outb(0x1e, adapter->cfg_reg);
-		}
-		if (!(sval & AVM_A1_STAT_HSCX)) {
-			hscx_irq(adapter->hscx);
-		}
-		if (!(sval & AVM_A1_STAT_ISAC)) {
-			isac_irq(&adapter->isac);
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-// ----------------------------------------------------------------------
-
-static int __init
-fcclassic_setup(struct fritz_adapter *adapter)
-{
-	u32 val = 0;
-	int i;
-	int retval;
-
-	DBG(1,"");
-
-	isac_init(&adapter->isac); // FIXME is this okay now
-
-	adapter->cfg_reg      = adapter->io + 0x1800;
-	adapter->isac_base    = adapter->io + 0x1400 - 0x20;
-	adapter->isac_fifo    = adapter->io + 0x1000;
-	adapter->hscx_base[0] = adapter->io + 0x0400 - 0x20;
-	adapter->hscx_fifo[0] = adapter->io;
-	adapter->hscx_base[1] = adapter->io + 0x0c00 - 0x20;
-	adapter->hscx_fifo[1] = adapter->io + 0x0800;
-
-	retval = -EBUSY;
-	if (!request_region(adapter->cfg_reg            ,  8,
-			    "fcclassic cfg"))
-		goto err;
-	if (!request_region(adapter->isac_base + 0x20   , 32,
-			    "fcclassic isac"))
-		goto err_cfg_reg;
-	if (!request_region(adapter->isac_fifo          ,  1,
-			    "fcclassic isac fifo"))
-		goto err_isac_base;
-	if (!request_region(adapter->hscx_base[0] + 0x20, 32,
-			    "fcclassic hscx"))
-		goto err_isac_fifo;
-	if (!request_region(adapter->hscx_fifo[0]       ,  1,
-			    "fcclassic hscx fifo"))
-		goto err_hscx_base_0;
-	if (!request_region(adapter->hscx_base[1] + 0x20, 32,
-			    "fcclassic hscx"))
-		goto err_hscx_fifo_0;
-	if (!request_region(adapter->hscx_fifo[1]       ,  1,
-			    "fcclassic hscx fifo"))
-		goto err_hscx_base_1;
-	retval = request_irq(adapter->irq, fcclassic_irq,  0,
-			     "fcclassic", adapter);
-	if (retval)
-		goto err_hscx_fifo_1;
-
-	// Reset
-	outb(0x00, adapter->cfg_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(200 * HZ / 1000); // 200 msec
-	outb(0x01, adapter->cfg_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(200 * HZ / 1000); // 200 msec
-	outb(0x00, adapter->cfg_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(200 * HZ / 1000); // 200 msec
-
-	val = adapter->irq;
-	if (val == 9)
-		val = 2;
-	outb(val, adapter->cfg_reg + 1);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(200 * HZ / 1000); // 200 msec
-	outb(0x00, adapter->cfg_reg);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(200 * HZ / 1000); // 200 msec
-
-	val = inb(adapter->cfg_reg);
-	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
-	       adapter->cfg_reg, val);
-	val = inb(adapter->cfg_reg + 3);
-	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
-	       adapter->cfg_reg + 3, val);
-	val = inb(adapter->cfg_reg + 2);
-	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
-	       adapter->cfg_reg + 2, val);
-	val = inb(adapter->cfg_reg);
-	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
-	       adapter->cfg_reg, val);
-
-	outb(0x16, adapter->cfg_reg);
-	outb(0x1e, adapter->cfg_reg);
-
-	adapter->isac.priv            = adapter;
-	adapter->isac.read_isac       = &fcclassic_read_isac;
-	adapter->isac.write_isac      = &fcclassic_write_isac;
-	adapter->isac.read_isac_fifo  = &fcclassic_read_isac_fifo;
-	adapter->isac.write_isac_fifo = &fcclassic_write_isac_fifo;
-	hisax_isac_setup(&adapter->isac);
-	for (i = 0; i < 2; i++) {
-		hscx_init(&adapter->hscx[i]);
-		adapter->hscx[i].priv            = adapter;
-		adapter->hscx[i].read_hscx       = &fcclassic_read_hscx;
-		adapter->hscx[i].write_hscx      = &fcclassic_write_hscx;
-		adapter->hscx[i].read_hscx_fifo  = &fcclassic_read_hscx_fifo;
-		adapter->hscx[i].write_hscx_fifo = &fcclassic_write_hscx_fifo;
-		hscx_setup(&adapter->hscx[i]);
-	}
-
-	return 0;
-
- err_hscx_fifo_1:
-	release_region(adapter->hscx_fifo[1]       ,  1);
- err_hscx_base_1:
-	release_region(adapter->hscx_base[1] + 0x20, 32);
- err_hscx_fifo_0:
-	release_region(adapter->hscx_fifo[0]       ,  1);
- err_hscx_base_0:
-	release_region(adapter->hscx_base[0] + 0x20, 32);
- err_isac_fifo:
-	release_region(adapter->isac_fifo          ,  1);
- err_isac_base:
-	release_region(adapter->isac_base    + 0x20, 32);
- err_cfg_reg:
-	release_region(adapter->cfg_reg            ,  8);
- err:
-	return retval;
-}
-
-static void __exit fcclassic_release(struct fritz_adapter *adapter)
-{
-	DBG(1,"");
-
-//	outb(0, adapter->io + AVM_STATUS0);
-	free_irq(adapter->irq, adapter);
-	release_region(adapter->hscx_fifo[1]       ,  1);
-	release_region(adapter->hscx_base[1] + 0x20, 32);
-	release_region(adapter->hscx_fifo[0]       ,  1);
-	release_region(adapter->hscx_base[0] + 0x20, 32);
-	release_region(adapter->isac_fifo          ,  1);
-	release_region(adapter->isac_base    + 0x20, 32);
-	release_region(adapter->cfg_reg            ,  8);
-}
-
-// ----------------------------------------------------------------------
-
-static struct fritz_adapter * __init 
-new_adapter(struct pci_dev *pdev)
-{
-	struct fritz_adapter *adapter;
-	struct hisax_b_if *b_if[2];
-	int i;
-
-	adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
-	if (!adapter)
-		return NULL;
-
-	memset(adapter, 0, sizeof(struct fritz_adapter));
-
-	adapter->isac.hisax_d_if.owner = THIS_MODULE;
-	adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
-	adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
-
-	for (i = 0; i < 2; i++) {
-	  //		adapter->hscx[i].adapter = adapter;
-		adapter->hscx[i].channel = i;
-		adapter->hscx[i].b_if.ifc.priv = &adapter->hscx[i];
-		adapter->hscx[i].b_if.ifc.l2l1 = hscx_b_l2l1;
-	}
-	pci_set_drvdata(pdev, adapter);
-
-	for (i = 0; i < 2; i++)
-		b_if[i] = &adapter->hscx[i].b_if;
-
-	hisax_register(&adapter->isac.hisax_d_if, b_if, "fcclassic", protocol);
-
-	return adapter;
-}
-
-static void
-delete_adapter(struct fritz_adapter *adapter)
-{
-	hisax_unregister(&adapter->isac.hisax_d_if);
-	kfree(adapter);
-}
-
-static int __init
-fcclassic_probe(struct pci_dev *pdev, const struct isapnp_device_id *ent)
-{
-	struct fritz_adapter *adapter;
-	int retval;
-
-	retval = -ENOMEM;
-	adapter = new_adapter(pdev);
-	if (!adapter)
-		goto err;
-
-	adapter->io = pdev->resource[0].start;
-	adapter->irq = pdev->irq_resource[0].start;
-
-	printk(KERN_INFO "hisax_fcclassic: found Fritz!Card classic at IO %#x irq %d\n",
-	       adapter->io, adapter->irq);
-
-	retval = fcclassic_setup(adapter);
-	if (retval)
-		goto err_free;
-
-	return 0;
-	
- err_free:
-	delete_adapter(adapter);
- err:
-	return retval;
-}
-
-static int __exit 
-fcclassic_remove(struct pci_dev *pdev)
-{
-	struct fritz_adapter *adapter = pci_get_drvdata(pdev);
-
-	fcclassic_release(adapter);
-	delete_adapter(adapter);
-
-	return 0;
-}
-
-static struct pci_dev isa_dev[4];
-
-static int __init
-hisax_fcclassic_init(void)
-{
-	printk(KERN_INFO "hisax_fcclassic: Fritz!Card classic ISDN driver v0.0.1\n");
-
-	isa_dev[0].resource[0].start = 0x300;
-	isa_dev[0].irq_resource[0].start = 7;
-
-	fcclassic_probe(isa_dev, NULL);
-
-	return 0;
-}
-
-static void __exit
-hisax_fcclassic_exit(void)
-{
-	fcclassic_remove(isa_dev);
-}
-
-module_init(hisax_fcclassic_init);
-module_exit(hisax_fcclassic_exit);
--- diff/drivers/isdn/hisax/hisax_fcclassic.h	2002-10-16 04:28:30.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_fcclassic.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,18 +0,0 @@
-#include "hisax_if.h"
-#include "hisax_isac.h"
-#include "hisax_hscx.h"
-
-#include <linux/pci.h>
-
-struct fritz_adapter {
-	unsigned int io;
-	unsigned int irq;
-	unsigned int cfg_reg;
-	unsigned int isac_base;
-	unsigned int isac_fifo;
-	unsigned int hscx_base[2];
-	unsigned int hscx_fifo[2];
-	struct isac isac;
-
-	struct hscx hscx[2];
-};
--- diff/drivers/isdn/hisax/hisax_hfcpci.c	2004-02-18 08:54:09.000000000 +0000
+++ source/drivers/isdn/hisax/hisax_hfcpci.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1645 +0,0 @@
-/*
- * Driver for HFC PCI based cards
- *
- * Author       Kai Germaschewski
- * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- *              2000 by Karsten Keil       <keil@isdn4linux.de>
- *              2000 by Werner Cornelius   <werner@isdn4linux.de>
- * 
- * based upon Werner Cornelius's original hfc_pci.c driver
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-// XXX timer3
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include "hisax_hfcpci.h"
-
-// debugging cruft
-#define __debug_variable debug
-#include "hisax_debug.h"
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 0;
-MODULE_PARM(debug, "i");
-#endif
-
-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Werner Cornelius <werner@isdn4linux.de>");
-MODULE_DESCRIPTION("HFC PCI ISDN driver");
-
-#define ID(ven, dev, name)                     \
-        { .vendor      = PCI_VENDOR_ID_##ven,    \
-	  .device      = PCI_DEVICE_ID_##dev,    \
-	  .subvendor   = PCI_ANY_ID,             \
-	  .subdevice   = PCI_ANY_ID,             \
-	  .class       = 0,                      \
-          .class_mask  = 0,                      \
-	  .driver_data = (unsigned long) name }
-
-static struct pci_device_id hfcpci_ids[] = {
-	ID(CCD,     CCD_2BD0,         "CCD/Billion/Asuscom 2BD0"),
-	ID(CCD,     CCD_B000,         "Billion B000"),
-	ID(CCD,     CCD_B006,         "Billion B006"),
-	ID(CCD,     CCD_B007,         "Billion B007"),
-	ID(CCD,     CCD_B008,         "Billion B008"),
-	ID(CCD,     CCD_B009,         "Billion B009"),
-	ID(CCD,     CCD_B00A,         "Billion B00A"),
-	ID(CCD,     CCD_B00B,         "Billion B00B"),
-	ID(CCD,     CCD_B00C,         "Billion B00C"),
-	ID(CCD,     CCD_B100,         "Seyeon"),
-	ID(ABOCOM,  ABOCOM_2BD1,      "Abocom/Magitek"),
-	ID(ASUSTEK, ASUSTEK_0675,     "Asuscom/Askey"),
-	ID(BERKOM,  BERKOM_T_CONCEPT, "German Telekom T-Concept"),
-	ID(BERKOM,  BERKOM_A1T,       "German Telekom A1T"),
-	ID(ANIGMA,  ANIGMA_MC145575,  "Motorola MC145575"),
-	ID(ZOLTRIX, ZOLTRIX_2BD0,     "Zoltrix 2BD0"),
-	ID(DIGI,    DIGI_DF_M_IOM2_E, "Digi DataFire Micro V IOM2 (Europe)"),
-	ID(DIGI,    DIGI_DF_M_E,      "Digi DataFire Micro V (Europe)"),
-	ID(DIGI,    DIGI_DF_M_IOM2_A, "Digi DataFire Micro V IOM2 (America)"),
-	ID(DIGI,    DIGI_DF_M_A,      "Digi DataFire Micro V (America)"),
-	{ } 
-};
-MODULE_DEVICE_TABLE(pci, hfcpci_ids);
-
-#undef ID
-
-static int protocol = 2;       /* EURO-ISDN Default */
-MODULE_PARM(protocol, "i");
-
-// ----------------------------------------------------------------------
-//
-
-#define DBG_WARN      0x0001
-#define DBG_INFO      0x0002
-#define DBG_IRQ       0x0010
-#define DBG_L1M       0x0020
-#define DBG_PR        0x0040
-#define DBG_D_XMIT    0x0100
-#define DBG_D_RECV    0x0200
-#define DBG_B_XMIT    0x1000
-#define DBG_B_RECV    0x2000
-
-/* memory window base address offset (in config space) */
-
-#define HFCPCI_MWBA      0x80
-
-/* GCI/IOM bus monitor registers */
-
-#define HCFPCI_C_I       0x08
-#define HFCPCI_TRxR      0x0C
-#define HFCPCI_MON1_D    0x28
-#define HFCPCI_MON2_D    0x2C
-
-
-/* GCI/IOM bus timeslot registers */
-
-#define HFCPCI_B1_SSL    0x80
-#define HFCPCI_B2_SSL    0x84
-#define HFCPCI_AUX1_SSL  0x88
-#define HFCPCI_AUX2_SSL  0x8C
-#define HFCPCI_B1_RSL    0x90
-#define HFCPCI_B2_RSL    0x94
-#define HFCPCI_AUX1_RSL  0x98
-#define HFCPCI_AUX2_RSL  0x9C
-
-/* GCI/IOM bus data registers */
-
-#define HFCPCI_B1_D      0xA0
-#define HFCPCI_B2_D      0xA4
-#define HFCPCI_AUX1_D    0xA8
-#define HFCPCI_AUX2_D    0xAC
-
-/* GCI/IOM bus configuration registers */
-
-#define HFCPCI_MST_EMOD  0xB4
-#define HFCPCI_MST_MODE	 0xB8
-#define HFCPCI_CONNECT 	 0xBC
-
-
-/* Interrupt and status registers */
-
-#define HFCPCI_FIFO_EN   0x44
-#define HFCPCI_TRM       0x48
-#define HFCPCI_B_MODE    0x4C
-#define HFCPCI_CHIP_ID   0x58
-#define HFCPCI_CIRM  	 0x60
-#define HFCPCI_CTMT	 0x64
-#define HFCPCI_INT_M1  	 0x68
-#define HFCPCI_INT_M2  	 0x6C
-#define HFCPCI_INT_S1  	 0x78
-#define HFCPCI_INT_S2  	 0x7C
-#define HFCPCI_STATUS  	 0x70
-
-/* S/T section registers */
-
-#define HFCPCI_STATES  	 0xC0
-#define HFCPCI_SCTRL  	 0xC4
-#define HFCPCI_SCTRL_E   0xC8
-#define HFCPCI_SCTRL_R   0xCC
-#define HFCPCI_SQ  	 0xD0
-#define HFCPCI_CLKDEL  	 0xDC
-#define HFCPCI_B1_REC    0xF0
-#define HFCPCI_B1_SEND   0xF0
-#define HFCPCI_B2_REC    0xF4
-#define HFCPCI_B2_SEND   0xF4
-#define HFCPCI_D_REC     0xF8
-#define HFCPCI_D_SEND    0xF8
-#define HFCPCI_E_REC     0xFC
-
-
-/* bits in status register (READ) */
-#define HFCPCI_PCI_PROC   0x02
-#define HFCPCI_NBUSY	  0x04 
-#define HFCPCI_TIMER_ELAP 0x10
-#define HFCPCI_STATINT	  0x20
-#define HFCPCI_FRAMEINT	  0x40
-#define HFCPCI_ANYINT	  0x80
-
-/* bits in CTMT (Write) */
-#define HFCPCI_CLTIMER    0x80
-#define HFCPCI_TIM3_125   0x04
-#define HFCPCI_TIM25      0x10
-#define HFCPCI_TIM50      0x14
-#define HFCPCI_TIM400     0x18
-#define HFCPCI_TIM800     0x1C
-#define HFCPCI_AUTO_TIMER 0x20
-#define HFCPCI_TRANSB2    0x02
-#define HFCPCI_TRANSB1    0x01
-
-/* bits in CIRM (Write) */
-#define HFCPCI_AUX_MSK    0x07
-#define HFCPCI_RESET  	  0x08
-#define HFCPCI_B1_REV     0x40
-#define HFCPCI_B2_REV     0x80
-
-/* bits in INT_M1 and INT_S1 */
-#define HFCPCI_INTS_B1TRANS  0x01
-#define HFCPCI_INTS_B2TRANS  0x02
-#define HFCPCI_INTS_DTRANS   0x04
-#define HFCPCI_INTS_B1REC    0x08
-#define HFCPCI_INTS_B2REC    0x10
-#define HFCPCI_INTS_DREC     0x20
-#define HFCPCI_INTS_L1STATE  0x40
-#define HFCPCI_INTS_TIMER    0x80
-
-/* bits in INT_M2 */
-#define HFCPCI_PROC_TRANS    0x01
-#define HFCPCI_GCI_I_CHG     0x02
-#define HFCPCI_GCI_MON_REC   0x04
-#define HFCPCI_IRQ_ENABLE    0x08
-#define HFCPCI_PMESEL        0x80
-
-/* bits in STATES */
-#define HFCPCI_STATE_MSK     0x0F
-#define HFCPCI_LOAD_STATE    0x10
-#define HFCPCI_ACTIVATE	     0x20
-#define HFCPCI_DO_ACTION     0x40
-#define HFCPCI_NT_G2_G3      0x80
-
-/* bits in HFCD_MST_MODE */
-#define HFCPCI_MASTER	     0x01
-#define HFCPCI_SLAVE         0x00
-/* remaining bits are for codecs control */
-
-/* bits in HFCD_SCTRL */
-#define SCTRL_B1_ENA	     0x01
-#define SCTRL_B2_ENA	     0x02
-#define SCTRL_MODE_TE        0x00
-#define SCTRL_MODE_NT        0x04
-#define SCTRL_LOW_PRIO	     0x08
-#define SCTRL_SQ_ENA	     0x10
-#define SCTRL_TEST	     0x20
-#define SCTRL_NONE_CAP	     0x40
-#define SCTRL_PWR_DOWN	     0x80
-
-/* bits in SCTRL_E  */
-#define HFCPCI_AUTO_AWAKE    0x01
-#define HFCPCI_DBIT_1        0x04
-#define HFCPCI_IGNORE_COL    0x08
-#define HFCPCI_CHG_B1_B2     0x80
-
-/* bits in FIFO_EN register */
-#define HFCPCI_FIFOEN_B1     0x03
-#define HFCPCI_FIFOEN_B2     0x0C
-#define HFCPCI_FIFOEN_DTX    0x10
-#define HFCPCI_FIFOEN_DRX    0x20
-#define HFCPCI_FIFOEN_B1TX   0x01
-#define HFCPCI_FIFOEN_B1RX   0x02
-#define HFCPCI_FIFOEN_B2TX   0x04
-#define HFCPCI_FIFOEN_B2RX   0x08
-
-/*
- * thresholds for transparent B-channel mode
- * change mask and threshold simultaneously
- */
-#define HFCPCI_BTRANS_THRESHOLD 128
-#define HFCPCI_BTRANS_THRESMASK 0x00
-
-#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */
-#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
-
-#define MAX_D_FRAMES 0x10
-#define MAX_B_FRAMES 0x20
-#define B_FIFO_START 0x0200
-#define B_FIFO_END   0x2000
-#define B_FIFO_SIZE  (B_FIFO_END - B_FIFO_START)
-#define D_FIFO_START 0x0000
-#define D_FIFO_END   0x0200
-#define D_FIFO_SIZE  (D_FIFO_END - D_FIFO_START)
-
-// ----------------------------------------------------------------------
-// push messages to the upper layers
-
-static inline void D_L1L2(struct hfcpci_adapter *adapter, int pr, void *arg)
-{
-	struct hisax_if *ifc = (struct hisax_if *) &adapter->d_if;
-
-	DBG(DBG_PR, "pr %#x", pr);
-	ifc->l1l2(ifc, pr, arg);
-}
-
-static inline void B_L1L2(struct hfcpci_bcs *bcs, int pr, void *arg)
-{
-	struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
-
-	DBG(DBG_PR, "pr %#x", pr);
-	ifc->l1l2(ifc, pr, arg);
-}
-
-// ----------------------------------------------------------------------
-// MMIO
-
-static inline void
-hfcpci_writeb(struct hfcpci_adapter *adapter, u8 b, unsigned char offset)
-{
-	writeb(b, adapter->mmio + offset);
-}
-
-static inline u8
-hfcpci_readb(struct hfcpci_adapter *adapter, unsigned char offset)
-{
-	return readb(adapter->mmio + offset);
-}
-
-// ----------------------------------------------------------------------
-// magic to define the various F/Z counter accesses
-
-#define DECL_B_F(r, f)                                                      \
-static inline u8                                                            \
-get_b_##r##_##f (struct hfcpci_bcs *bcs)                                    \
-{                                                                           \
-	u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f;       \
-                                                                            \
-	return *(bcs->adapter->fifo + off);                                 \
-}                                                                           \
-                                                                            \
-static inline void                                                          \
-set_b_##r##_##f (struct hfcpci_bcs *bcs, u8 f)                              \
-{                                                                           \
-	u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f;       \
-                                                                            \
-	*(bcs->adapter->fifo + off) = f;                                    \
-}
-
-#define OFF_B1_rx_f1 0x6080
-#define OFF_B2_rx_f1 0x6180
-#define OFF_B1_rx_f2 0x6081
-#define OFF_B2_rx_f2 0x6181
-
-#define OFF_B1_tx_f1 0x2080
-#define OFF_B2_tx_f1 0x2180
-#define OFF_B1_tx_f2 0x2081
-#define OFF_B2_tx_f2 0x2181
-
-DECL_B_F(rx, f1)
-DECL_B_F(rx, f2)
-DECL_B_F(tx, f1)
-DECL_B_F(tx, f2)
-
-#undef DECL_B_F
-
-#define DECL_B_Z(r, z)                                                      \
-static inline u16                                                           \
-get_b_##r##_##z (struct hfcpci_bcs *bcs, u8 f)                              \
-{                                                                           \
-	u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z;       \
-                                                                            \
-	return le16_to_cpu(*((u16 *) (bcs->adapter->fifo + off + f * 4)));  \
-}                                                                           \
-                                                                            \
-static inline void                                                          \
-set_b_##r##_##z(struct hfcpci_bcs *bcs, u8 f, u16 z)                        \
-{                                                                           \
-	u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z;       \
-                                                                            \
-	*((u16 *) (bcs->adapter->fifo + off + f * 4)) = cpu_to_le16(z);     \
-}
-
-#define OFF_B1_rx_z1 0x6000
-#define OFF_B2_rx_z1 0x6100
-#define OFF_B1_rx_z2 0x6002
-#define OFF_B2_rx_z2 0x6102
-
-#define OFF_B1_tx_z1 0x2000
-#define OFF_B2_tx_z1 0x2100
-#define OFF_B1_tx_z2 0x2002
-#define OFF_B2_tx_z2 0x2102
-
-DECL_B_Z(rx, z1)
-DECL_B_Z(rx, z2)
-DECL_B_Z(tx, z1)
-DECL_B_Z(tx, z2)
-
-#undef DECL_B_Z
-
-#define DECL_D_F(r, f)                                                      \
-static inline u8                                                            \
-get_d_##r##_##f (struct hfcpci_adapter *adapter)                            \
-{                                                                           \
-	u16 off = OFF_D_##r##_##f;                                          \
-                                                                            \
-	return *(adapter->fifo + off) & 0xf;                                \
-}                                                                           \
-                                                                            \
-static inline void                                                          \
-set_d_##r##_##f (struct hfcpci_adapter *adapter, u8 f)                      \
-{                                                                           \
-	u16 off = OFF_D_##r##_##f;                                          \
-                                                                            \
-	*(adapter->fifo + off) = f | 0x10;                                  \
-}
-
-#define OFF_D_rx_f1 0x60a0
-#define OFF_D_rx_f2 0x60a1
-
-#define OFF_D_tx_f1 0x20a0
-#define OFF_D_tx_f2 0x20a1
-
-DECL_D_F(rx, f1)
-DECL_D_F(rx, f2)
-DECL_D_F(tx, f1)
-DECL_D_F(tx, f2)
-
-#undef DECL_D_F
-
-#define DECL_D_Z(r, z)                                                      \
-static inline u16                                                           \
-get_d_##r##_##z (struct hfcpci_adapter *adapter, u8 f)                      \
-{                                                                           \
-	u16 off = OFF_D_##r##_##z;                                          \
-                                                                            \
-	return le16_to_cpu(*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)));\
-}                                                                           \
-                                                                            \
-static inline void                                                          \
-set_d_##r##_##z(struct hfcpci_adapter *adapter, u8 f, u16 z)                \
-{                                                                           \
-	u16 off = OFF_D_##r##_##z;                                          \
-                                                                            \
-	*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)) = cpu_to_le16(z); \
-}
-
-#define OFF_D_rx_z1 0x6080
-#define OFF_D_rx_z2 0x6082
-
-#define OFF_D_tx_z1 0x2080
-#define OFF_D_tx_z2 0x2082
-
-DECL_D_Z(rx, z1)
-DECL_D_Z(rx, z2)
-DECL_D_Z(tx, z1)
-DECL_D_Z(tx, z2)
-
-#undef DECL_B_Z
-
-// ----------------------------------------------------------------------
-// fill b / d fifos
-
-static inline void
-hfcpci_fill_d_fifo(struct hfcpci_adapter *adapter)
-{
-	u8 f1, f2;
-	u16 z1, z2;
-	int cnt, fcnt;
-	char *fifo_adr = adapter->fifo;
-	struct sk_buff *tx_skb = adapter->tx_skb;
-	
-	f1 = get_d_tx_f1(adapter);
-	f2 = get_d_tx_f2(adapter);
-	DBG(DBG_D_XMIT, "f1 %#x f2 %#x", f1, f2);
-
-	fcnt = f1 - f2;
-	if (fcnt < 0)
-		fcnt += MAX_D_FRAMES;
-	
-	if (fcnt) {
-		printk("BUG\n");
-		return;
-	}
-
-	z1 = get_d_tx_z1(adapter, f1);
-	z2 = get_d_tx_z2(adapter, f1); //XXX
-	DBG(DBG_D_XMIT, "z1 %#x z2 %#x", z1, z2);
-
-	cnt = z2 - z1;
-	if (cnt <= 0)
-		cnt += D_FIFO_SIZE;
-
-	if (tx_skb->len > cnt) {
-		printk("BUG\n");
-		return;
-	}
-
-	cnt = tx_skb->len;
-	if (z1 + cnt <= D_FIFO_END) {
-		memcpy(fifo_adr + z1, tx_skb->data, cnt);
-	} else {
-		memcpy(fifo_adr + z1, tx_skb->data, D_FIFO_END - z1);
-		memcpy(fifo_adr + D_FIFO_START, 
-		       tx_skb->data + (D_FIFO_END - z1), 
-		       cnt - (D_FIFO_END - z1));
-	}
-	z1 += cnt;
-	if (z1 >= D_FIFO_END)
-		z1 -= D_FIFO_SIZE;
-
-	f1 = (f1 + 1) & (MAX_D_FRAMES - 1);
-	mb();
-	set_d_tx_z1(adapter, f1, z1);
-	mb();
-	set_d_tx_f1(adapter, f1);
-}
-
-static inline void
-hfcpci_fill_b_fifo_hdlc(struct hfcpci_bcs *bcs)
-{
-	u8 f1, f2;
-	u16 z1, z2;
-	int cnt, fcnt;
-	char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000);
-	struct sk_buff *tx_skb = bcs->tx_skb;
-	
-	f1 = get_b_tx_f1(bcs);
-	f2 = get_b_tx_f2(bcs);
-	DBG(DBG_B_XMIT, "f1 %#x f2 %#x", f1, f2);
-
-	fcnt = f1 - f2;
-	if (fcnt < 0)
-		fcnt += MAX_B_FRAMES;
-	
-	if (fcnt) {
-		printk("BUG\n");
-		return;
-	}
-
-	z1 = get_b_tx_z1(bcs, f1);
-	z2 = get_b_tx_z2(bcs, f1); //XXX
-	DBG(DBG_B_XMIT, "z1 %#x z2 %#x", z1, z2);
-
-	cnt = z2 - z1;
-	if (cnt <= 0)
-		cnt += B_FIFO_SIZE;
-
-	if (tx_skb->len > cnt) {
-		printk("BUG\n");
-		return;
-	}
-
-	cnt = tx_skb->len;
-	if (z1 + cnt <= B_FIFO_END) {
-		memcpy(fifo_adr + z1, tx_skb->data, cnt);
-	} else {
-		memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1);
-		memcpy(fifo_adr + B_FIFO_START,
-		       tx_skb->data + (B_FIFO_END - z1), 
-		       cnt - (B_FIFO_END - z1));
-	}
-	z1 += cnt;
-	if (z1 >= B_FIFO_END)
-		z1 -= B_FIFO_SIZE;
-
-	f1 = (f1 + 1) & (MAX_B_FRAMES - 1);
-	mb();
-	set_b_tx_z1(bcs, f1, z1);
-	mb();
-	set_b_tx_f1(bcs, f1);
-}
-
-static inline void
-hfcpci_fill_b_fifo_trans(struct hfcpci_bcs *bcs)
-{
-	int cnt;
-	char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000);
-	struct sk_buff *tx_skb = bcs->tx_skb;
-	u8 f1, f2;
-	u16 z1, z2;
-
-	f1 = get_b_tx_f1(bcs);
-	f2 = get_b_tx_f2(bcs);
-
-	if (f1 != f2)
-		BUG();
-
-	z1 = get_b_tx_z1(bcs, f1);
-	z2 = get_b_tx_z2(bcs, f1);
-
-	cnt = z2 - z1;
-	if (cnt <= 0)
-		cnt += B_FIFO_SIZE;
-
-	if (tx_skb->len > cnt)
-		BUG();
-
-	if (z1 + cnt <= B_FIFO_END) {
-		memcpy(fifo_adr + z1, tx_skb->data, cnt);
-	} else {
-		memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1);
-		memcpy(fifo_adr + B_FIFO_START,
-		       tx_skb->data + (B_FIFO_END - z1), 
-		       cnt - (B_FIFO_END - z1));
-	}
-	z1 += cnt;
-	if (z1 >= B_FIFO_END)
-		z1 -= B_FIFO_SIZE;
-
-	mb();
-	set_b_tx_z1(bcs, f1, z1);
-}
-
-static inline void
-hfcpci_fill_b_fifo(struct hfcpci_bcs *bcs)
-{
-	if (!bcs->tx_skb) {
-		DBG(DBG_WARN, "?");
-		return;
-	}
-	
-	switch (bcs->mode) {
-	case L1_MODE_TRANS:
-		hfcpci_fill_b_fifo_trans(bcs);
-		break;
-	case L1_MODE_HDLC:
-		hfcpci_fill_b_fifo_hdlc(bcs);
-		break;
-	default:
-		DBG(DBG_WARN, "?");
-	}
-}
-
-static void hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs);
-static void hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs);
-
-static void
-hfcpci_b_mode(struct hfcpci_bcs *bcs, int mode)
-{
-	struct hfcpci_adapter *adapter = bcs->adapter;
-	
-	DBG(DBG_B_XMIT, "B%d mode %d --> %d",
-	    bcs->channel + 1, bcs->mode, mode);
-
-	if (bcs->mode == mode)
-		return;
-
-	switch (mode) {
-	case L1_MODE_NULL:
-		if (bcs->channel == 0) {
-			adapter->sctrl &= ~SCTRL_B1_ENA;
-			adapter->sctrl_r &= ~SCTRL_B1_ENA;
-			adapter->fifo_en &= ~HFCPCI_FIFOEN_B1;
-			adapter->int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
-		} else {
-			adapter->sctrl &= ~SCTRL_B2_ENA;
-			adapter->sctrl_r &= ~SCTRL_B2_ENA;
-			adapter->fifo_en &= ~HFCPCI_FIFOEN_B2;
-			adapter->int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
-		}
-		break;
-	case L1_MODE_TRANS:
-	case L1_MODE_HDLC:
-		hfcpci_clear_b_rx_fifo(bcs);
-		hfcpci_clear_b_tx_fifo(bcs);
-		if (bcs->channel == 0) {
-			adapter->sctrl |= SCTRL_B1_ENA;
-			adapter->sctrl_r |= SCTRL_B1_ENA;
-			adapter->fifo_en |= HFCPCI_FIFOEN_B1;
-			adapter->int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
-
-			if (mode == L1_MODE_TRANS)
-				adapter->ctmt |= 1;
-			else
-				adapter->ctmt &= ~1;
-
-		} else {
-			adapter->sctrl |= SCTRL_B2_ENA;
-			adapter->sctrl_r |= SCTRL_B2_ENA;
-			adapter->fifo_en |= HFCPCI_FIFOEN_B2;
-			adapter->int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
-
-			if (mode == L1_MODE_TRANS)
-				adapter->ctmt |= 2;
-			else
-				adapter->ctmt &= ~2;
-
-		}
-		break;
-	}
-	hfcpci_writeb(adapter, adapter->int_m1,  HFCPCI_INT_M1);
-	hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	hfcpci_writeb(adapter, adapter->sctrl,   HFCPCI_SCTRL);
-	hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R);
-	hfcpci_writeb(adapter, adapter->ctmt,    HFCPCI_CTMT);
-	hfcpci_writeb(adapter, adapter->conn,    HFCPCI_CONNECT);
-
-	bcs->mode = mode;
-}
-
-// ----------------------------------------------------------------------
-// Layer 1 state machine
-
-static struct Fsm l1fsm;
-
-enum {
-	ST_L1_F0,
-	ST_L1_F2,
-	ST_L1_F3,
-	ST_L1_F4,
-	ST_L1_F5,
-	ST_L1_F6,
-	ST_L1_F7,
-	ST_L1_F8,
-};
-
-#define L1_STATE_COUNT (ST_L1_F8+1)
-
-static char *strL1State[] =
-{
-	"ST_L1_F0",
-	"ST_L1_F2",
-	"ST_L1_F3",
-	"ST_L1_F4",
-	"ST_L1_F5",
-	"ST_L1_F6",
-	"ST_L1_F7",
-	"ST_L1_F8",
-};
-
-enum {
-	EV_PH_F0,
-	EV_PH_1,
-	EV_PH_F2,
-	EV_PH_F3,
-	EV_PH_F4,
-	EV_PH_F5,
-	EV_PH_F6,
-	EV_PH_F7,
-	EV_PH_F8,
-	EV_PH_ACTIVATE_REQ,
-	EV_PH_DEACTIVATE_REQ,
-	EV_TIMER3,
-};
-
-#define L1_EVENT_COUNT (EV_TIMER3 + 1)
-
-static char *strL1Event[] =
-{
-	"EV_PH_F0",
-	"EV_PH_1",
-	"EV_PH_F2",
-	"EV_PH_F3",
-	"EV_PH_F4",
-	"EV_PH_F5",
-	"EV_PH_F6",
-	"EV_PH_F7",
-	"EV_PH_F8",
-	"EV_PH_ACTIVATE_REQ",
-	"EV_PH_DEACTIVATE_REQ",
-	"EV_TIMER3",
-};
-
-static void l1_ignore(struct FsmInst *fi, int event, void *arg)
-{
-}
-
-static void l1_go_f3(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F3);
-}
-
-static void l1_go_f3_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
-	struct hfcpci_adapter *adapter = fi->userdata;
-
-	FsmChangeState(fi, ST_L1_F3);
-	D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F3);
-}
-
-static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F3);
-}
-
-static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F6);
-}
-
-static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
-	struct hfcpci_adapter *adapter = fi->userdata;
-
-	FsmChangeState(fi, ST_L1_F6);
-	D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void l1_go_f7(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F7);
-}
-
-static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
-{
-	struct hfcpci_adapter *adapter = fi->userdata;
-
-	FsmChangeState(fi, ST_L1_F7);
-	D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
-}
-
-static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L1_F8);
-}
-
-static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
-	struct hfcpci_adapter *adapter = fi->userdata;
-
-	FsmChangeState(fi, ST_L1_F8);
-	D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void l1_act_req(struct FsmInst *fi, int event, void *arg)
-{
-	struct hfcpci_adapter *adapter = fi->userdata;
-
-	hfcpci_writeb(adapter, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION, HFCPCI_STATES);
-}
-
-static struct FsmNode L1FnList[] __initdata =
-{
-	{ST_L1_F2,            EV_PH_F3,             l1_go_f3},
-	{ST_L1_F2,            EV_PH_F6,             l1_go_f6},
-	{ST_L1_F2,            EV_PH_F7,             l1_go_f7_act_ind},
-
-	{ST_L1_F3,            EV_PH_F3,             l1_ignore},
-	{ST_L1_F3,            EV_PH_F4,             l1_go_f4},
-	{ST_L1_F3,            EV_PH_F5,             l1_go_f5},
-	{ST_L1_F3,            EV_PH_F6,             l1_go_f6},
-	{ST_L1_F3,            EV_PH_F7,             l1_go_f7_act_ind},
-	{ST_L1_F3,            EV_PH_ACTIVATE_REQ,   l1_act_req},
-
-	{ST_L1_F4,            EV_PH_F7,             l1_ignore},
-	{ST_L1_F4,            EV_PH_F3,             l1_go_f3},
-	{ST_L1_F4,            EV_PH_F5,             l1_go_f5},
-	{ST_L1_F4,            EV_PH_F6,             l1_go_f6},
-	{ST_L1_F4,            EV_PH_F7,             l1_go_f7},
-
-	{ST_L1_F5,            EV_PH_F7,             l1_ignore},
-	{ST_L1_F5,            EV_PH_F3,             l1_go_f3},
-	{ST_L1_F5,            EV_PH_F6,             l1_go_f6},
-	{ST_L1_F5,            EV_PH_F7,             l1_go_f7},
-
-	{ST_L1_F6,            EV_PH_F7,             l1_ignore},
-	{ST_L1_F6,            EV_PH_F3,             l1_go_f3},
-	{ST_L1_F6,            EV_PH_F7,             l1_go_f7_act_ind},
-	{ST_L1_F6,            EV_PH_F8,             l1_go_f8},
-
-	{ST_L1_F7,            EV_PH_F7,             l1_ignore},
-	{ST_L1_F7,            EV_PH_F3,             l1_go_f3_deact_ind},
-	{ST_L1_F7,            EV_PH_F6,             l1_go_f6_deact_ind},
-	{ST_L1_F7,            EV_PH_F8,             l1_go_f8_deact_ind},
-
-	{ST_L1_F8,            EV_PH_F7,             l1_ignore},
-	{ST_L1_F8,            EV_PH_F3,             l1_go_f3},
-	{ST_L1_F8,            EV_PH_F6,             l1_go_f6},
-	{ST_L1_F8,            EV_PH_F7,             l1_go_f7_act_ind},
-
-};
-
-static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
-{
-	va_list args;
-	char buf[256];
-	
-	va_start(args, fmt);
-	vsprintf(buf, fmt, args);
-	DBG(DBG_L1M, "%s", buf);
-	va_end(args);
-}
-
-// ----------------------------------------------------------------------
-// clear FIFOs
-
-static void
-hfcpci_clear_d_rx_fifo(struct hfcpci_adapter *adapter)
-{
-	u8 fifo_state;
-
-	DBG(DBG_D_RECV, "");
-
-	fifo_state = adapter->fifo_en & HFCPCI_FIFOEN_DRX;
-
-	if (fifo_state) { // enabled
-		// XXX locking
-	        adapter->fifo_en &= ~fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-	
-	adapter->last_fcnt = 0;
-
-	set_d_rx_z1(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1);
-	set_d_rx_z2(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1);
-	mb();
-	set_d_rx_f1(adapter, MAX_D_FRAMES - 1);
-	set_d_rx_f2(adapter, MAX_D_FRAMES - 1);
-	mb();
-	
-	if (fifo_state) {
-	        adapter->fifo_en |= fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-}   
-
-static void
-hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs)
-{
-	struct hfcpci_adapter *adapter = bcs->adapter;
-	int nr = bcs->channel;
-	u8 fifo_state;
-
-	DBG(DBG_B_RECV, "");
-
-	fifo_state = adapter->fifo_en & 
-		(nr ? HFCPCI_FIFOEN_B2RX : HFCPCI_FIFOEN_B1RX);
-
-	if (fifo_state) { // enabled
-	        adapter->fifo_en &= ~fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-	
-	bcs->last_fcnt = 0;
-
-	set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1);
-	set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1);
-	mb();
-	set_b_rx_f1(bcs, MAX_B_FRAMES - 1);
-	set_b_rx_f2(bcs, MAX_B_FRAMES - 1);
-	mb();
-	
-	if (fifo_state) {
-	        adapter->fifo_en |= fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-}   
-
-// XXX clear d_tx_fifo?
-
-static void
-hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs)
-{
-	struct hfcpci_adapter *adapter = bcs->adapter;
-	int nr = bcs->channel;
-	u8 fifo_state;
-
-	fifo_state = adapter->fifo_en & 
-		(nr ? HFCPCI_FIFOEN_B2TX : HFCPCI_FIFOEN_B1TX);
-
-	if (fifo_state) { // enabled
-	        adapter->fifo_en &= ~fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-	
-	bcs->last_fcnt = 0;
-
-	set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1);
-	set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1);
-	mb();
-	set_b_rx_f1(bcs, MAX_B_FRAMES - 1);
-	set_b_rx_f2(bcs, MAX_B_FRAMES - 1);
-	mb();
-	
-	if (fifo_state) {
-	        adapter->fifo_en |= fifo_state;
-		hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-	}
-}   
-
-// ----------------------------------------------------------------------
-// receive messages from upper layers
-
-static void
-hfcpci_d_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
-	struct hfcpci_adapter *adapter = ifc->priv;
-	struct sk_buff *skb = arg;
-
-	DBG(DBG_PR, "pr %#x", pr);
-
-	switch (pr) {
-	case PH_ACTIVATE | REQUEST:
-		FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL);
-		break;
-	case PH_DEACTIVATE | REQUEST:
-		FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL);
-		break;
-	case PH_DATA | REQUEST:
-		DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
-		DBG_SKB(DBG_D_XMIT, skb);
-		if (adapter->l1m.state != ST_L1_F7) {
-			DBG(DBG_WARN, "L1 wrong state %d", adapter->l1m.state);
-			break;
-		}
-		if (adapter->tx_skb)
-			BUG();
-
-		adapter->tx_skb = skb;
-		hfcpci_fill_d_fifo(adapter);
-		break;
-	}
-}
-
-static void
-hfcpci_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
-	struct hfcpci_bcs *bcs = ifc->priv;
-	struct sk_buff *skb = arg;
-	int mode;
-
-	DBG(DBG_PR, "pr %#x", pr);
-
-	switch (pr) {
-	case PH_DATA | REQUEST:
-		if (bcs->tx_skb)
-			BUG();
-		
-		bcs->tx_skb = skb;
-		DBG_SKB(DBG_B_XMIT, skb);
-		hfcpci_fill_b_fifo(bcs);
-		break;
-	case PH_ACTIVATE | REQUEST:
-		mode = (int) arg;
-		DBG(DBG_PR,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
-		hfcpci_b_mode(bcs, mode);
-		B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
-		break;
-	case PH_DEACTIVATE | REQUEST:
-		DBG(DBG_PR,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
-		hfcpci_b_mode(bcs, L1_MODE_NULL);
-		B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
-		break;
-	}
-}
-
-// ----------------------------------------------------------------------
-// receive IRQ
-
-static inline void
-hfcpci_d_recv_irq(struct hfcpci_adapter *adapter)
-{
-	struct sk_buff *skb;
-	char *fifo_adr = adapter->fifo + 0x4000;
-	char *p;
-	int cnt, fcnt;
-	int loop = 5;
-	u8 f1, f2;
-	u16 z1, z2;
-
-	while (loop-- > 0) {
-		f1 = get_d_rx_f1(adapter);
-		f2 = get_d_rx_f2(adapter);
-		DBG(DBG_D_RECV, "f1 %#x f2 %#x", f1, f2);
-		
-		fcnt = f1 - f2;
-		if (fcnt < 0)
-			fcnt += 16;
-
-		if (!fcnt)
-			return;
-		
-		if (fcnt < adapter->last_fcnt)
-			/* overrun */
-			hfcpci_clear_d_rx_fifo(adapter);
-			// XXX init last_fcnt
-
-		z1 = get_d_rx_z1(adapter, f2);
-		z2 = get_d_rx_z2(adapter, f2);
-		DBG(DBG_D_RECV, "z1 %#x z2 %#x", z1, z2);
-
-		cnt = z1 - z2;
-		if (cnt < 0)
-			cnt += D_FIFO_SIZE;
-		cnt++;
-		
-		if (cnt < 4) {
-			DBG(DBG_WARN, "frame too short");
-			goto next;
-		}
-		if (fifo_adr[z1] != 0) {
-			DBG(DBG_WARN, "CRC error");
-			goto next;
-		}
-		cnt -= 3;
-		skb = dev_alloc_skb(cnt);
-		if (!skb) {
-			DBG(DBG_WARN, "no mem");
-			goto next;
-		}
-		p = skb_put(skb, cnt);
-		if (z2 + cnt <= D_FIFO_END) {
-			memcpy(p, fifo_adr + z2, cnt);
-		} else {
-			memcpy(p, fifo_adr + z2, D_FIFO_END - z2);
-			memcpy(p + (D_FIFO_END - z2), fifo_adr + D_FIFO_START,
-			       cnt - (D_FIFO_END - z2));
-		}
-
-		DBG_SKB(DBG_D_RECV, skb);
-		D_L1L2(adapter, PH_DATA | INDICATION, skb);
-	
-	next:
-		if (++z1 >= D_FIFO_END)
-			z1 -= D_FIFO_START;
-
-		f2 = (f2 + 1) & (MAX_D_FRAMES - 1);
-		mb();
-		set_d_rx_z2(adapter, f2, z1);
-		mb();
-		set_d_rx_f2(adapter, f2);
-		
-		adapter->last_fcnt = fcnt - 1;
-	}
-}
-
-static inline void
-hfcpci_b_recv_hdlc_irq(struct hfcpci_adapter *adapter, int nr)
-{
-	struct hfcpci_bcs *bcs = &adapter->bcs[nr];
-	struct sk_buff *skb;
-	char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000);
-	char *p;
-	int cnt, fcnt;
-	int loop = 5;
-	u8 f1, f2;
-	u16 z1, z2;
-
-	while (loop-- > 0) {
-		f1 = get_b_rx_f1(bcs);
-		f2 = get_b_rx_f2(bcs);
-		DBG(DBG_B_RECV, "f1 %d f2 %d", f1, f2);
-		
-		fcnt = f1 - f2;
-		if (fcnt < 0)
-			fcnt += 32;
-
-		if (!fcnt)
-			return;
-		
-		if (fcnt < bcs->last_fcnt)
-			/* overrun */
-			hfcpci_clear_b_rx_fifo(bcs);
-			// XXX init last_fcnt
-		
-		z1 = get_b_rx_z1(bcs, f2);
-		z2 = get_b_rx_z2(bcs, f2);
-		DBG(DBG_B_RECV, "z1 %d z2 %d", z1, z2);
-
-		cnt = z1 - z2;
-		if (cnt < 0)
-			cnt += B_FIFO_SIZE;
-		cnt++;
-		
-		if (cnt < 4) {
-			DBG(DBG_WARN, "frame too short");
-			goto next;
-		}
-		if (fifo_adr[z1] != 0) {
-			DBG(DBG_WARN, "CRC error");
-			goto next;
-		}
-		cnt -= 3;
-		skb = dev_alloc_skb(cnt);
-		if (!skb) {
-			DBG(DBG_WARN, "no mem");
-			goto next;
-		}
-		p = skb_put(skb, cnt);
-		if (z2 + cnt <= B_FIFO_END) {
-			memcpy(p, fifo_adr + z2, cnt);
-		} else {
-			memcpy(p, fifo_adr + z2, B_FIFO_END - z2);
-			memcpy(p + (B_FIFO_END - z2), fifo_adr + B_FIFO_START,
-			       cnt - (B_FIFO_END - z2));
-		}
-
-		DBG_SKB(DBG_B_RECV, skb);
-		B_L1L2(bcs, PH_DATA | INDICATION, skb);
-	
-	next:
-		if (++z1 >= B_FIFO_END)
-			z1 -= B_FIFO_SIZE;
-
-		f2 = (f2 + 1) & (MAX_B_FRAMES - 1);
-		mb();
-		set_b_rx_z2(bcs, f2, z1);
-		mb();
-		set_b_rx_f2(bcs, f2);
-		
-		bcs->last_fcnt = fcnt - 1;
-	}
-}
-
-static inline void
-hfcpci_b_recv_trans_irq(struct hfcpci_adapter *adapter, int nr)
-{
-	struct hfcpci_bcs *bcs = &adapter->bcs[nr];
-	struct sk_buff *skb;
-	char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000);
-	char *p;
-	int cnt;
-	int loop = 5;
-	u8 f1, f2;
-	u16 z1, z2;
-
-	f1 = get_b_rx_f1(bcs);
-	f2 = get_b_rx_f2(bcs);
-
-	if (f1 != f2)
-		BUG();
-
-	while (loop-- > 0) {
-		z1 = get_b_rx_z1(bcs, f2);
-		z2 = get_b_rx_z2(bcs, f2);
-		
-		cnt = z1 - z2;
-		if (!cnt)
-			/* no data available */
-			return;
-		
-		if (cnt < 0)
-			cnt += B_FIFO_SIZE;
-		
-		if (cnt > HFCPCI_BTRANS_THRESHOLD)
-			cnt = HFCPCI_BTRANS_THRESHOLD;
-		
-		skb = dev_alloc_skb(cnt);
-		if (!skb) {
-			DBG(DBG_WARN, "no mem");
-			goto next;
-		}
-		
-		p = skb_put(skb, cnt);
-		if (z2 + cnt <= 0x2000) {
-			memcpy(p, fifo_adr + z2, cnt);
-		} else {
-			memcpy(p, fifo_adr + z2, 0x2000 - z2);
-			p += 0x2000 - z2;
-			memcpy(p, fifo_adr + 0x200, cnt - (0x2000 - z2));
-		}
-		
-		DBG_SKB(DBG_B_RECV, skb);
-		B_L1L2(bcs, PH_DATA | INDICATION, skb);
-		
-	next:
-		z2 += cnt;
-		if (z2 >= 0x2000)
-			z2 -= B_FIFO_SIZE;
-		
-		mb();
-		set_b_rx_z2(bcs, f2, z2);
-		// XXX always receive buffers of a given size
-	}
-}
-
-static inline void
-hfcpci_b_recv_irq(struct hfcpci_adapter *adapter, int nr)
-{
-	DBG(DBG_B_RECV, "");
-
-	switch (adapter->bcs[nr].mode) {
-	case L1_MODE_NULL:
-		DBG(DBG_WARN, "?");
-		break;
-		
-	case L1_MODE_HDLC:
-		hfcpci_b_recv_hdlc_irq(adapter, nr);
-		break;
-
-	case L1_MODE_TRANS:
-		hfcpci_b_recv_trans_irq(adapter, nr);
-		break;
-	}
-}
-
-// ----------------------------------------------------------------------
-// transmit IRQ
-
-// XXX make xmit FIFO deeper than 1 
-
-static inline void
-hfcpci_d_xmit_irq(struct hfcpci_adapter *adapter)
-{
-	struct sk_buff *skb;
-
-	DBG(DBG_D_XMIT, "");
-
-	skb = adapter->tx_skb;
-	if (!skb) {
-		DBG(DBG_WARN, "?");
-		return;
-	}
-
-	adapter->tx_skb = NULL;
-	D_L1L2(adapter, PH_DATA | CONFIRM, (void *) skb->truesize);
-	dev_kfree_skb_irq(skb);
-}
-
-static inline void
-hfcpci_b_xmit_irq(struct hfcpci_adapter *adapter, int nr)
-{
-	struct hfcpci_bcs *bcs = &adapter->bcs[nr];
-	struct sk_buff *skb;
-
-	DBG(DBG_B_XMIT, "");
-
-	skb = bcs->tx_skb;
-	if (!skb) {
-		DBG(DBG_WARN, "?");
-		return;
-	}
-
-	bcs->tx_skb = NULL;
-	B_L1L2(bcs, PH_DATA | CONFIRM, skb);
-}
-
-// ----------------------------------------------------------------------
-// Layer 1 state change IRQ
-
-static inline void
-hfcpci_state_irq(struct hfcpci_adapter *adapter)
-{
-	u8 val;
-
-	val = hfcpci_readb(adapter, HFCPCI_STATES);
-	DBG(DBG_L1M, "STATES %#x", val);
-	FsmEvent(&adapter->l1m, val & 0xf, NULL);
-}
-
-// ----------------------------------------------------------------------
-// Timer IRQ
-
-static inline void
-hfcpci_timer_irq(struct hfcpci_adapter *adapter)
-{
-	hfcpci_writeb(adapter, adapter->ctmt | HFCPCI_CLTIMER, HFCPCI_CTMT);
-}
-
-// ----------------------------------------------------------------------
-// IRQ handler
-
-static irqreturn_t
-hfcpci_irq(int intno, void *dev, struct pt_regs *regs)
-{
-	struct hfcpci_adapter *adapter = dev;
-	int loop = 15;
-	u8 val, stat;
-
-	if (!(adapter->int_m2 & 0x08))
-		return IRQ_NONE;		/* not initialised */ // XX
-
-	stat = hfcpci_readb(adapter, HFCPCI_STATUS);
-	if (!(stat & HFCPCI_ANYINT))
-		return IRQ_NONE;
-
-	spin_lock(&adapter->hw_lock);
-	while (loop-- > 0) {
-		val = hfcpci_readb(adapter, HFCPCI_INT_S1);
-		DBG(DBG_IRQ, "stat %02x s1 %02x", stat, val);
-		val &= adapter->int_m1;
-
-		if (!val)
-			break;
-
-		if (val & 0x08)
-			hfcpci_b_recv_irq(adapter, 0);
-			
-		if (val & 0x10)
-			hfcpci_b_recv_irq(adapter, 1);
-
-		if (val & 0x01)
-			hfcpci_b_xmit_irq(adapter, 0);
-
-		if (val & 0x02)
-			hfcpci_b_xmit_irq(adapter, 1);
-
-		if (val & 0x20)
-			hfcpci_d_recv_irq(adapter);
-
-		if (val & 0x04)
-			hfcpci_d_xmit_irq(adapter);
-
-		if (val & 0x40)
-			hfcpci_state_irq(adapter);
-
-		if (val & 0x80)
-			hfcpci_timer_irq(adapter);
-	}
-	spin_unlock(&adapter->hw_lock);
-	return IRQ_HANDLED;
-}
-
-// ----------------------------------------------------------------------
-// reset hardware
-
-static void
-hfcpci_reset(struct hfcpci_adapter *adapter)
-{
-	/* disable all interrupts */
-	adapter->int_m1 = 0;
-	adapter->int_m2 = 0;
-	hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1);
-	hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2);
-
-	/* reset */
-	hfcpci_writeb(adapter, HFCPCI_RESET, HFCPCI_CIRM);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((30 * HZ) / 1000);
-	hfcpci_writeb(adapter, 0, HFCPCI_CIRM);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((20 * HZ) / 1000);
-	if (hfcpci_readb(adapter, HFCPCI_STATUS) & 2) // XX
-		printk(KERN_WARNING "HFC-PCI init bit busy\n");
-}
-
-// ----------------------------------------------------------------------
-// init hardware
-
-static void
-hfcpci_hw_init(struct hfcpci_adapter *adapter)
-{
-	adapter->fifo_en = 0x30;	/* only D fifos enabled */ // XX
-	hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN);
-
-	/* no echo connect , threshold */
-	adapter->trm = HFCPCI_BTRANS_THRESMASK;
-	hfcpci_writeb(adapter, adapter->trm, HFCPCI_TRM);
-
-	/* ST-Bit delay for TE-Mode */
-	hfcpci_writeb(adapter, CLKDEL_TE, HFCPCI_CLKDEL);
-
-	/* S/T Auto awake */
-	adapter->sctrl_e = HFCPCI_AUTO_AWAKE;
-	hfcpci_writeb(adapter, adapter->sctrl_e, HFCPCI_SCTRL_E);
-
-	/* no exchange */
-	adapter->bswapped = 0;
-	/* we are in TE mode */
-	adapter->nt_mode = 0;
-
-	adapter->ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
-	hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT);
-
-	adapter->int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
-		HFCPCI_INTS_L1STATE;
-	hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1);
-
-	/* clear already pending ints */
-	hfcpci_readb(adapter, HFCPCI_INT_S1);
-
-	adapter->l1m.state = 2;
-	hfcpci_writeb(adapter, HFCPCI_LOAD_STATE | 2, HFCPCI_STATES);	// XX /* HFC ST 2 */
-	udelay(10);
-	hfcpci_writeb(adapter, 2, HFCPCI_STATES);	/* HFC ST 2 */
-
-	/* HFC Master Mode */
-	adapter->mst_m = HFCPCI_MASTER;
-	hfcpci_writeb(adapter, adapter->mst_m, HFCPCI_MST_MODE);
-
-	/* set tx_lo mode, error in datasheet ! */
-	adapter->sctrl = 0x40;
-	hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL);
-
-	adapter->sctrl_r = 0;
-	hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R);
-
-	// XXX
-	/* Init GCI/IOM2 in master mode */
-	/* Slots 0 and 1 are set for B-chan 1 and 2 */
-	/* D- and monitor/CI channel are not enabled */
-	/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
-	/* STIO2 is used as data input, B1+B2 from IOM->ST */
-	/* ST B-channel send disabled -> continous 1s */
-	/* The IOM slots are always enabled */
-	adapter->conn = 0;	/* set data flow directions */
-	hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT);
-	hfcpci_writeb(adapter, 0x80, HFCPCI_B1_SSL);	/* B1-Slot 0 STIO1 out enabled */
-	hfcpci_writeb(adapter, 0x81, HFCPCI_B2_SSL);	/* B2-Slot 1 STIO1 out enabled */
-	hfcpci_writeb(adapter, 0x80, HFCPCI_B1_RSL);	/* B1-Slot 0 STIO2 in enabled */
-	hfcpci_writeb(adapter, 0x81, HFCPCI_B2_RSL);	/* B2-Slot 1 STIO2 in enabled */
-
-	/* Finally enable IRQ output */
-	adapter->int_m2 = HFCPCI_IRQ_ENABLE;
-	hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2);
-
-	hfcpci_readb(adapter, HFCPCI_INT_S2);
-}
-
-// ----------------------------------------------------------------------
-// probe / remove
-
-static struct hfcpci_adapter * __devinit 
-new_adapter(struct pci_dev *pdev)
-{
-	struct hfcpci_adapter *adapter;
-	struct hisax_b_if *b_if[2];
-	int i;
-
-	adapter = kmalloc(sizeof(struct hfcpci_adapter), GFP_KERNEL);
-	if (!adapter)
-		return NULL;
-
-	memset(adapter, 0, sizeof(struct hfcpci_adapter));
-
-	adapter->d_if.owner = THIS_MODULE;
-	adapter->d_if.ifc.priv = adapter;
-	adapter->d_if.ifc.l2l1 = hfcpci_d_l2l1;
-	
-	for (i = 0; i < 2; i++) {
-		adapter->bcs[i].adapter = adapter;
-		adapter->bcs[i].channel = i;
-		adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
-		adapter->bcs[i].b_if.ifc.l2l1 = hfcpci_b_l2l1;
-	}
-
-	pci_set_drvdata(pdev, adapter);
-
-	for (i = 0; i < 2; i++)
-		b_if[i] = &adapter->bcs[i].b_if;
-
-	hisax_register(&adapter->d_if, b_if, "hfcpci", protocol);
-
-	return adapter;
-}
-
-static void delete_adapter(struct hfcpci_adapter *adapter)
-{
-	hisax_unregister(&adapter->d_if);
-	kfree(adapter);
-}
-
-static int __devinit hfcpci_probe(struct pci_dev *pdev,
-				 const struct pci_device_id *ent)
-{
-	struct hfcpci_adapter *adapter;
-	int retval;
-
-	DBG(DBG_INFO, "");
-	retval = -ENOMEM;
-	adapter = new_adapter(pdev);
-	if (!adapter)
-		goto err;
-
-	retval = pci_enable_device(pdev);
-	if (retval)
-		goto err_free;
-
-	adapter->irq = pdev->irq;
-	retval = request_irq(adapter->irq, hfcpci_irq, SA_SHIRQ, 
-			     "hfcpci", adapter);
-	if (retval)
-		goto err_free;
-
-	retval = -EBUSY;
-	if (!request_mem_region(pci_resource_start(pdev, 1), 256, "hfcpci"))
-		goto err_free_irq;
-
-	adapter->mmio = ioremap(pci_resource_start(pdev, 1), 256); // XX pci_io
-	if (!adapter->mmio)
-		goto err_release_region;
-
-	/* Allocate 32K for FIFOs */
-	if (pci_set_dma_mask(pdev, 0xffffffff))
-		goto err_unmap;
-	
-	adapter->fifo = pci_alloc_consistent(pdev, 32768, &adapter->fifo_dma); 
-	if (!adapter->fifo)
-		goto err_unmap;
-	
-	pci_write_config_dword(pdev, HFCPCI_MWBA, (u32) adapter->fifo_dma);
-	pci_set_master(pdev);
-
-	adapter->l1m.fsm = &l1fsm;
-	adapter->l1m.state = ST_L1_F0;
-#ifdef CONFIG_HISAX_DEBUG
-	adapter->l1m.debug = 1;
-#else
-	adapter->l1m.debug = 0;
-#endif
-	adapter->l1m.userdata = adapter;
-	adapter->l1m.printdebug = l1m_debug;
-	FsmInitTimer(&adapter->l1m, &adapter->timer);
-
-	hfcpci_reset(adapter);
-	hfcpci_hw_init(adapter);
-
-	printk(KERN_INFO "hisax_hfcpci: found adapter %s at %s\n",
-	       (char *) ent->driver_data, pci_name(pdev));
-
-	return 0;
-
- err_unmap:
-	iounmap(adapter->mmio);
- err_release_region:
-	release_mem_region(pci_resource_start(pdev, 1), 256);
- err_free_irq:
-	free_irq(adapter->irq, adapter);
- err_free:
-	delete_adapter(adapter);
- err:
-	return retval;
-}
-
-static void __devexit hfcpci_remove(struct pci_dev *pdev)
-{
-	struct hfcpci_adapter *adapter = pci_get_drvdata(pdev);
-
-	hfcpci_reset(adapter);
-
-//	del_timer(&cs->hw.hfcpci.timer); XX
-
-	/* disable DMA */
-	pci_disable_device(pdev);
-	pci_write_config_dword(pdev, HFCPCI_MWBA, 0);
-	pci_free_consistent(pdev, 32768, adapter->fifo, adapter->fifo_dma);
-
-	iounmap(adapter->mmio);
-	release_mem_region(pci_resource_start(pdev, 1), 256);
-	free_irq(adapter->irq, adapter);
-	delete_adapter(adapter);
-}
-
-static struct pci_driver hfcpci_driver = {
-	.name     = "hfcpci",
-	.probe    = hfcpci_probe,
-	.remove   = __devexit_p(hfcpci_remove),
-	.id_table = hfcpci_ids,
-};
-
-static int __init hisax_hfcpci_init(void)
-{
-	int retval;
-
-	printk(KERN_INFO "hisax_hfcpcipnp: HFC PCI ISDN driver v0.0.1\n");
-
-	l1fsm.state_count = L1_STATE_COUNT;
-	l1fsm.event_count = L1_EVENT_COUNT;
-	l1fsm.strState = strL1State;
-	l1fsm.strEvent = strL1Event;
-	retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
-	if (retval)
-		goto err;
-
-	retval = pci_module_init(&hfcpci_driver);
-	if (retval)
-		goto err_fsm;
-	
-	return 0;
-
- err_fsm:
-	FsmFree(&l1fsm);
- err:
-	return retval;
-}
-
-static void __exit hisax_hfcpci_exit(void)
-{
-	FsmFree(&l1fsm);
-	pci_unregister_driver(&hfcpci_driver);
-}
-
-module_init(hisax_hfcpci_init);
-module_exit(hisax_hfcpci_exit);
--- diff/drivers/isdn/hisax/hisax_hfcpci.h	2002-10-16 04:27:55.000000000 +0100
+++ source/drivers/isdn/hisax/hisax_hfcpci.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,40 +0,0 @@
-#include "hisax_if.h"
-#include "hisax_isac.h"
-#include <linux/pci.h>
-
-struct hfcpci_bcs {
-	struct hisax_b_if b_if;
-	struct hfcpci_adapter *adapter;
-	int mode;
-	int channel;
-	int last_fcnt;
-
-	struct sk_buff *tx_skb;
-};
-
-struct hfcpci_adapter {
-	struct hisax_d_if d_if;
-	spinlock_t hw_lock;
-	unsigned int irq;
-	void *mmio;
-	u8 *fifo;
-	dma_addr_t fifo_dma;
-
-	struct FsmInst l1m;
-	struct FsmTimer timer;
-	struct sk_buff *tx_skb;
-	int last_fcnt;
-
-	u8 int_m1, int_m2;
-	u8 fifo_en;
-	u8 trm;
-	u8 sctrl, sctrl_r, sctrl_e;
-	u8 nt_mode;
-	u8 ctmt;
-	u8 mst_m;
-	u8 conn;
-	u8 bswapped;
-
-	struct hfcpci_bcs bcs[2];
-};
-
--- diff/drivers/isdn/hisax/hisax_hscx.c	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hisax_hscx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,420 +0,0 @@
-/*
- * Driver for HSCX
- * High-Level Serial Communcation Controller Extended
- *
- * Author       Kai Germaschewski
- * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
- *              2001 by Karsten Keil       <keil@isdn4linux.de>
- * 
- * based upon Karsten Keil's original isac.c driver
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-/* TODO:
- * comments in .h
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include "hisax_hscx.h"
-
-// debugging cruft
-
-#define __debug_variable debug
-#include "hisax_debug.h"
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 1;
-MODULE_PARM(debug, "i");
-
-static char *HSCXVer[] =
-{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
- "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
-#endif
-
-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
-MODULE_DESCRIPTION("HSCX driver");
-
-#define DBG_WARN      0x0001
-#define DBG_IRQ       0x0002
-#define DBG_L1M       0x0004
-#define DBG_PR        0x0008
-#define DBG_RFIFO     0x0100
-#define DBG_RPACKET   0x0200
-#define DBG_XFIFO     0x1000
-#define DBG_XPACKET   0x2000
-
-#define HSCX_ISTA      0x20
-#define HSCX_ISTA_EXB  0x01
-#define HSCX_ISTA_EXA  0x02
-#define HSCX_ISTA_ICA  0x04
-#define HSCX_ISTA_TIN  0x08
-#define HSCX_ISTA_XPR  0x10
-#define HSCX_ISTA_RSC  0x20
-#define HSCX_ISTA_RPF  0x40
-#define HSCX_ISTA_RME  0x80
-
-#define HSCX_CMDR      0x21
-#define HSCX_CMDR_RMC  0x80
-#define HSCX_CMDR_RHR  0x40
-#define HSCX_CMDR_RNR  0x20
-#define HSCX_CMDR_STI  0x10
-#define HSCX_CMDR_XTF  0x08
-#define HSCX_CMDR_XIF  0x04
-#define HSCX_CMDR_XME  0x02
-#define HSCX_CMDR_XRES 0x01
-
-#define HSCX_EXIR      0x24
-#define HSCX_EXIR_XDU  0x40
-
-#define HSCX_RSTA      0x27
-#define HSCX_RSTA_VFR  0x80
-#define HSCX_RSTA_RDO  0x40
-#define HSCX_RSTA_CRC  0x20
-#define HSCX_RSTA_RAB  0x10
-
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void B_L1L2(struct hscx *hscx, int pr, void *arg)
-{
-	struct hisax_if *ifc = (struct hisax_if *) &hscx->b_if;
-
-	DBG(0x10, "pr %#x", pr);
-	ifc->l1l2(ifc, pr, arg);
-}
-
-static void hscx_version(struct hscx *hscx)
-{
-	int val;
-
-	val = hscx->read_hscx(hscx, HSCX_VSTR) & 0xf;
-	DBG(1, "HSCX version (%x): %s", val, HSCXVer[val]);
-}
-
-static void hscx_empty_fifo(struct hscx *hscx, int count)
-{
-	u8 *ptr;
-
-	DBG(DBG_IRQ, "count %d", count);
-
-	if ((hscx->rcvidx + count) >= HSCX_BUFMAX) {
-		DBG(DBG_WARN, "overrun %d", hscx->rcvidx + count);
-		hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
-		hscx->rcvidx = 0;
-		return;
-	}
-	ptr = hscx->rcvbuf + hscx->rcvidx;
-	hscx->rcvidx += count;
-	hscx->read_hscx_fifo(hscx, ptr, count);
-	hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
-	DBG_PACKET(DBG_RFIFO, ptr, count);
-}
-
-static void hscx_fill_fifo(struct hscx *hscx)
-{
-	int count;
-	unsigned char cmd;
-	int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
-	unsigned char *ptr;
-
-	if (!hscx->tx_skb)
-		BUG();
-
-	count = hscx->tx_skb->len;
-	if (count <= 0)
-		BUG();
-
-	DBG(DBG_IRQ, "count %d", count);
-
-	if (count > fifo_size || hscx->mode == L1_MODE_TRANS) {
-		count = fifo_size;
-		cmd = 0x8;
-	} else {
-		cmd = 0xa;
-	}
-
-	ptr = hscx->tx_skb->data;
-	skb_pull(hscx->tx_skb, count);
-	hscx->tx_cnt += count;
-	DBG_PACKET(DBG_XFIFO, ptr, count);
-	hscx->write_hscx_fifo(hscx, ptr, count);
-	hscx->write_hscx(hscx, HSCX_CMDR, cmd);
-}
-
-static void hscx_retransmit(struct hscx *hscx)
-{
-	if (!hscx->tx_skb) {
-		DBG(DBG_WARN, "no skb");
-		return;
-	}
-	skb_push(hscx->tx_skb, hscx->tx_cnt);
-	hscx->tx_cnt = 0;
-	hscx->write_hscx(hscx, HSCX_CMDR, 0x01);
-}
-
-static inline void hscx_rme_interrupt(struct hscx *hscx)
-{
-	unsigned char val;
-	int count;
-	struct sk_buff *skb;
-	int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
-	
-	val = hscx->read_hscx(hscx, HSCX_RSTA);
-	if ((val & (HSCX_RSTA_VFR | HSCX_RSTA_RDO | HSCX_RSTA_CRC | HSCX_RSTA_RAB) )
-	     != (HSCX_RSTA_VFR | HSCX_RSTA_CRC)) {
-		DBG(DBG_WARN, "RSTA %#x, dropped", val);
-		hscx->write_hscx(hscx, HSCX_CMDR, HSCX_CMDR_RMC);
-		goto out;
-	}
-	
-	count = hscx->read_hscx(hscx, HSCX_RBCL) & (fifo_size-1);
-	DBG(DBG_IRQ, "RBCL %#x", count);
-	if (count == 0)
-		count = fifo_size;
-
-	hscx_empty_fifo(hscx, count);
-
-	count = hscx->rcvidx;
-	if (count < 1) {
-		DBG(DBG_WARN, "count %d < 1", count);
-		goto out;
-	}
-
-	skb = alloc_skb(count, GFP_ATOMIC);
-	if (!skb) {
-		DBG(DBG_WARN, "no memory, dropping\n");
-		goto out;
-	}
-	memcpy(skb_put(skb, count), hscx->rcvbuf, count);
-	DBG_SKB(DBG_RPACKET, skb);
-	B_L1L2(hscx, PH_DATA | INDICATION, skb);
- out:
-	hscx->rcvidx = 0;
-}
-
-static inline void hscx_xpr_interrupt(struct hscx *hscx)
-{
-	struct sk_buff *skb;
-
-	skb = hscx->tx_skb;
-	if (!skb)
-		return;
-
-	if (skb->len > 0) {
-		hscx_fill_fifo(hscx);
-		return;
-	}
-	hscx->tx_cnt = 0;
-	hscx->tx_skb = NULL;
-	B_L1L2(hscx, PH_DATA | CONFIRM, skb);
-}
-
-static inline void hscx_exi_interrupt(struct hscx *hscx)
-{
-	unsigned char val;
-
-	val = hscx->read_hscx(hscx, HSCX_EXIR);
-	DBG(2, "EXIR %#x", val);
-
-	if (val & HSCX_EXIR_XDU) {
-		DBG(DBG_WARN, "HSCX XDU");
-		if (hscx->mode == L1_MODE_TRANS) {
-			hscx_fill_fifo(hscx);
-		} else {
-			hscx_retransmit(hscx);
-		}
-	}
-}
-
-static void hscx_reg_interrupt(struct hscx *hscx, unsigned char val)
-{
-	struct sk_buff *skb;
-
-	if (val & HSCX_ISTA_XPR) {
-		DBG(DBG_IRQ, "XPR");
-		hscx_xpr_interrupt(hscx);
-	}
-	if (val & HSCX_ISTA_RME) {
-		DBG(DBG_IRQ, "RME");
-		hscx_rme_interrupt(hscx);
-	}
-	if (val & HSCX_ISTA_RPF) {
-		int fifo_size = test_bit(HSCX_IPAC, &hscx->flags)? 64: 32;
-
-		DBG(DBG_IRQ, "RPF");
-		hscx_empty_fifo(hscx, fifo_size);
-		if (hscx->mode == L1_MODE_TRANS) {
-			skb = dev_alloc_skb(fifo_size);
-			if (!skb) {
-				DBG(DBG_WARN, "no memory, dropping\n");
-				goto out;
-			}
-			memcpy(skb_put(skb, fifo_size), hscx->rcvbuf, fifo_size);
-			DBG_SKB(DBG_RPACKET, skb);
-			B_L1L2(hscx, PH_DATA | INDICATION, skb);
-		out:
-			hscx->rcvidx = 0;
-		}
-	}
-}
-
-void hscx_irq(struct hscx *hscx_a)
-{
-	struct hscx *hscx_b = hscx_a + 1;
-	unsigned char val;
-
-	val = hscx_b->read_hscx(hscx_b, HSCX_ISTA);
-	DBG(DBG_IRQ, "ISTA B %#x", val);
-
-	if (val & HSCX_ISTA_EXB) {
-		DBG(DBG_IRQ, "EXI B");
-		hscx_exi_interrupt(hscx_b);
-	}
-	if (val & HSCX_ISTA_EXA) {
-		DBG(DBG_IRQ, "EXI A");
-		hscx_exi_interrupt(hscx_a);
-	}
-	if (val & 0xf8) {
-		hscx_reg_interrupt(hscx_b, val);
-	}
-	if (val & HSCX_ISTA_ICA) {
-		val = hscx_a->read_hscx(hscx_a, HSCX_ISTA);
-		DBG(DBG_IRQ, "ISTA A %#x", val);
-		hscx_reg_interrupt(hscx_a, val);
-		hscx_a->write_hscx(hscx_a, HSCX_MASK, 0xff);
-		hscx_a->write_hscx(hscx_a, HSCX_MASK, 0x00);
-	}
-	hscx_b->write_hscx(hscx_b, HSCX_MASK, 0xff);
-	hscx_b->write_hscx(hscx_b, HSCX_MASK, 0x00);
-}
-
-static void modehscx(struct hscx *hscx, int mode)
-{
-	int bc = hscx->channel;
-
-	DBG(0x40, "hscx %c mode %d --> %d",
-	    'A' + hscx->channel, hscx->mode, mode);
-
-	hscx->mode = mode;
-	hscx->write_hscx(hscx, HSCX_XAD1, 0xFF);
-	hscx->write_hscx(hscx, HSCX_XAD2, 0xFF);
-	hscx->write_hscx(hscx, HSCX_RAH2, 0xFF);
-	hscx->write_hscx(hscx, HSCX_XBCH, 0x0);
-	hscx->write_hscx(hscx, HSCX_RLCR, 0x0);
-	hscx->write_hscx(hscx, HSCX_CCR1, 
-			 test_bit(HSCX_IPAC, &hscx->flags) ? 0x82 : 0x85);
-	hscx->write_hscx(hscx, HSCX_CCR2, 0x30);
-	hscx->write_hscx(hscx, HSCX_XCCR, 7);
-	hscx->write_hscx(hscx, HSCX_RCCR, 7);
-
-	/* Switch IOM 1 SSI */
-	if (test_bit(HSCX_IOM1, &hscx->flags))
-		bc = 1;
-
-	hscx->write_hscx(hscx, HSCX_TSAX, hscx->tsaxr);
-	hscx->write_hscx(hscx, HSCX_TSAR, hscx->tsaxr);
-
-	switch (mode) {
-		case (L1_MODE_NULL):
-			hscx->write_hscx(hscx, HSCX_TSAX, 0x1f);
-			hscx->write_hscx(hscx, HSCX_TSAR, 0x1f);
-			hscx->write_hscx(hscx, HSCX_MODE, 0x84);
-			break;
-		case (L1_MODE_TRANS):
-			hscx->write_hscx(hscx, HSCX_MODE, 0xe4);
-			break;
-		case (L1_MODE_HDLC):
-			hscx->write_hscx(hscx, HSCX_CCR1, test_bit(HSCX_IPAC, &hscx->flags) ? 0x8a : 0x8d);
-			hscx->write_hscx(hscx, HSCX_MODE, 0x8c);
-			break;
-	}
-	if (mode)
-		hscx->write_hscx(hscx, HSCX_CMDR, 0x41);
-
-	hscx->write_hscx(hscx, HSCX_ISTA, 0x00);
-}
-
-void hscx_init(struct hscx *hscx)
-{
-	if (hscx->channel)
-		hscx->tsaxr = 0x03;
-	else
-		hscx->tsaxr = 0x2f;
-}
-
-void hscx_setup(struct hscx *hscx)
-{
-	hscx_version(hscx);
-	hscx->mode = -1;
-	modehscx(hscx, L1_MODE_NULL);
-}
-
-void hscx_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
-	struct hscx *hscx = ifc->priv;
-	struct sk_buff *skb = arg;
-	int mode;
-
-	DBG(0x10, "pr %#x", pr);
-
-	switch (pr) {
-	case PH_DATA | REQUEST:
-		if (hscx->tx_skb)
-			BUG();
-		
-		hscx->tx_skb = skb;
-		DBG_SKB(1, skb);
-		hscx_fill_fifo(hscx);
-		break;
-	case PH_ACTIVATE | REQUEST:
-		mode = (int) arg;
-		DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", hscx->channel + 1, mode);
-		modehscx(hscx, mode);
-		B_L1L2(hscx, PH_ACTIVATE | INDICATION, NULL);
-		break;
-	case PH_DEACTIVATE | REQUEST:
-		DBG(4,"B%d,PH_DEACTIVATE_REQUEST", hscx->channel + 1);
-		modehscx(hscx, L1_MODE_NULL);
-		B_L1L2(hscx, PH_DEACTIVATE | INDICATION, NULL);
-		break;
-	}
-}
-
-static int __init hisax_hscx_init(void)
-{
-	printk(KERN_INFO "hisax_hscx: HSCX ISDN driver v0.1.0\n");
-	return 0;
-}
-
-static void __exit hisax_hscx_exit(void)
-{
-}
-
-EXPORT_SYMBOL(hscx_init);
-EXPORT_SYMBOL(hscx_b_l2l1);
-
-EXPORT_SYMBOL(hscx_setup);
-EXPORT_SYMBOL(hscx_irq);
-
-module_init(hisax_hscx_init);
-module_exit(hisax_hscx_exit);
--- diff/drivers/isdn/hisax/hisax_hscx.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/hisax_hscx.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,37 +0,0 @@
-#ifndef __HISAX_HSCX_H__
-#define __HISAX_HSCX_H__
-
-#include <linux/kernel.h>
-#include "fsm.h"
-#include "hisax_if.h"
-
-#define HSCX_BUFMAX	4096
-
-#define HSCX_IOM1 0
-#define HSCX_IPAC 1
-
-struct hscx {
-	void *priv;
-	u_long flags;
-	struct hisax_b_if b_if;
-	int mode;
-	int channel;
-	u8 tsaxr;
-	struct sk_buff *tx_skb;
-	int tx_cnt;
-	u8 rcvbuf[HSCX_BUFMAX];
-	int rcvidx;
-
-	u8 (*read_hscx)      (struct hscx *, u8);
-	void   (*write_hscx)     (struct hscx *, u8, u8);
-	void   (*read_hscx_fifo) (struct hscx *, u8 *, int);
-	void   (*write_hscx_fifo)(struct hscx *, u8 *, int);
-};
-
-void hscx_init(struct hscx *hscx);
-void hscx_b_l2l1(struct hisax_if *hisax_b_if, int pr, void *arg);
-
-void hscx_setup(struct hscx *hscx);
-void hscx_irq(struct hscx *hscx);
-
-#endif
--- diff/drivers/isdn/hisax/ipac.c	2003-05-21 11:50:15.000000000 +0100
+++ source/drivers/isdn/hisax/ipac.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,107 +0,0 @@
-#include "hisax.h"
-#include "isdnl1.h"
-#include "ipac.h"
-#include "hscx.h"
-#include "isac.h"
-
-static inline u8
-ipac_dc_read(struct IsdnCardState *cs, u8 addr)
-{
-	return cs->dc_hw_ops->read_reg(cs, addr);
-}
-
-static inline void
-ipac_dc_write(struct IsdnCardState *cs, u8 addr, u8 val)
-{
-	cs->dc_hw_ops->write_reg(cs, addr, val);
-}
-
-static inline u8
-ipac_bc_read(struct IsdnCardState *cs, int hscx, u8 addr)
-{
-	return cs->bc_hw_ops->read_reg(cs, hscx, addr);
-}
-
-static inline void
-ipac_bc_write(struct IsdnCardState *cs, int hscx, u8 addr, u8 val)
-{
-	cs->bc_hw_ops->write_reg(cs, hscx, addr, val);
-}
-
-static inline u8
-ipac_read(struct IsdnCardState *cs, u8 offset)
-{
-	return ipac_dc_read(cs, offset - 0x80);
-}
-
-static inline void
-ipac_write(struct IsdnCardState *cs, u8 offset, u8 value)
-{
-	ipac_dc_write(cs, offset - 0x80, value);
-}
-
-void
-ipac_init(struct IsdnCardState *cs)
-{
-	set_bit(HW_IPAC, &cs->HW_Flags);
-	inithscxisac(cs);
-}
-
-irqreturn_t
-ipac_irq(int intno, void *dev_id, struct pt_regs *regs)
-{
-	struct IsdnCardState *cs = dev_id;
-	u8 ista, val, icnt = 5;
-
-	spin_lock(&cs->lock);
-	ista = ipac_read(cs, IPAC_ISTA);
-Start_IPAC:
-	if (cs->debug & L1_DEB_IPAC)
-		debugl1(cs, "IPAC ISTA %02X", ista);
-	if (ista & 0x0f) {
-		val = ipac_bc_read(cs, 1, HSCX_ISTA);
-		if (ista & 0x01)
-			val |= 0x01;
-		if (ista & 0x04)
-			val |= 0x02;
-		if (ista & 0x08)
-			val |= 0x04;
-		if (val)
-			hscx_int_main(cs, val);
-	}
-	if (ista & 0x20) {
-		val = ipac_dc_read(cs, ISAC_ISTA) & 0xfe;
-		if (val) {
-			isac_interrupt(cs, val);
-		}
-	}
-	if (ista & 0x10) {
-		val = 0x01;
-		isac_interrupt(cs, val);
-	}
-	ista  = ipac_read(cs, IPAC_ISTA);
-	if ((ista & 0x3f) && icnt) {
-		icnt--;
-		goto Start_IPAC;
-	}
-	if (!icnt)
-		printk(KERN_WARNING "IRQ LOOP\n");
-
-	ipac_write(cs, IPAC_MASK, 0xFF);
-	ipac_write(cs, IPAC_MASK, 0xC0);
-	spin_unlock(&cs->lock);
-	return IRQ_HANDLED;
-}
-
-int
-ipac_setup(struct IsdnCardState *cs, struct dc_hw_ops *ipac_dc_ops,
-	   struct bc_hw_ops *ipac_bc_ops)
-{
-	u8 val;
-
-	cs->dc_hw_ops = ipac_dc_ops;
-	cs->bc_hw_ops = ipac_bc_ops;
-	val = ipac_read(cs, IPAC_ID);
-	printk(KERN_INFO "HiSax: IPAC version %#x\n", val);
-	return 0;
-}
--- diff/drivers/isdn/hisax/md5sums.asc	2002-10-16 04:27:53.000000000 +0100
+++ source/drivers/isdn/hisax/md5sums.asc	1970-01-01 01:00:00.000000000 +0100
@@ -1,22 +0,0 @@
-# This are valid md5sums for certificated HiSax driver.
-# The certification is valid only if the md5sums of all files match.
-# The certification is valid only for ELSA Microlink PCI,
-# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+, 
-# HFC-S PCI A based cards and HFC-S USB based isdn tas 
-# in the moment.
-# Read ../../../Documentation/isdn/HiSax.cert for more informations.
-# 
-d08b59f56fb9ed1fbd17713342c75081  isac.c
-e81e6e96f307e55f8b9777aca2b356d9  isdnl1.c
-cfd2527d9fb01885484cba74bfc67121  isdnl2.c
-8c6829f11459f9d044b5768803fb646d  isdnl3.c
-d40f88dff4191d2660240749cbdcb688  tei.c
-3bd3bd05ee4cb25ffe046200b569a83a  callc.c
-d518f52402ebc3f1be84e09af375313c  cert.c
-c425de1f8be86e84006de63c9bb3cc5f  l3dss1.c
-4c411e29d4103ba60e9af4e3e1234a99  l3_1tr6.c
-68c6cc2784f208e3247a5a555918d014  elsa.c
-8d63a85d7222cf7b40e663e543191d8f  diva.c
-8c8cb4ce621fb84d8e337a696e75b0df  sedlbauer.c
-ebe5613d535748409407568435b2be97  hfc_pci.c
-# end of md5sums
--- diff/drivers/isdn/hisax/rawhdlc.c	2003-05-21 11:49:45.000000000 +0100
+++ source/drivers/isdn/hisax/rawhdlc.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,543 +0,0 @@
-/* $Id: rawhdlc.c,v 1.5.6.2 2001/09/23 22:24:51 kai Exp $
- *
- * support routines for cards that don't support HDLC
- *
- * Author     Brent Baccala
- * Copyright  by Karsten Keil <keil@isdn4linux.de>
- *            by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *
- * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
- * don't perform HDLC encapsulation over the B channel.  Drivers for
- * such cards use support routines in this file to perform B channel HDLC.
- *
- * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
- * over a continuously transmitting serial communications link.
- * It looks like this:
- *
- *      11111111101111110...........0111111011111111111
- *      iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
- *
- *      i = idle     f = flag     d = data
- *
- * When idle, the channel sends a continuous string of ones (mark
- * idle; illustrated), or a continuous string of flag characters (flag
- * idle).  The beginning of a data frame is marked by a flag character
- * (01111110), then comes the actual data, followed by another flag
- * character, after which another frame may be sent immediately (a
- * single flag may serve as both the end of one frame and the start of
- * the next), or the link may return to idle.  Obviously, the flag
- * character can not appear anywhere in the data (or a false
- * end-of-frame would occur), so the transmitter performs
- * "bit-stuffing" - inserting a zero bit after every five one bits,
- * irregardless of the original bit after the five ones.  Byte
- * ordering is irrelevant at this point - the data is treated as a
- * string of bits, not bytes.  Since no more than 5 ones may now occur
- * in a row, the flag sequence, with its 6 ones, is unique.
- *
- * Upon reception, a zero bit that occur after 5 one bits is simply
- * discarded.  A series of 6 one bits is end-of-frame, and a series of
- * 7 one bits is an abort.  Once bit-stuffing has been corrected for,
- * an integer number of bytes should now be present.  The last two
- * of these bytes form the Frame Check Sequence, a CRC that is verified
- * and then discarded.  Note that bit-stuffing is performed on the FCS
- * just as if it were regular data.
- *
- *
- *
- * int make_raw_hdlc_data(u8 *src, u_int slen,
- *                        u8 *dst, u_int dsize)
- *
- *   Used for transmission.  Copies slen bytes from src to dst, performing
- *   HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
- *   dsize is size of destination buffer, and should be at least
- *   ((6*slen)/5)+5 bytes to ensure adequate space will be available.
- *   Function returns length (in bytes) of valid destination buffer, or
- *   0 upon destination overflow.
- *
- * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
- *
- *   Initializes hdlc_state structure before first call to read_raw_hdlc_data
- *
- *   mode = 0: Sane mode
- *   mode = 1/2: 
- *             Insane mode; NETJet use a shared unsigned int memory block (
- * 	       with busmaster DMA), the bit pattern of every word is 
- *  	       <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
- *	       according to Siemens IOM-2 interface, so we have to handle
- *             the src buffer as unsigned int and have to shift/mask the
- *             B-channel bytes.
- *             mode 1 -> B1  mode 2  -> B2 data is used
- *
- * int read_raw_hdlc_data(struct hdlc_state *saved_state,
- *                        u8 *src, u_int slen,
- *                        u8 *dst, u_int dsize)
- *
- *   Used for reception.  Scans source buffer bit-by-bit looking for
- *   valid HDLC frames, which are copied to destination buffer.  HDLC
- *   state information is stored in a structure, which allows this
- *   function to process frames spread across several blocks of raw
- *   HDLC data.  Part of the state information is bit offsets into
- *   the source and destination buffers.
- *
- *   A return value >0 indicates the length of a valid frame, now
- *   stored in the destination buffer.  In this case, the source
- *   buffer might not be completely processed, so this function should
- *   be called again with the same source buffer, possibly with a
- *   different destination buffer.
- *
- *   A return value of zero indicates that the source buffer was
- *   completely processed without finding a valid end-of-packet;
- *   however, we might be in the middle of packet reception, so
- *   the function should be called again with the next block of
- *   raw HDLC data and the same destination buffer.  It is NOT
- *   permitted to change the destination buffer in this case,
- *   since data may already have begun to be stored there.
- *
- *   A return value of -1 indicates some kind of error - destination
- *   buffer overflow, CRC check failed, frame not a multiple of 8
- *   bits.  Destination buffer probably contains invalid data, which
- *   should be discarded.  Call function again with same source buffer
- *   and a new (or same) destination buffer.
- *
- *   Suggested calling sequence:
- *
- *      init_hdlc_state(...);
- *      for (EACH_RAW_DATA_BLOCK) {
- *         while (len = read_raw_hdlc_data(...)) {
- *             if (len == -1) DISCARD_FRAME;
- *             else PROCESS_FRAME;
- *         }
- *      }
- *
- *
- * Test the code in this file as follows:
- *    gcc -DDEBUGME -o rawhdlctest rawhdlc.c
- *    ./rawhdlctest < rawdata
- *
- * The file "rawdata" can be easily generated from a HISAX B-channel
- * hex dump (CF CF CF 02 ...) using the following perl script:
- *
- * while(<>) {
- *     @hexlist = split ' ';
- *     while ($hexstr = shift(@hexlist)) {
- *         printf "%c", hex($hexstr);
- *     }
- * }
- *
- */
-
-#ifdef DEBUGME
-#include <stdio.h>
-#endif
-
-#include <linux/types.h>
-#include <linux/ppp_defs.h>
-#include "rawhdlc.h"
-
-/* There's actually an identical copy of this table in the PPP code
- * (ppp_crc16_table), but I don't want this code dependent on PPP
- */
-
-// static 
-__u16 fcstab[256] =
-{
-	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
-	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
-	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
-	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
-	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
-	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
-	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
-	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
-	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
-	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
-	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
-	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
-	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
-	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
-	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
-	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
-	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
-	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
-	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
-	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
-	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
-	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
-	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
-	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
-	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
-	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
-	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
-	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
-	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
-	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
-	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
-	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
-};
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND  2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE	0x7e
-
-
-#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
-			bitcnt++;\
-			out_val >>= 1;\
-			if (val & 1) {\
-				s_one++;\
-				out_val |= 0x80;\
-			} else {\
-				s_one = 0;\
-				out_val &= 0x7f;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			if (s_one == 5) {\
-				out_val >>= 1;\
-				out_val &= 0x7f;\
-				bitcnt++;\
-				s_one = 0;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			val >>= 1;\
-		}
-
-/* Optimization suggestion: If needed, this function could be
- * dramatically sped up using a state machine.  Each state would
- * correspond to having seen N one bits, and being offset M bits into
- * the current output byte.  N ranges from 0 to 4, M from 0 to 7, so
- * we need 5*8 = 35 states.  Each state would have a table with 256
- * entries, one for each input character.  Each entry would contain
- * three output characters, an output state, an a byte increment
- * that's either 1 or 2.  All this could fit in four bytes; so we need
- * 4 bytes * 256 characters = 1 KB for each state (35 KB total).  Zero
- * the output buffer before you start.  For each character in your
- * input, you look it up in the current state's table and get three
- * bytes to be or'ed into the output at the current byte offset, and
- * an byte increment to move your pointer forward.  A simple Perl
- * script could generate the tables.  Given HDLC semantics, probably
- * would be better to set output to all 1s, then use ands instead of ors.
- * A smaller state machine could operate on nibbles instead of bytes.
- * A state machine for 32-bit architectures could use word offsets
- * instead of byte offsets, requiring 5*32 = 160 states; probably
- * best to work on nibbles in such a case.
- */
-
-
-int make_raw_hdlc_data(u8 *src, u_int slen, u8 *dst, u_int dsize)
-{
-	register u_int i,d_cnt=0;
-	register u8 j;
-	register u8 val;
-	register u8 s_one = 0;
-	register u8 out_val = 0;
-	register u8 bitcnt = 0;
-	u_int fcs;
-	
-	
-	dst[d_cnt++] = HDLC_FLAG_VALUE;
-	fcs = PPP_INITFCS;
-	for (i=0; i<slen; i++) {
-		val = src[i];
-		fcs = PPP_FCS (fcs, val);
-		MAKE_RAW_BYTE;
-	}
-	fcs ^= 0xffff;
-	val = fcs & 0xff;
-	MAKE_RAW_BYTE;
-	val = (fcs>>8) & 0xff;
-	MAKE_RAW_BYTE;
-	val = HDLC_FLAG_VALUE;
-	for (j=0; j<8; j++) { 
-		bitcnt++;
-		out_val >>= 1;
-		if (val & 1)
-			out_val |= 0x80;
-		else
-			out_val &= 0x7f;
-		if (bitcnt==8) {
-			if (d_cnt == dsize) return 0;
-			dst[d_cnt++] = out_val;
-			bitcnt = 0;
-		}
-		val >>= 1;
-	}
-	if (bitcnt) {
-		while (8>bitcnt++) {
-			out_val >>= 1;
-			out_val |= 0x80;
-		}
-		if (d_cnt == dsize) return 0;
-		dst[d_cnt++] = out_val;
-	}
-
-	return d_cnt;
-}
-
-void init_hdlc_state(struct hdlc_state *stateptr, int mode)
-{
-	stateptr->state = HDLC_ZERO_SEARCH;
-	stateptr->r_one = 0;
-	stateptr->r_val = 0;
-	stateptr->o_bitcnt = 0;
-	stateptr->i_bitcnt = 0;
-	stateptr->insane_mode = mode;
-}
-
-/* Optimization suggestion: A similar state machine could surely
- * be developed for this function as well.
- */
-
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u8 *src, u_int slen, u8 *dst, u_int dsize)
-{
-	int retval=0;
-	register u8 val;
-	register u8 state = saved_state->state;
-	register u8 r_one = saved_state->r_one;
-	register u8 r_val = saved_state->r_val;
-	register u_int o_bitcnt = saved_state->o_bitcnt;
-	register u_int i_bitcnt = saved_state->i_bitcnt;
-	register u_int fcs    = saved_state->fcs;
-	register u_int *isrc = (u_int *) src;
-        
-	/* Use i_bitcnt (bit offset into source buffer) to reload "val"
-	 * in case we're starting up again partway through a source buffer
-	 */
-
-	if ((i_bitcnt >> 3) < slen) {
-		if (saved_state->insane_mode==1) {
-			val = isrc[(i_bitcnt >> 3)] & 0xff;
-		} else if (saved_state->insane_mode==2) {
-			val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-		} else {
-			val = src[i_bitcnt >> 3];
-		}
-		val >>= i_bitcnt & 7;
-	}
-
-	/* One bit per loop.  Keep going until we've got something to
-	 * report (retval != 0), or we exhaust the source buffer
-	 */
-
-	while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
-		if ((i_bitcnt & 7) == 0) {
-			if (saved_state->insane_mode==1) {
-				val = isrc[(i_bitcnt >> 3)] & 0xff;
-			} else if (saved_state->insane_mode==2) {
-				val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-			} else {
-				val = src[i_bitcnt >> 3];
-			}
-#ifdef DEBUGME
-			printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
-#endif
-			if (val == 0xff) {
-				state = HDLC_ZERO_SEARCH;
-				o_bitcnt = 0;
-				r_one = 0;
-				i_bitcnt += 8;
-				continue;
-			}
-		}
-
-#ifdef DEBUGME
-		/* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
-#endif
-
-		if (state == HDLC_ZERO_SEARCH) {
-			if (val & 1) {
-				r_one++;
-			} else {
-				r_one=0;
-				state= HDLC_FLAG_SEARCH;
-			}
-		} else if (state == HDLC_FLAG_SEARCH) { 
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					state=HDLC_FLAG_FOUND;
-				}
-				r_one=0;
-			}
-		} else if (state ==  HDLC_FLAG_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else if (r_one!=5) {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state != HDLC_ZERO_SEARCH) &&
-				!(o_bitcnt & 7)) {
-#ifdef DEBUGME
-				printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
-#endif
-				state=HDLC_FRAME_FOUND;
-				fcs = PPP_INITFCS;
-				dst[0] = r_val;
-				fcs = PPP_FCS (fcs, r_val);
-			}
-		} else if (state ==  HDLC_FRAME_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-					o_bitcnt=0;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					r_val=0; 
-					r_one=0;
-					o_bitcnt++;
-					if (o_bitcnt & 7) {
-						/* Alignment error */
-#ifdef DEBUGME
-						printf("Alignment error\n");
-#endif
-						state=HDLC_FLAG_SEARCH;
-						retval = -1;
-					} else if (fcs==PPP_GOODFCS) {
-						/* Valid frame */
-						state=HDLC_FLAG_FOUND;
-						retval = (o_bitcnt>>3)-3;
-					} else {
-						/* CRC error */
-#ifdef DEBUGME
-						printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
-#endif
-						state=HDLC_FLAG_FOUND;
-						retval = -1;
-					}
-				} else if (r_one==5) {
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state == HDLC_FRAME_FOUND) &&
-				!(o_bitcnt & 7)) {
-				if ((o_bitcnt>>3)>=dsize) {
-					/* Buffer overflow error */
-#ifdef DEBUGME
-					printf("Buffer overflow error\n");
-#endif
-					r_val=0; 
-					state=HDLC_FLAG_SEARCH;
-					retval = -1;
-				} else {
-					dst[(o_bitcnt>>3)-1] = r_val;
-					fcs = PPP_FCS (fcs, r_val);
-#ifdef DEBUGME
-					printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
-#endif
-				}
-			}
-		}
-		i_bitcnt ++;
-		val >>= 1;
-	}
-
-	/* We exhausted the source buffer before anything else happened
-	 * (retval==0).  Reset i_bitcnt in expectation of a new source
-	 * buffer.  Other, we either had an error or a valid frame, so
-	 * reset o_bitcnt in expectation of a new destination buffer.
-	 */
-
-	if (retval == 0) {
-		i_bitcnt = 0;
-	} else {
-		o_bitcnt = 0;
-	}
-
-	saved_state->state = state;
-	saved_state->r_one = r_one;
-	saved_state->r_val = r_val;
-	saved_state->fcs = fcs;
-	saved_state->o_bitcnt = o_bitcnt;
-	saved_state->i_bitcnt = i_bitcnt;
-
-	return (retval);
-}
-
-
-
-#ifdef DEBUGME
-
-char buffer[1024];
-char obuffer[1024];
-
-main()
-{
-  int buflen=0;
-  int len;
-  struct hdlc_state hdlc_state;
-
-  while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
-
-  printf("buflen = %d\n", buflen);
-
-  init_hdlc_state(&hdlc_state, 0);
-
-  while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
-    if (len == -1) printf("Error @ byte %d/bit %d\n",
-			  hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
-    else {
-      printf("Frame received: len %d\n", len);
-    }
-  }
-
-  printf("Done\n");
-}
-
-#endif
--- diff/drivers/isdn/hisax/rawhdlc.h	2003-01-13 14:18:15.000000000 +0000
+++ source/drivers/isdn/hisax/rawhdlc.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,28 +0,0 @@
-/* $Id: rawhdlc.h,v 1.3.6.2 2001/09/23 22:24:51 kai Exp $
- *
- * Author     Brent Baccala
- * Copyright  by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef RAWHDLC_H
-struct hdlc_state {
-	char insane_mode;
-	u8 state;
-	u8 r_one;
-	u8 r_val;
-	u_int o_bitcnt;
-	u_int i_bitcnt;
-	u_int fcs;
-};
-
-
-int make_raw_hdlc_data(u8 *src, u_int slen, u8 *dst, u_int dsize);
-void init_hdlc_state(struct hdlc_state *stateptr, int mode);
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u8 *src, u_int slen, u8 *dst, u_int dsize);
-#define RAWHDLC_H
-#endif
--- diff/drivers/isdn/i4l/isdn_ciscohdlck.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ciscohdlck.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,452 +0,0 @@
-/* Linux ISDN subsystem, CISCO HDLC network interfaces
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *           2001       by Bjoern A. Zeeb <i4l@zabbadoz.net>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For info on the protocol, see http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
- */
-
-#include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_ciscohdlck.h"
-
-#include <linux/if_arp.h>
-#include <linux/inetdevice.h>
-
-/*
- * Definitions for Cisco-HDLC header.
- */
-
-#define CISCO_ADDR_UNICAST    0x0f
-#define CISCO_ADDR_BROADCAST  0x8f
-#define CISCO_CTRL            0x00
-#define CISCO_TYPE_CDP        0x2000
-#define CISCO_TYPE_SLARP      0x8035
-#define CISCO_SLARP_REQUEST   0
-#define CISCO_SLARP_REPLY     1
-#define CISCO_SLARP_KEEPALIVE 2
-
-/* 
- * CISCO HDLC keepalive specific stuff
- */
-static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_dev *idev, int len)
-{
-	unsigned short hl = isdn_slot_hdrlen(idev->isdn_slot);
-	struct sk_buff *skb;
-
-	skb = alloc_skb(hl + len, GFP_ATOMIC);
-	if (!skb) {
-		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
-		return NULL;
-	}
-	skb_reserve(skb, hl);
-	return skb;
-}
-
-/* cisco hdlck device private ioctls */
-static int
-isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	isdn_net_local *mlp = dev->priv;
-	struct inl_cisco *cisco = mlp->inl_priv;
-	unsigned long len = 0;
-	int period;
-	char debserint;
-	int rc = 0;
-
-	if (mlp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
-		return -EINVAL;
-
-	switch (cmd) {
-		/* get/set keepalive period */
-		case SIOCGKEEPPERIOD:
-			len = sizeof(cisco->keepalive_period);
-			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
-					 (char *)&cisco->keepalive_period, len))
-				rc = -EFAULT;
-			break;
-		case SIOCSKEEPPERIOD:
-			len = sizeof(cisco->keepalive_period);
-			if (copy_from_user((char *)&period,
-					   (char *)ifr->ifr_ifru.ifru_data, len)) {
-				rc = -EFAULT;
-				break;
-			}
-			if (period <= 0 || period > 32767) {
-				rc = -EINVAL;
-				break;
-			}
-			mod_timer(&cisco->timer, jiffies + period * HZ);
-			printk(KERN_INFO "%s: Keepalive period set "
-			       "to %d seconds.\n", dev->name, period);
-			cisco->keepalive_period = period;
-			break;
-
-		/* get/set debugging */
-		case SIOCGDEBSERINT:
-			len = sizeof(cisco->debserint);
-			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
-					 (char *)&cisco->debserint, len))
-				rc = -EFAULT;
-			break;
-		case SIOCSDEBSERINT:
-			len = sizeof(cisco->debserint);
-			if (copy_from_user((char *)&debserint,
-					   (char *)ifr->ifr_ifru.ifru_data, len)) {
-				rc = -EFAULT;
-				break;
-			}
-			if (debserint < 0 || debserint > 64) {
-				rc = -EINVAL;
-				break;
-			}
-			cisco->debserint = debserint;
-			break;
-
-		default:
-			rc = -EINVAL;
-			break;
-	}
-	return (rc);
-}
-
-/* called via cisco_timer.function */
-static void
-isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
-{
-	isdn_net_local *mlp = (isdn_net_local *) data;
- 	isdn_net_dev *idev;
-	struct inl_cisco *cisco = mlp->inl_priv;
-	struct sk_buff *skb;
-	unsigned char *p;
-	unsigned long last_cisco_myseq = cisco->myseq;
-	int myseq_diff = 0;
-
-	if (list_empty(&mlp->online)) {
-		isdn_BUG();
-		return;
-	}
-	idev = list_entry(mlp->online.next, isdn_net_dev, online);
-	cisco->myseq++;
-
-	myseq_diff = cisco->myseq - cisco->mineseen;
-	if (cisco->line_state && (myseq_diff >= 3 || myseq_diff <= -3)) {
-		/* line up -> down */
-		cisco->line_state = 0;
-		printk (KERN_WARNING
-				"UPDOWN: Line protocol on Interface %s,"
-				" changed state to down\n", idev->name);
-		/* should stop routing higher-level data accross */
-	} else if (!cisco->line_state &&
-		myseq_diff >= 0 && myseq_diff <= 2) {
-		/* line down -> up */
-		cisco->line_state = 1;
-		printk (KERN_WARNING
-				"UPDOWN: Line protocol on Interface %s,"
-				" changed state to up\n", idev->name);
-		/* restart routing higher-level data accross */
-	}
-
-	if (cisco->debserint)
-		printk (KERN_DEBUG "%s: HDLC "
-			"myseq %u, mineseen %u%c, yourseen %u, %s\n",
-			idev->name, cisco->myseq, cisco->mineseen,
-			(last_cisco_myseq == cisco->mineseen) ? '*' : 040,
-			cisco->yourseq,
-			(cisco->line_state) ? "line up" : "line down");
-
-	skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp keepalive */
-	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
-	p += put_u32(p, cisco->myseq);
-	p += put_u32(p, cisco->yourseq);
-	p += put_u16(p, 0xffff); // reliablity, always 0xffff
-
-	isdn_net_write_super(idev, skb);
-
-	mod_timer(&cisco->timer, jiffies + cisco->keepalive_period * HZ);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *mlp)
-{
-	isdn_net_dev *idev;
-	struct sk_buff *skb;
-	unsigned char *p;
-
-	if (list_empty(&mlp->online)) {
-		isdn_BUG();
-		return;
-	}
-	idev = list_entry(mlp->online.next, isdn_net_dev, online);
-
-	skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp request */
-	p += put_u32(p, CISCO_SLARP_REQUEST);
-	p += put_u32(p, 0); // address
-	p += put_u32(p, 0); // netmask
-	p += put_u16(p, 0); // unused
-
-	isdn_net_write_super(idev, skb);
-}
-
-static void 
-isdn_ciscohdlck_connected(isdn_net_dev *idev)
-{
-	isdn_net_local *lp = idev->mlp;
-	struct inl_cisco *cisco = lp->inl_priv;
-
-	cisco->myseq = 0;
-	cisco->mineseen = 0;
-	cisco->yourseq = 0;
-	cisco->keepalive_period = 10;
-	cisco->last_slarp_in = 0;
-	cisco->line_state = 0;
-	cisco->debserint = 0;
-
-	if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
-		/* send slarp request because interface/seq.no.s reset */
-		isdn_net_ciscohdlck_slarp_send_request(lp);
-
-		init_timer(&cisco->timer);
-		cisco->timer.data = (unsigned long) lp;
-		cisco->timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
-		cisco->timer.expires = jiffies + cisco->keepalive_period * HZ;
-		add_timer(&cisco->timer);
-	}
-	netif_wake_queue(&lp->dev);
-}
-
-static void 
-isdn_ciscohdlck_disconnected(isdn_net_dev *idev)
-{
-	isdn_net_local *lp = idev->mlp;
-	struct inl_cisco *cisco = lp->inl_priv;
-
-	if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
-		del_timer(&cisco->timer);
-	}
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	struct sk_buff *skb;
-	unsigned char *p;
-	struct in_device *in_dev = NULL;
-	u32 addr = 0;		/* local ipv4 address */
-	u32 mask = 0;		/* local netmask */
-
-	if ((in_dev = mlp->dev.ip_ptr) != NULL) {
-		/* take primary(first) address of interface */
-		struct in_ifaddr *ifa = in_dev->ifa_list;
-		if (ifa != NULL) {
-			addr = ifa->ifa_local;
-			mask = ifa->ifa_mask;
-		}
-	}
-
-	skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp reply, send own ip/netmask; if values are nonsense remote
-	 * should think we are unable to provide it with an address via SLARP */
-	p += put_u32(p, CISCO_SLARP_REPLY);
-	p += put_u32(p, addr);	// address
-	p += put_u32(p, mask);	// netmask
-	p += put_u16(p, 0);	// unused
-
-	isdn_net_write_super(idev, skb);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	isdn_net_local *mlp = idev->mlp;
-	struct inl_cisco *cisco = mlp->inl_priv;
-	unsigned char *p;
-	int period;
-	u32 code;
-	u32 my_seq, addr;
-	u32 your_seq, mask;
-	u32 local;
-	u16 unused;
-
-	if (skb->len < 14)
-		return;
-
-	p = skb->data;
-	p += get_u32(p, &code);
-	
-	switch (code) {
-	case CISCO_SLARP_REQUEST:
-		cisco->yourseq = 0;
-		isdn_net_ciscohdlck_slarp_send_reply(idev);
-		break;
-	case CISCO_SLARP_REPLY:
-		addr = ntohl(*(u32 *)p);
-		mask = ntohl(*(u32 *)(p+4));
-		if (mask != 0xfffffffc)
-			goto slarp_reply_out;
-		if ((addr & 3) == 0 || (addr & 3) == 3)
-			goto slarp_reply_out;
-		local = addr ^ 3;
-		printk(KERN_INFO "%s: got slarp reply: "
-			"remote ip: %d.%d.%d.%d, "
-			"local ip: %d.%d.%d.%d "
-			"mask: %d.%d.%d.%d\n",
-		       idev->name,
-		       HIPQUAD(addr),
-		       HIPQUAD(local),
-		       HIPQUAD(mask));
-		break;
-  slarp_reply_out:
-		 printk(KERN_INFO "%s: got invalid slarp "
-				 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
-				 "- ignored\n", idev->name,
-				 HIPQUAD(addr), HIPQUAD(mask));
-		break;
-	case CISCO_SLARP_KEEPALIVE:
-		period = (jiffies - cisco->last_slarp_in + HZ/2 - 1) / HZ;
-		if (cisco->debserint &&
-				(period != cisco->keepalive_period) &&
-				cisco->last_slarp_in) {
-			printk(KERN_DEBUG "%s: Keepalive period mismatch - "
-				"is %d but should be %d.\n",
-				idev->name, period, cisco->keepalive_period);
-		}
-		cisco->last_slarp_in = jiffies;
-		p += get_u32(p, &my_seq);
-		p += get_u32(p, &your_seq);
-		p += get_u16(p, &unused);
-		cisco->yourseq = my_seq;
-		cisco->mineseen = your_seq;
-		break;
-	}
-}
-
-static void 
-isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
-			struct sk_buff *skb)
-{
-	struct inl_cisco *cisco = lp->inl_priv;
-	unsigned char *p;
- 	u8 addr;
- 	u8 ctrl;
- 	u16 type;
-	
-	if (skb->len < 4)
-		goto out_free;
-
-	p = skb->data;
-	p += get_u8 (p, &addr);
-	p += get_u8 (p, &ctrl);
-	p += get_u16(p, &type);
-	skb_pull(skb, 4);
-	
-	if ((addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) ||
-	    ctrl != CISCO_CTRL) {
-		printk(KERN_DEBUG "%s: Unknown Cisco header %#02x %#02x\n",
-		       idev->name, addr, ctrl);
-		goto out_free;
-	}
-
-	switch (type) {
-	case CISCO_TYPE_SLARP:
-		isdn_net_ciscohdlck_slarp_in(idev, skb);
-		goto out_free;
-	case CISCO_TYPE_CDP:
-		if (cisco->debserint)
-			printk(KERN_DEBUG "%s: Received CDP packet. use "
-				"\"no cdp enable\" on cisco.\n", idev->name);
-		goto out_free;
-	default:
-		/* no special cisco protocol */
-		idev->huptimer = 0;
-		skb->protocol = htons(type);
-		netif_rx(skb);
-		return;
-	}
-
- out_free:
-	kfree_skb(skb);
-}
-
-static int
-isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev, 
-		      unsigned short type,
-		      void *daddr, void *saddr, unsigned plen)
-{
-	unsigned char *p = skb_push(skb, 4);
-
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, type);
-	
-	return 4;
-}
-
-static int
-isdn_ciscohdlck_open(isdn_net_local *lp)
-{
-	lp->inl_priv = kmalloc(sizeof(struct inl_cisco), GFP_KERNEL);
-	if (!lp->inl_priv)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static void
-isdn_ciscohdlck_close(isdn_net_local *lp)
-{
-	kfree(lp->inl_priv);
-}
-
-struct isdn_netif_ops isdn_ciscohdlck_ops = {
-	.hard_start_xmit     = isdn_net_start_xmit,
-	.hard_header         = isdn_ciscohdlck_header,
-	.do_ioctl            = isdn_ciscohdlck_dev_ioctl,
-	.flags               = IFF_NOARP | IFF_POINTOPOINT,
-	.type                = ARPHRD_CISCO,
-	.receive             = isdn_ciscohdlck_receive,
-	.connected           = isdn_ciscohdlck_connected,
-	.disconnected        = isdn_ciscohdlck_disconnected,
-	.open                = isdn_ciscohdlck_open,
-	.close               = isdn_ciscohdlck_close,
-};
--- diff/drivers/isdn/i4l/isdn_ciscohdlck.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ciscohdlck.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,26 +0,0 @@
-/* Linux ISDN subsystem, CISCO HDLC network interfaces
- *
- * Copyright 1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *           2001       by Bjoern A. Zeeb <i4l@zabbadoz.net>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef ISDN_CISCOHDLCK_H
-#define ISDN_CISCOHDLCK_H
-
-extern struct isdn_netif_ops isdn_ciscohdlck_ops;
-
-struct inl_cisco {
-	u32 myseq;             /* local keepalive seq. for Cisco */
-	u32 mineseen;          /* returned keepalive seq. from remote */
-	u32 yourseq;           /* remote keepalive seq. for Cisco  */
-	int keepalive_period;  /* keepalive period */
-	int last_slarp_in;     /* jiffie of last recvd keepalive pkt */
-	char line_state;       /* state of line */
-	char debserint;	       /* debugging flags */
-	struct timer_list timer;
-};
-
-#endif
--- diff/drivers/isdn/i4l/isdn_fsm.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_fsm.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,166 +0,0 @@
-/* Linux ISDN subsystem, finite state machine
- *
- * Author       Karsten Keil
- * Copyright              by Karsten Keil      <keil@isdn4linux.de>
- *              2001-2002 by Kai Germaschewski <kai@germaschewski.name>
- * 
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to    Jan den Ouden
- *              Fritz Elfert
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/isdn/fsm.h>
-
-int
-fsm_new(struct fsm *fsm)
-{
-	int i;
-	int size = sizeof(fsm_fn) * fsm->st_cnt * fsm->ev_cnt;
-
-	fsm->jumpmatrix = kmalloc(size, GFP_KERNEL);
-	if (!fsm->jumpmatrix)
-		return -ENOMEM;
-
-	memset(fsm->jumpmatrix, 0, size);
-
-	for (i = 0; i < fsm->fn_cnt; i++) {
-		if (fsm->fn_tbl[i].st >= fsm->st_cnt || 
-		    fsm->fn_tbl[i].ev >= fsm->ev_cnt) {
-			printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n", i,
-			       fsm->fn_tbl[i].st, fsm->st_cnt, 
-			       fsm->fn_tbl[i].ev, fsm->ev_cnt);
-			continue;
-		}
-		fsm->jumpmatrix[fsm->st_cnt * fsm->fn_tbl[i].ev + fsm->fn_tbl[i].st] = fsm->fn_tbl[i].fn;
-	}
-	return 0;
-}
-
-void
-fsm_free(struct fsm *fsm)
-{
-	kfree(fsm->jumpmatrix);
-}
-
-int
-fsm_event(struct fsm_inst *fi, int event, void *arg)
-{
-	fsm_fn fn;
-
-	if (fi->state >= fi->fsm->st_cnt || 
-	    event >= fi->fsm->ev_cnt) {
-		printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n",
-		       fi->state, fi->fsm->st_cnt,event, 
-		       fi->fsm->ev_cnt);
-		return -EINVAL;
-	}
-	fn = fi->fsm->jumpmatrix[fi->fsm->st_cnt * event + fi->state];
-	if (!fn) {
-		if (fi->debug)
-			fi->printdebug(fi, "State %s Event %s no routine",
-				       fi->fsm->st_str[fi->state],
-				       fi->fsm->ev_str[event]);
-		return -ESRCH;
-	}
-	if (fi->debug)
-		fi->printdebug(fi, "State %s Event %s",
-			       fi->fsm->st_str[fi->state],
-			       fi->fsm->ev_str[event]);
-
-	return fn(fi, event, arg);
-}
-
-void
-fsm_change_state(struct fsm_inst *fi, int newstate)
-{
-	fi->state = newstate;
-	if (fi->debug)
-		fi->printdebug(fi, "ChangeState %s",
-			       fi->fsm->st_str[newstate]);
-}
-
-#if 0
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
-#if FSM_TIMER_DEBUG
-	if (ft->fi->debug)
-		ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
-#endif
-	FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
-	ft->fi = fi;
-	ft->tl.function = (void *) FsmExpireTimer;
-	ft->tl.data = (long) ft;
-#if FSM_TIMER_DEBUG
-	if (ft->fi->debug)
-		ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
-#endif
-	init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if FSM_TIMER_DEBUG
-	if (ft->fi->debug)
-		ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
-#endif
-	del_timer(&ft->tl);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
-	    int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
-	if (ft->fi->debug)
-		ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
-			(long) ft, millisec, where);
-#endif
-
-	if (timer_pending(&ft->tl)) {
-		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
-		ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
-		return -1;
-	}
-	init_timer(&ft->tl);
-	ft->event = event;
-	ft->arg = arg;
-	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
-	add_timer(&ft->tl);
-	return 0;
-}
-
-void
-FsmRestartTimer(struct FsmTimer *ft,
-	    int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
-	if (ft->fi->debug)
-		ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
-			(long) ft, millisec, where);
-#endif
-
-	if (timer_pending(&ft->tl))
-		del_timer(&ft->tl);
-	init_timer(&ft->tl);
-	ft->event = event;
-	ft->arg = arg;
-	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
-	add_timer(&ft->tl);
-}
-#endif
--- diff/drivers/isdn/i4l/isdn_net_lib.c	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_net_lib.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,2342 +0,0 @@
-/* Linux ISDN subsystem, network interface support code
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 
- *                                       guy@traverse.com.au
- * Outgoing calls - looks for a 'V' in first char of dialed number
- * Incoming calls - checks first character of eaz as follows:
- *   Numeric - accept DATA only - original functionality
- *   'V'     - accept VOICE (DOV) only
- *   'B'     - accept BOTH DATA and DOV types
- *
- */
-
-/* Locking works as follows: 
- *
- * The configuration of isdn_net_devs works via ioctl on
- * /dev/isdnctrl (for legacy reasons).
- * All configuration accesses are globally serialized by means of
- * the global semaphore &sem.
- * 
- * All other uses of isdn_net_dev will only happen when the corresponding
- * struct net_device has been opened. So in the non-config code we can
- * rely on the config data not changing under us.
- *
- * To achieve this, in the "writing" ioctls, that is those which may change
- * data, additionally grep the rtnl semaphore and check to make sure
- * that the net_device has not been openend ("netif_running()")
- *
- * isdn_net_dev's are added to the global list "isdn_net_devs" in the
- * configuration ioctls, so accesses to that list are protected by
- * &sem as well.
- *
- * Incoming calls are signalled in IRQ context, so we cannot take &sem
- * while walking the list of devices. To handle this, we put devices
- * onto a "running" list, which is protected by a spin lock and can thus
- * be traversed in IRQ context. If a matching isdn_net_dev is found,
- * it's ref count shall be incremented, to make sure no racing
- * net_device::close() can take it away under us. 
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/capability.h>
-#include <linux/rtnetlink.h>
-#include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_net.h"
-#include "isdn_ppp.h"
-#include "isdn_ciscohdlck.h"
-#include "isdn_concap.h"
-
-#define ISDN_NET_TX_TIMEOUT (20*HZ) 
-
-/* All of this configuration code is globally serialized */
-
-static DECLARE_MUTEX(sem);
-LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */ // FIXME static
-
-/* Reference counting for net devices (they work on isdn_net_local *,
- * but count references to the related isdn_net_dev's as well.
- * Basic rule: When state of isdn_net_dev changes from ST_NULL -> sth,
- * get a reference, when it changes back to ST_NULL, put it
- */ 
-
-static inline void
-lp_get(isdn_net_local *lp)
-{
-	if (atomic_read(&lp->refcnt) < 1)
-		isdn_BUG();
-
-	atomic_inc(&lp->refcnt);
-}
-
-static inline void
-lp_put(isdn_net_local *lp)
-{
-	atomic_dec(&lp->refcnt);
-
-	/* the last reference, the list should always remain */
-	if (atomic_read(&lp->refcnt) < 1)
-		isdn_BUG();
-}
-
-static int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg);
-static void isdn_net_tasklet(unsigned long data);
-static void isdn_net_dial_timer(unsigned long data);
-static int isdn_init_netif(struct net_device *ndev);
-static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...);
-static int isdn_net_dial(isdn_net_dev *idev);
-static int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c);
-
-static struct fsm isdn_net_fsm;
-
-enum {
-	ST_NULL,
-	ST_OUT_BOUND,
-	ST_OUT_WAIT_DCONN,
-	ST_OUT_WAIT_BCONN,
-	ST_IN_WAIT_DCONN,
-	ST_IN_WAIT_BCONN,
-	ST_ACTIVE,
-	ST_WAIT_DHUP,
-	ST_WAIT_BEFORE_CB,
-	ST_OUT_DIAL_WAIT,
-};
-
-static char *isdn_net_st_str[] = {
-	"ST_NULL",
-	"ST_OUT_BOUND",
-	"ST_OUT_WAIT_DCONN",
-	"ST_OUT_WAIT_BCONN",
-	"ST_IN_WAIT_DCONN",
-	"ST_IN_WAIT_BCONN",
-	"ST_ACTIVE",
-	"ST_WAIT_DHUP",
-	"ST_WAIT_BEFORE_CB",
-	"ST_OUT_DIAL_WAIT",
-};
-
-enum {
-	EV_NET_TIMER_INCOMING,
-	EV_NET_TIMER_DIAL,
-	EV_NET_TIMER_DIAL_WAIT,
-	EV_NET_TIMER_CB_OUT,
-	EV_NET_TIMER_CB_IN,
-	EV_NET_TIMER_HUP,
-	EV_NET_STAT_DCONN,
-	EV_NET_STAT_BCONN,
-	EV_NET_STAT_DHUP,
-	EV_NET_STAT_BHUP,
-	EV_NET_STAT_CINF,
-	EV_NET_STAT_BSENT,
-	EV_NET_DO_DIAL,
-	EV_NET_DO_CALLBACK,
-	EV_NET_DO_ACCEPT,
-};
-
-static char *isdn_net_ev_str[] = {
-	"EV_NET_TIMER_INCOMING",
-	"EV_NET_TIMER_DIAL",
-	"EV_NET_TIMER_DIAL_WAIT",
-	"EV_NET_TIMER_CB_OUT",
-	"EV_NET_TIMER_CB_IN",
-	"EV_NET_TIMER_HUP",
-	"EV_NET_STAT_DCONN",
-	"EV_NET_STAT_BCONN",
-	"EV_NET_STAT_DHUP",
-	"EV_NET_STAT_BHUP",
-	"EV_NET_STAT_CINF",
-	"EV_NET_STAT_BSENT",
-	"EV_NET_DO_DIAL",
-	"EV_NET_DO_CALLBACK",
-	"EV_NET_DO_ACCEPT",
-};
-
-/* Definitions for hupflags: */
-
-#define ISDN_CHARGEHUP   4      /* We want to use the charge mechanism      */
-#define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
-#define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
-
-enum {
-	ST_CHARGE_NULL,
-	ST_CHARGE_GOT_CINF,  /* got a first charge info */
-	ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */
-};
-
-/* ====================================================================== */
-/* Registration of ISDN network interface types                           */
-/* ====================================================================== */
-
-static struct isdn_netif_ops *isdn_netif_ops[ISDN_NET_ENCAP_NR];
-
-int
-register_isdn_netif(int encap, struct isdn_netif_ops *ops)
-{
-	if (encap < 0 || encap >= ISDN_NET_ENCAP_NR)
-		return -EINVAL;
-
-	if (isdn_netif_ops[encap])
-		return -EBUSY;
-
-	isdn_netif_ops[encap] = ops;
-
-	return 0;
-}
-
-/* ====================================================================== */
-/* Helpers                                                                */
-/* ====================================================================== */
-
-/* Search list of net-interfaces for an interface with given name. */
-
-static isdn_net_dev *
-isdn_net_findif(char *name)
-{
-	isdn_net_dev *idev;
-
-	list_for_each_entry(idev, &isdn_net_devs, global_list) {
-		if (!strcmp(idev->name, name))
-			return idev;
-	}
-	return NULL;
-}
-
-/* Set up a certain encapsulation */
-
-static int
-isdn_net_set_encap(isdn_net_local *lp, int encap)
-{
-	int retval = 0;
-
-	if (lp->p_encap == encap){
-		/* nothing to do */
-		retval = 0;
-		goto out;
-	}
-	if (netif_running(&lp->dev)) {
-		retval = -EBUSY;
-		goto out;
-	}
-	if (lp->ops && lp->ops->cleanup)
-		lp->ops->cleanup(lp);
-
-	if (encap < 0 || encap >= ISDN_NET_ENCAP_NR ||
-	    !isdn_netif_ops[encap]) {
-		lp->p_encap = -1;
-		lp->ops = NULL;
-		retval = -EINVAL;
-		goto out;
-	}
-
-	lp->p_encap = encap;
-	lp->ops = isdn_netif_ops[encap];
-
-	lp->dev.hard_start_xmit     = lp->ops->hard_start_xmit;
-	lp->dev.hard_header         = lp->ops->hard_header;
-	lp->dev.do_ioctl            = lp->ops->do_ioctl;
-	lp->dev.flags               = lp->ops->flags;
-	lp->dev.type                = lp->ops->type;
-	lp->dev.addr_len            = lp->ops->addr_len;
-	if (lp->ops->init)
-		retval = lp->ops->init(lp);
-
-	if (retval != 0) {
-		lp->p_encap = -1;
-		lp->ops = NULL;
-	}
- out:
-	return retval;
-}
-
-static int
-isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
-{
-	isdn_net_local *mlp = idev->mlp;
-	int retval;
-	int drvidx = -1;
-	int chidx = -1;
-	char drvid[25];
-
-	strlcpy(drvid, cfg->drvid, sizeof(drvid));
-
-	if (cfg->exclusive && !strlen(drvid)) {
-		/* If we want to bind exclusively, need to specify drv/chan */
-		retval = -ENODEV;
-		goto out;
-	}
-	if (strlen(drvid)) {
-		/* A bind has been requested ... */
-		char *c = strchr(drvid, ',');
-		if (!c) {
-			retval = -ENODEV;
-			goto out;
-		}
-		/* The channel-number is appended to the driver-Id with a comma */
-		*c = 0;
-		chidx = simple_strtol(c + 1, NULL, 10);
-		drvidx = isdn_drv_lookup(drvid);
-		if (drvidx == -1 || chidx == -1) {
-			/* Either driver-Id or channel-number invalid */
-			retval = -ENODEV;
-			goto out;
-		}
-	}
-	if (cfg->exclusive == !!idev->exclusive &&
-	    drvidx == idev->pre_device && chidx == idev->pre_channel) {
-		/* no change */
-		retval = 0;
-		goto out;
-	}
-	if (idev->exclusive) {
-		isdn_slot_free(idev->exclusive);
-		idev->exclusive = NULL;
-	}
-	if (cfg->exclusive) {
-		/* If binding is exclusive, try to grab the channel */
-		idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET | ISDN_USAGE_EXCLUSIVE, 
-						     mlp->l2_proto, mlp->l3_proto, drvidx, chidx, cfg->eaz);
-		if (!idev->exclusive) {
-			/* Grab failed, because desired channel is in use */
-			retval = -EBUSY;
-			goto out;
-		}
-	}
-	idev->pre_device = drvidx;
-	idev->pre_channel = chidx;
-	retval = 0;
- out:
-	return retval;
-}
-
-/*
- * Delete all phone-numbers of an interface.
- */
-static void
-isdn_net_rmallphone(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	struct isdn_net_phone *n;
-	int i;
-
-	for (i = 0; i < 2; i++) {
-		while (!list_empty(&mlp->phone[i])) {
-			n = list_entry(mlp->phone[i].next, struct isdn_net_phone, list);
-			list_del(&n->list);
-			kfree(n);
-		}
-	}
-}
-
-/* ====================================================================== */
-/* /dev/isdnctrl net ioctl interface                                      */
-/* ====================================================================== */
-
-/*
- * Allocate a new network-interface and initialize its data structures
- */
-static int
-isdn_net_addif(char *name, isdn_net_local *mlp)
-{
-	int retval;
-	struct net_device *dev = NULL;
-	isdn_net_dev *idev;
-
-	/* Avoid creating an existing interface */
-	if (isdn_net_findif(name))
-		return -EEXIST;
-
-	idev = kmalloc(sizeof(*idev), GFP_KERNEL);
-	if (!idev)
-		return -ENOMEM;
-
-	memset(idev, 0, sizeof(*idev));
-	strcpy(idev->name, name);
-
-	tasklet_init(&idev->tlet, isdn_net_tasklet, (unsigned long) idev);
-	skb_queue_head_init(&idev->super_tx_queue);
-
-	idev->isdn_slot = NULL;
-	idev->pre_device = -1;
-	idev->pre_channel = -1;
-	idev->exclusive = NULL;
-
-	idev->pppbind = -1;
-
-	init_timer(&idev->dial_timer);
-	idev->dial_timer.data = (unsigned long) idev;
-	idev->dial_timer.function = isdn_net_dial_timer;
-
-	idev->fi.fsm = &isdn_net_fsm;
-	idev->fi.state = ST_NULL;
-	idev->fi.debug = 1;
-	idev->fi.userdata = idev;
-	idev->fi.printdebug = isdn_net_dev_debug;
-
-	if (!mlp) {
-		/* Device shall be a master */
-		mlp = kmalloc(sizeof(*mlp), GFP_KERNEL);
-		if (!mlp)
-			return -ENOMEM;
-		
-		memset(mlp, 0, sizeof(*mlp));
-
-		mlp->magic = ISDN_NET_MAGIC;
-		INIT_LIST_HEAD(&mlp->slaves);
-		INIT_LIST_HEAD(&mlp->online);
-		spin_lock_init(&mlp->xmit_lock);
-
-		mlp->p_encap = -1;
-		isdn_net_set_encap(mlp, ISDN_NET_ENCAP_RAWIP);
-
-		mlp->l2_proto = ISDN_PROTO_L2_X75I;
-		mlp->l3_proto = ISDN_PROTO_L3_TRANS;
-		mlp->triggercps = 6000;
-		mlp->slavedelay = 10 * HZ;
-		mlp->hupflags = ISDN_INHUP;
-		mlp->onhtime = 10;
-		mlp->dialmax = 1;
-		mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL | ISDN_NET_SECURE;
-		mlp->cbdelay = 5 * HZ;	   /* Wait 5 secs before call-back  */
-		mlp->dialtimeout = 60 * HZ;/* Wait 1 min for connection     */
-		mlp->dialwait = 5 * HZ;    /* Wait 5 sec. after failed dial */
-		INIT_LIST_HEAD(&mlp->phone[0]);
-		INIT_LIST_HEAD(&mlp->phone[1]);
-		dev = &mlp->dev;
-	}
-	idev->mlp = mlp;
-	list_add_tail(&idev->slaves, &mlp->slaves);
-
-	if (dev) {
-		strcpy(dev->name, name);
-		dev->priv = mlp;
-		dev->init = isdn_init_netif;
-		SET_MODULE_OWNER(dev);
-		retval = register_netdev(dev);
-		if (retval) {
-			kfree(mlp);
-			kfree(idev);
-			return retval;
-		}
-	}
-	list_add(&idev->global_list, &isdn_net_devs);
-
-	return 0;
-}
-
-/*
- * Add a new slave interface to an existing one
- */
-static int
-isdn_net_addslave(char *parm)
-{
-	char *p = strchr(parm, ',');
-	isdn_net_dev *idev;
-	isdn_net_local *mlp;
-	int retval;
-
-	/* get slave name */
-	if (!p || !p[1])
-		return -EINVAL;
-
-	*p++ = 0;
-
-	/* find master */
-	idev = isdn_net_findif(parm);
-	if (!idev)
-		return -ESRCH;
-
-	mlp = idev->mlp;
-
-	rtnl_lock();
-
-	if (netif_running(&mlp->dev)) {
-		retval = -EBUSY;
-		goto out;
-	}
-	retval = isdn_net_addif(p, mlp);
- out:	
-	rtnl_unlock();
-	return retval;
-}
-
-/*
- * Delete a single network-interface
- */
-static int
-isdn_net_dev_delete(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	int retval;
-
-	rtnl_lock();
-	
-	if (netif_running(&mlp->dev)) {
-		retval = -EBUSY;
-		goto unlock;
-	}
-	isdn_net_set_encap(mlp, -1);
-	isdn_net_rmallphone(idev);
-
-	if (idev->exclusive)
-		isdn_slot_free(idev->exclusive);
-
-	list_del(&idev->slaves);
-	
-	rtnl_unlock();
-
-	if (list_empty(&mlp->slaves)) {
-		unregister_netdev(&mlp->dev);
-		kfree(mlp);
-	}
-
-	list_del(&idev->global_list);
-	kfree(idev);
-	return 0;
-
- unlock:
-	rtnl_unlock();
-	return retval;
-}
-
-/*
- * Delete a single network-interface
- */
-static int
-isdn_net_delif(char *name)
-{
-	/* FIXME: For compatibility, if a master isdn_net_dev is rm'ed,
-	 * kill all slaves, too */
-
-	isdn_net_dev *idev = isdn_net_findif(name);
-
-	if (!idev)
-		return -ENODEV;
-
-	return isdn_net_dev_delete(idev);
-}
-
-/*
- * Set interface-parameters.
- * Always set all parameters, so the user-level application is responsible
- * for not overwriting existing setups. It has to get the current
- * setup first, if only selected parameters are to be changed.
- */
-static int
-isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
-{
-	isdn_net_dev *idev = isdn_net_findif(cfg->name);
-	isdn_net_local *mlp;
-	int retval;
-
-	if (!idev)
-		return -ENODEV;
-
-	mlp = idev->mlp;
-
-	rtnl_lock();
-
-	if (netif_running(&mlp->dev)) {
-		retval = -EBUSY;
-		goto out;
-	}
-
-	retval = isdn_net_set_encap(mlp, cfg->p_encap);
-	if (retval)
-		goto out;
-
-	retval = isdn_net_bind(idev, cfg);
-	if (retval)
-		goto out;
-
-	strlcpy(mlp->msn, cfg->eaz, sizeof(mlp->msn));
-	mlp->onhtime = cfg->onhtime;
-	idev->charge = cfg->charge;
-	mlp->l2_proto = cfg->l2_proto;
-	mlp->l3_proto = cfg->l3_proto;
-	mlp->cbdelay = cfg->cbdelay * HZ / 5;
-	mlp->dialmax = cfg->dialmax;
-	mlp->triggercps = cfg->triggercps;
-	mlp->slavedelay = cfg->slavedelay * HZ;
-	idev->pppbind = cfg->pppbind;
-	mlp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
-	mlp->dialwait = cfg->dialwait * HZ;
-	if (cfg->secure)
-		mlp->flags |= ISDN_NET_SECURE;
-	else
-		mlp->flags &= ~ISDN_NET_SECURE;
-	if (cfg->cbhup)
-		mlp->flags |= ISDN_NET_CBHUP;
-	else
-		mlp->flags &= ~ISDN_NET_CBHUP;
-	switch (cfg->callback) {
-	case 0:
-		mlp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
-		break;
-	case 1:
-		mlp->flags |= ISDN_NET_CALLBACK;
-		mlp->flags &= ~ISDN_NET_CBOUT;
-		break;
-	case 2:
-		mlp->flags |= ISDN_NET_CBOUT;
-		mlp->flags &= ~ISDN_NET_CALLBACK;
-		break;
-	}
-	mlp->flags &= ~ISDN_NET_DIALMODE_MASK;	/* first all bits off */
-	if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
-		retval = -EINVAL;
-		goto out;
-	}
-
-	mlp->flags |= cfg->dialmode;  /* turn on selected bits */
-	if (mlp->flags & ISDN_NET_DM_OFF)
-		isdn_net_hangup(idev);
-
-	if (cfg->chargehup)
-		mlp->hupflags |= ISDN_CHARGEHUP;
-	else
-		mlp->hupflags &= ~ISDN_CHARGEHUP;
-
-	if (cfg->ihup)
-		mlp->hupflags |= ISDN_INHUP;
-	else
-		mlp->hupflags &= ~ISDN_INHUP;
-
-	if (cfg->chargeint > 10) {
-		idev->chargeint = cfg->chargeint * HZ;
-		idev->charge_state = ST_CHARGE_HAVE_CINT;
-		mlp->hupflags |= ISDN_MANCHARGE;
-	}
-	retval = 0;
-
- out:
-	rtnl_unlock();
-	
-	return retval;
-}
-
-/*
- * Perform get-interface-parameters.ioctl
- */
-static int
-isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
-{
-	isdn_net_dev *idev = isdn_net_findif(cfg->name);
-	isdn_net_local *mlp;
-		
-	if (!idev)
-		return -ENODEV;
-
-	mlp = idev->mlp;
-
-	strcpy(cfg->eaz, mlp->msn);
-	cfg->exclusive = !!idev->exclusive;
-	if (idev->pre_device >= 0) {
-		sprintf(cfg->drvid, "%s,%d", isdn_drv_drvid(idev->pre_device),
-			idev->pre_channel);
-	} else {
-		cfg->drvid[0] = '\0';
-	}
-	cfg->onhtime = mlp->onhtime;
-	cfg->charge = idev->charge;
-	cfg->l2_proto = mlp->l2_proto;
-	cfg->l3_proto = mlp->l3_proto;
-	cfg->p_encap = mlp->p_encap;
-	cfg->secure = (mlp->flags & ISDN_NET_SECURE) ? 1 : 0;
-	cfg->callback = 0;
-	if (mlp->flags & ISDN_NET_CALLBACK)
-		cfg->callback = 1;
-	if (mlp->flags & ISDN_NET_CBOUT)
-		cfg->callback = 2;
-	cfg->cbhup = (mlp->flags & ISDN_NET_CBHUP) ? 1 : 0;
-	cfg->dialmode = mlp->flags & ISDN_NET_DIALMODE_MASK;
-	cfg->chargehup = (mlp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
-	cfg->ihup = (mlp->hupflags & ISDN_INHUP) ? 1 : 0;
-	cfg->cbdelay = mlp->cbdelay * 5 / HZ;
-	cfg->dialmax = mlp->dialmax;
-	cfg->triggercps = mlp->triggercps;
-	cfg->slavedelay = mlp->slavedelay / HZ;
-	cfg->chargeint = (mlp->hupflags & ISDN_CHARGEHUP) ?
-		(idev->chargeint / HZ) : 0;
-	cfg->pppbind = idev->pppbind;
-	cfg->dialtimeout = mlp->dialtimeout >= 0 ? mlp->dialtimeout / HZ : -1;
-	cfg->dialwait = mlp->dialwait / HZ;
-
-	if (idev->slaves.next != &mlp->slaves)
-		strcpy(cfg->slave, list_entry(idev->slaves.next, isdn_net_dev, slaves)->name);
-	else
-		cfg->slave[0] = '\0';
-	if (strcmp(mlp->dev.name, idev->name))
-		strcpy(cfg->master, mlp->dev.name);
-	else
-		cfg->master[0] = '\0';
-
-	return 0;
-}
-
-/*
- * Add a phone-number to an interface.
- */
-static int
-isdn_net_addphone(isdn_net_ioctl_phone *phone)
-{
-	isdn_net_dev *idev = isdn_net_findif(phone->name);
-	struct isdn_net_phone *n;
-	int retval = 0;
-
-	if (!idev)
-		return -ENODEV;
-
-	rtnl_lock();
-
-	if (netif_running(&idev->mlp->dev)) {
-		retval = -EBUSY;
-		goto out;
-	}
-	n = kmalloc(sizeof(*n), GFP_KERNEL);
-	if (!n) {
-		retval = -ENOMEM;
-		goto out;
-	}
-	strcpy(n->num, phone->phone);
-	list_add_tail(&n->list, &idev->mlp->phone[phone->outgoing & 1]);
-
- out:
-	rtnl_unlock();
-	return retval;
-}
-
-/*
- * Delete a phone-number from an interface.
- */
-static int
-isdn_net_delphone(isdn_net_ioctl_phone *phone)
-{
-	isdn_net_dev *idev = isdn_net_findif(phone->name);
-	struct isdn_net_phone *n;
-	int retval;
-
-	if (!idev)
-		return -ENODEV;
-
-	rtnl_lock();
-
-	if (netif_running(&idev->mlp->dev)) {
-		retval = -EBUSY;
-		goto out;
-	}
-	retval = -EINVAL;
-	list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) {
-		if (!strcmp(n->num, phone->phone)) {
-			list_del(&n->list);
-			kfree(n);
-			retval = 0;
-			break;
-		}
-	}
- out:
-	rtnl_unlock();
-	return retval;
-}
-
-/*
- * Copy a string of all phone-numbers of an interface to user space.
- */
-static int
-isdn_net_getphone(isdn_net_ioctl_phone * phone, char *phones)
-{
-	isdn_net_dev *idev = isdn_net_findif(phone->name);
-	u_int count = 0;
-	char *buf = (char *)__get_free_page(GFP_KERNEL);
-	struct isdn_net_phone *n;
-
-	if (!buf)
-		return -ENOMEM;
-
-	if (!idev) {
-		count = -ENODEV;
-		goto free;
-	}
-	list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) {
-		strcpy(&buf[count], n->num);
-		count += strlen(n->num);
-		buf[count++] = ' ';
-		if (count > PAGE_SIZE - ISDN_MSNLEN - 1)
-			break;
-	}
-	if (!count) /* list was empty? */
-		count++;
-
-	buf[count-1] = 0;
-
-	if (copy_to_user(phones, buf, count))
-		count = -EFAULT;
-
- free:
-	free_page((unsigned long)buf);
-	return count;
-}
-
-/*
- * Force a net-interface to dial out.
- */
-static int
-isdn_net_dial_out(char *name)
-{
-	isdn_net_dev *idev = isdn_net_findif(name);
-
-	if (!idev)
-		return -ENODEV;
-
-	return isdn_net_dial(idev);
-}
-
-static int
-__isdn_net_dial_slave(isdn_net_local *mlp)
-{
-	isdn_net_dev *idev;
-
-	list_for_each_entry(idev, &mlp->slaves, slaves) {
-		if (isdn_net_dial(idev) == 0)
-			return 0;
-	}
-	return -EBUSY;
-}
-
-static int
-isdn_net_dial_slave(char *name)
-{
-	isdn_net_dev *idev = isdn_net_findif(name);
-
-	if (!idev)
-		return -ENODEV;
-
-	return __isdn_net_dial_slave(idev->mlp);
-}
-
-/*
- * Force a hangup of a network-interface.
- */
-static int
-isdn_net_force_hangup(char *name) // FIXME rename?
-{
-	isdn_net_dev *idev = isdn_net_findif(name);
-
-	if (!idev)
-		return -ENODEV;
-
-	if (idev->isdn_slot == NULL)
-		return -ENOTCONN;
-
-	isdn_net_hangup(idev);
-	return 0;
-}
-
-/*
- * Copy a string containing the peer's phone number of a connected interface
- * to user space.
- */
-static int
-isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
-{
-	isdn_net_dev *idev = isdn_net_findif(phone->name);
-	struct isdn_slot *slot;
-
-	if (!idev)
-		return -ENODEV;
-
-	if (idev->fi.state != ST_ACTIVE)
-		return -ENOTCONN;
-
-	slot = idev->isdn_slot;
-
-	strlcpy(phone->phone, slot->num, sizeof(phone->phone));
-	phone->outgoing = USG_OUTGOING(slot->usage);
-
-	if (copy_to_user(peer, phone, sizeof(*peer)))
-		return -EFAULT;
-
-	return 0;
-}
-
-/*
- * ioctl on /dev/isdnctrl, used to configure ISDN net interfaces 
- */
-int
-isdn_net_ioctl(struct inode *ino, struct file *file, uint cmd, ulong arg)
-{
-	/* Save stack space */
-	union {
-		char name[10];
-		char bname[20];
-		isdn_net_ioctl_phone phone;
-		isdn_net_ioctl_cfg cfg;
-	} iocpar;
-	int retval;
-
-#define name  iocpar.name
-#define bname iocpar.bname
-#define phone iocpar.phone
-#define cfg   iocpar.cfg
-
-	name[sizeof(name)-1] = 0;
-	bname[sizeof(bname)-1] = 0;
-
-	down(&sem);
-	
-	switch (cmd) {
-	case IIOCNETAIF: /* add an interface */
-		if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_addif(name, NULL);
-		break;
-	case IIOCNETASL: /* add slave to an interface */
-		if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_addslave(bname);
-		break;
-	case IIOCNETDIF: /* delete an interface */
-		if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_delif(name);
-		break;
-	case IIOCNETSCF: /* set config */
-		if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_setcfg(&cfg);
-		break;
-	case IIOCNETGCF: /* get config */
-		if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_getcfg(&cfg);
-		if (retval)
-			break;
-		if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
-			retval = -EFAULT;
-		break;
-	case IIOCNETANM: /* add a phone number */
-		if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_addphone(&phone);
-		break;
-	case IIOCNETGNM: /* get list of phone numbers */
-		if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_getphone(&phone, (char *) arg);
-		break;
-	case IIOCNETDNM: /* delete a phone number */
-		if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_delphone(&phone);
-		break;
-	case IIOCNETDIL: /* trigger dial-out */
-		if (copy_from_user(name, (char *) arg, sizeof(name))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_dial_out(name);
-		break;
-	case IIOCNETHUP: /* hangup */
-		if (copy_from_user(name, (char *) arg, sizeof(name))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_force_hangup(name);
-		break;
-	case IIOCNETGPN: /* Get peer phone number of a connected interface */
-		if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
-			retval = -EFAULT;
-		}
-		retval = isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
-		break;
-	case IIOCNETALN: /* Add link */
-		if (copy_from_user(name, (char *) arg, sizeof(name))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_dial_slave(name);
-		break;
-	case IIOCNETDLN: /* Delete link */
-		if (copy_from_user(name, (char *) arg, sizeof(name))) {
-			retval = -EFAULT;
-			break;
-		}
-		retval = isdn_net_force_hangup(name);
-		break;
-	default:
-		retval = -ENOTTY;
-	}
-	up(&sem);
-	return retval;
-
-#undef name
-#undef bname
-#undef iocts
-#undef phone
-#undef cfg
-}
-
-/*
- * Hang up all network-interfaces
- */
-void
-isdn_net_hangup_all(void)
-{
-	isdn_net_dev *idev;
-
-	down(&sem);
-
-	list_for_each_entry(idev, &isdn_net_devs, global_list)
-		isdn_net_hangup(idev);
-
-	up(&sem);
-}
-
-/*
- * Remove all network-interfaces
- */
-void
-isdn_net_cleanup(void)
-{
-	isdn_net_dev *idev;
-	int retval;
-
-	down(&sem);
-
-	while (!list_empty(&isdn_net_devs)) {
-		idev = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
-		retval = isdn_net_dev_delete(idev);
-		/* can only fail if an interface is still running.
-		 * In this case, an elevated module use count should
-		 * have prevented this function from being called in
-		 * the first place */
-		if (retval)
-			isdn_BUG();
-	}
-	up(&sem);
-}
-
-/* ====================================================================== */
-/* interface to network layer                                             */
-/* ====================================================================== */
-
-static spinlock_t running_devs_lock = SPIN_LOCK_UNLOCKED;
-static LIST_HEAD(running_devs);
-
-/* 
- * Open/initialize the board.
- */
-static int
-isdn_net_open(struct net_device *dev)
-{
-	isdn_net_local *lp = dev->priv;
-	unsigned long flags;
-	int retval = 0;
-
-	if (!lp->ops)
-		return -ENODEV;
-
-	if (lp->ops->open)
-		retval = lp->ops->open(lp);
-
-	if (retval)
-		return retval;
-	
-	netif_start_queue(dev);
-
-	atomic_set(&lp->refcnt, 1);
-	spin_lock_irqsave(&running_devs_lock, flags);
-	list_add(&lp->running_devs, &running_devs);
-	spin_unlock_irqrestore(&running_devs_lock, flags);
-
-	return 0;
-}
-
-/*
- * Shutdown a net-interface.
- */
-static int
-isdn_net_close(struct net_device *dev)
-{
-	isdn_net_local *lp = dev->priv;
-	isdn_net_dev *sdev;
-	struct list_head *l, *n;
-	unsigned long flags;
-
-	if (lp->ops->close)
-		lp->ops->close(lp);
-
-	netif_stop_queue(dev);
-
-	list_for_each_safe(l, n, &lp->slaves) {
-		sdev = list_entry(l, isdn_net_dev, slaves);
-		isdn_net_hangup(sdev);
-	}
-	/* The hangup will make the refcnt drop back to
-	 * 1 (referenced by list only) soon. */
-	spin_lock_irqsave(&running_devs_lock, flags);
-	while (atomic_read(&lp->refcnt) != 1) {
-		spin_unlock_irqrestore(&running_devs_lock, flags);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/10);
-		spin_lock_irqsave(&running_devs_lock, flags);
-	}
-	/* We have the only reference and list lock, so
-	 * nobody can get another reference. */
-	list_del(&lp->running_devs);
-	spin_unlock_irqrestore(&running_devs_lock, flags);
-
-	return 0;
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *
-isdn_net_get_stats(struct net_device *dev)
-{
-	isdn_net_local *lp = dev->priv;
-
-	return &lp->stats;
-}
-
-/*
- * Transmit timeout
- */
-static void
-isdn_net_tx_timeout(struct net_device *dev)
-{
-	printk(KERN_WARNING "isdn_tx_timeout dev %s\n", dev->name);
-
-	netif_wake_queue(dev);
-}
-
-/*
- * Interface-setup. (just after registering a new interface)
- */
-static int
-isdn_init_netif(struct net_device *ndev)
-{
-	/* Setup the generic properties */
-
-	ndev->mtu = 1500;
-	ndev->tx_queue_len = 10;
-	ndev->open = &isdn_net_open;
-	ndev->hard_header_len = ETH_HLEN + isdn_hard_header_len();
-	ndev->stop = &isdn_net_close;
-	ndev->get_stats = &isdn_net_get_stats;
-	ndev->tx_timeout = isdn_net_tx_timeout;
-	ndev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
-
-	return 0;
-}
-
-/* ====================================================================== */
-/* call control state machine                                             */
-/* ====================================================================== */
-
-// FIXME
-static int
-isdn_net_is_connected(isdn_net_dev *idev)
-{
-	return idev->fi.state == ST_ACTIVE;
-}
-
-static void
-isdn_net_dial_timer(unsigned long data)
-{
-	isdn_net_dev *idev = (isdn_net_dev *) data;
-
-	isdn_net_handle_event(idev, idev->dial_event, NULL);
-}
-
-/*
- * Unbind a net-interface
- */
-static void
-isdn_net_unbind_channel(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-
-	if (idev->isdn_slot == NULL) {
-		isdn_BUG();
-		return;
-	}
-
-	if (mlp->ops->unbind)
-		mlp->ops->unbind(idev);
-
-	idev->isdn_slot->priv = NULL;
-	idev->isdn_slot->event_cb = NULL;
-
-	skb_queue_purge(&idev->super_tx_queue);
-
-	if (idev->isdn_slot != idev->exclusive)
-		isdn_slot_free(idev->isdn_slot);
-
-	idev->isdn_slot = NULL;
-
-	if (idev->fi.state != ST_NULL) {
-		lp_put(mlp);
-		fsm_change_state(&idev->fi, ST_NULL);
-	}
-}
-
-static int isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg);
-
-/*
- * Assign an ISDN-channel to a net-interface
- */
-static int
-isdn_net_bind_channel(isdn_net_dev *idev, struct isdn_slot *slot)
-{
-	isdn_net_local *mlp = idev->mlp;
-	int retval = 0;
-
-	if (mlp->ops->bind)
-		retval = mlp->ops->bind(idev);
-
-	if (retval < 0)
-		goto out;
-
-	idev->isdn_slot = slot;
-	slot->priv = idev;
-	slot->event_cb = isdn_net_event_callback;
-	slot->usage |= ISDN_USAGE_NET;
-
- out:
-	return retval;
-}
-
-static int
-isdn_net_dial(isdn_net_dev *idev)
-{
-	int retval;
-
-	lp_get(idev->mlp);
-	retval = fsm_event(&idev->fi, EV_NET_DO_DIAL, NULL);
-	if (retval == -ESRCH) /* event not handled in this state */
-		retval = -EBUSY;
-
-	if (retval)
-		lp_put(idev->mlp);
-
-	return retval;
-}
-
-static void
-isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
-{
-	u_short proto = ntohs(skb->protocol);
-	
-	printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
-	       dev->name,
-	       (reason != NULL) ? reason : "unknown",
-	       (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
-	
-	dst_link_failure(skb);
-}
-
-/*
- * This is called from certain upper protocol layers (multilink ppp
- * and x25iface encapsulation module) that want to initiate dialing
- * themselves.
- */
-int
-isdn_net_dial_req(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	/* is there a better error code? */
-	if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
-		return -EBUSY;
-
-	return isdn_net_dial(idev);
-}
-
-static void
-isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev)
-{
-	unsigned char *p = skb->nh.raw; /* hopefully, this was set correctly */
-	unsigned short proto = ntohs(skb->protocol);
-	int data_ofs;
-	struct ip_ports {
-		unsigned short source;
-		unsigned short dest;
-	} *ipp;
-	char addinfo[100];
-
-	data_ofs = ((p[0] & 15) * 4);
-	switch (proto) {
-	case ETH_P_IP:
-		switch (p[9]) {
-		case IPPROTO_ICMP:
-			strcpy(addinfo, "ICMP");
-			break;
-		case IPPROTO_TCP:
-		case IPPROTO_UDP:
-			ipp = (struct ip_ports *) (&p[data_ofs]);
-			sprintf(addinfo, "%s, port: %d -> %d",
-				p[9] == IPPROTO_TCP ? "TCP" : "UDP",
-				ntohs(ipp->source), ntohs(ipp->dest));
-			break;
-		default:
-			sprintf(addinfo, "type %d", p[9]);
-		}
-		printk(KERN_INFO
-		       "OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s\n",
-		       
-		       NIPQUAD(*(u32 *)(p + 12)), NIPQUAD(*(u32 *)(p + 16)),
-		       addinfo);
-		break;
-	case ETH_P_ARP:
-		printk(KERN_INFO
-		       "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
-		       NIPQUAD(*(u32 *)(p + 14)), NIPQUAD(*(u32 *)(p + 24)));
-		break;
-	default:
-		printk(KERN_INFO "OPEN: unknown proto %#x\n", proto);
-	}
-}
-
-int
-isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
-{
-	isdn_net_local *mlp = ndev->priv;
-	isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves);
-	int retval;
-
-	if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
-		goto discard;
-
-	retval = isdn_net_dial(idev);
-	if (retval == -ESRCH)
-		goto stop_queue;
-
-	if (retval < 0)
-		goto discard;
-
-	/* Log packet, which triggered dialing */
-	if ((get_isdn_dev())->net_verbose)
-		isdn_net_log_skb(skb, idev);
-
- stop_queue:
-	netif_stop_queue(ndev);
-	return 1;
-
- discard:
-	isdn_net_unreachable(ndev, skb, "dial rejected");
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-static int
-accept_icall(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-	isdn_ctrl cmd;
-	struct isdn_slot *slot = arg;
-
-	isdn_net_bind_channel(idev, slot);
-	
-	idev->outgoing = 0;
-	idev->charge_state = ST_CHARGE_NULL;
-	/* Got incoming call, setup L2 and L3 protocols,
-	 * then wait for D-Channel-connect
-	 */
-	cmd.arg = mlp->l2_proto << 8;
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
-	cmd.arg = mlp->l3_proto << 8;
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTD, &cmd);
-	
-	idev->dial_timer.expires = jiffies + mlp->dialtimeout;
-	idev->dial_event = EV_NET_TIMER_INCOMING;
-	add_timer(&idev->dial_timer);
-	fsm_change_state(&idev->fi, ST_IN_WAIT_DCONN);
-	return 0;
-}
-
-static int
-do_callback(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-
-	printk(KERN_DEBUG "%s: start callback\n", idev->name);
-
-	idev->dial_timer.expires = jiffies + mlp->cbdelay;
-	idev->dial_event = EV_NET_TIMER_CB_IN;
-	add_timer(&idev->dial_timer);
-	fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
-
-	return 0;
-}
-
-static int
-isdn_net_dev_icall(isdn_net_dev *idev, struct isdn_slot *slot,
-		   int si1, char *eaz, char *nr)
-{
-	isdn_net_local *mlp = idev->mlp;
-	struct isdn_net_phone *ph;
-	char *my_eaz;
-	
-	/* check acceptable call types for DOV */
-	dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n",
-		      idev->name, mlp->msn, mlp->flags, idev->fi.state);
-	
-	my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn);
-	if (si1 == 1) { /* it's a DOV call, check if we allow it */
-		if (*my_eaz == 'v' || *my_eaz == 'V' ||
-		    *my_eaz == 'b' || *my_eaz == 'B')
-			my_eaz++; /* skip to allow a match */
-		else
-			return 0; /* no match */
-	} else { /* it's a DATA call, check if we allow it */
-		if (*my_eaz == 'b' || *my_eaz == 'B')
-			my_eaz++; /* skip to allow a match */
-	}
-	/* check called number */
-	switch (isdn_msncmp(eaz, my_eaz)) {
-	case 1: /* no match */
-		return 0;
-	case 2: /* matches so far */
-		return 5;
-	}
-
-	dbg_net_icall("%s: pdev=%d di=%d pch=%d ch = %d\n", idev->name,
-		      idev->pre_device, slot->di, idev->pre_channel, slot->ch);
-	
-	/* check if exclusive */
-	if ((slot->usage & ISDN_USAGE_EXCLUSIVE) &&
-	    (idev->pre_channel != slot->ch || idev->pre_device != slot->di)) {
-		dbg_net_icall("%s: excl check failed\n", idev->name);
-		return 0;
-	}
-	
-	/* check calling number */
-	dbg_net_icall("%s: secure\n", idev->name);
-	if (mlp->flags & ISDN_NET_SECURE) {
-		list_for_each_entry(ph, &mlp->phone[0], list) {
-			if (isdn_msncmp(nr, ph->num) == 0)
-					goto found;
-		}
-		return 0;
-	}
- found:
-	/* check dial mode */
-	if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
-		printk(KERN_INFO "%s: incoming call, stopped -> rejected\n",
-		       idev->name);
-		return 3;
-	}
-	lp_get(mlp);
-	/* check callback */
-	if (mlp->flags & ISDN_NET_CALLBACK) {
-		if (fsm_event(&idev->fi, EV_NET_DO_CALLBACK, NULL)) {
-			lp_put(mlp);
-			return 0;
-		}
-		/* Initiate dialing by returning 2 or 4 */
-		return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4;
-	}
-	printk(KERN_INFO "%s: call from %s -> %s accepted\n",
-	       idev->name, nr, eaz);
-
-	if (fsm_event(&idev->fi, EV_NET_DO_ACCEPT, slot)) {
-		lp_put(mlp);
-		return 0;
-	}
-	return 1; // accepted
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the interface-chain for an appropriate interface.
- * If found, connect the interface to the ISDN-channel and initiate
- * D- and B-Channel-setup. If secure-flag is set, accept only
- * configured phone-numbers. If callback-flag is set, initiate
- * callback-dialing.
- *
- * Return-Value: 0 = No appropriate interface for this call.
- *               1 = Call accepted
- *               2 = Reject call, wait cbdelay, then call back
- *               3 = Reject call
- *               4 = Wait cbdelay, then call back
- *               5 = No appropriate interface for this call,
- *                   would eventually match if CID was longer.
- */
-int
-isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup)
-{
-	isdn_net_local	*lp;
-	isdn_net_dev	*idev;
-	char		*nr, *eaz;
-	unsigned char	si1, si2;
-	int		retval;
-	int		verbose = (get_isdn_dev())->net_verbose;
-	unsigned long	flags;
-
-	/* fix up calling number */
-	if (!setup->phone[0]) {
-		printk(KERN_INFO
-		       "isdn_net: Incoming call without OAD, assuming '0'\n");
-		nr = "0";
-	} else {
-		nr = setup->phone;
-	}
-	/* fix up called number */
-	if (!setup->eazmsn[0]) {
-		printk(KERN_INFO
-		       "isdn_net: Incoming call without CPN, assuming '0'\n");
-		eaz = "0";
-	} else {
-		eaz = setup->eazmsn;
-	}
-	si1 = setup->si1;
-	si2 = setup->si2;
-	if (verbose > 1)
-		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", 
-		       nr, si1, si2, eaz);
-	/* check service indicator */
-        /* Accept DATA and VOICE calls at this stage
-	   local eaz is checked later for allowed call types */
-        if ((si1 != 7) && (si1 != 1)) {
-                if (verbose > 1)
-                        printk(KERN_INFO "isdn_net: "
-			       "Service-Indicator not 1 or 7, ignored\n");
-                return 0;
-        }
-
-	dbg_net_icall("n_fi: di=%d ch=%d usg=%#x\n", slot->di, slot->ch,
-		      slot->usage);
-
-	retval = 0;
-	spin_lock_irqsave(&running_devs_lock, flags);
-	list_for_each_entry(lp, &running_devs, running_devs) {
-		lp_get(lp);
-		spin_unlock_irqrestore(&running_devs_lock, flags);
-
-		list_for_each_entry(idev, &lp->slaves, slaves) {
-			retval = isdn_net_dev_icall(idev, slot, si1, eaz, nr);
-			if (retval > 0)
-				break;
-		}
-
-		spin_lock_irqsave(&running_devs_lock, flags);
-		lp_put(lp);
-		if (retval > 0)
-			break;
-		
-	}
-	spin_unlock_irqrestore(&running_devs_lock, flags);
-	if (!retval) {
-		if (verbose)
-			printk(KERN_INFO "isdn_net: call "
-			       "from %s -> %s ignored\n", nr, eaz);
-	}
-	return retval;
-}
-
-/* ---------------------------------------------------------------------- */
-/* callbacks in the state machine                                         */
-/* ---------------------------------------------------------------------- */
-
-/* Find the idev->dial'th outgoing number. */
-
-static struct isdn_net_phone *
-get_outgoing_phone(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	struct isdn_net_phone *phone;
-	int i = 0;
-
-	list_for_each_entry(phone, &mlp->phone[1], list) {
-		if (i++ == idev->dial)
-			return phone;
-	}
-	return NULL;
-}
-
-static int dialout_next(struct fsm_inst *fi, int pr, void *arg);
-
-/* Initiate dialout. */
-
-static int
-do_dial(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-	struct isdn_slot *slot;
-
-	if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF)
-		return -EPERM;
-
-	if (list_empty(&mlp->phone[1])) /* no number to dial ? */
-		return -EINVAL;
-
-	if (idev->exclusive)
-		slot = idev->exclusive;
-	else
-		slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
-					  mlp->l3_proto, idev->pre_device, 
-					  idev->pre_channel, mlp->msn);
-	if (!slot)
-		return -EAGAIN;
-
-	if (isdn_net_bind_channel(idev, slot) < 0) {
-		/* has freed the slot as well */
-		return -EAGAIN;
-	}
-
-	fsm_change_state(fi, ST_OUT_BOUND);
-
-	idev->dial = 0;
-	idev->dialretry = 0;
-
-	dialout_next(fi, pr, arg);
-	return 0;
-}
-
-/* Try dialing the next number. */
-
-static int
-dialout_next(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-	struct dial_info dial = {
-		.l2_proto = mlp->l2_proto,
-		.l3_proto = mlp->l3_proto,
-		.si1      = 7,
-		.si2      = 0,
-		.msn      = mlp->msn,
-		.phone    = get_outgoing_phone(idev)->num,
-	};
-
-	/* next time, try next number */
-	idev->dial++;
-
-	idev->outgoing = 1;
-	if (idev->chargeint)
-		idev->charge_state = ST_CHARGE_HAVE_CINT;
-	else
-		idev->charge_state = ST_CHARGE_NULL;
-
-	/* For outgoing callback, use cbdelay instead of dialtimeout */
-	if (mlp->cbdelay && (mlp->flags & ISDN_NET_CBOUT)) {
-		idev->dial_timer.expires = jiffies + mlp->cbdelay;
-		idev->dial_event = EV_NET_TIMER_CB_OUT;
-	} else {
-		idev->dial_timer.expires = jiffies + mlp->dialtimeout;
-		idev->dial_event = EV_NET_TIMER_DIAL;
-	}
-	fsm_change_state(&idev->fi, ST_OUT_WAIT_DCONN);
-	add_timer(&idev->dial_timer);
-
-	/* Dial */
-	isdn_slot_dial(idev->isdn_slot, &dial);
-	return 0;
-}
-
-/* If we didn't connect within dialtimeout, we give up for now
- * and wait for dialwait jiffies before trying again.
- */
-static int
-dial_timeout(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-	isdn_ctrl cmd;
-
-	fsm_change_state(&idev->fi, ST_OUT_DIAL_WAIT);
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
-	
-	/* get next phone number */
-	if (!get_outgoing_phone(idev)) {
-		/* otherwise start over at first entry */
-		idev->dial = 0;
-		idev->dialretry++;
-	}
-	if (idev->dialretry >= mlp->dialmax) {
-		isdn_net_hangup(idev);
-		return 0;
-	}
-	idev->dial_event = EV_NET_TIMER_DIAL_WAIT;
-	mod_timer(&idev->dial_timer, jiffies + mlp->dialwait);
-	return 0;
-}
-
-static int
-connect_fail(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-
-	del_timer(&idev->dial_timer);
-	printk(KERN_INFO "%s: connection failed\n", idev->name);
-	isdn_net_unbind_channel(idev);
-	return 0;
-}
-
-static int
-out_dconn(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_ctrl cmd;
-
-	fsm_change_state(&idev->fi, ST_OUT_WAIT_BCONN);
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
-	return 0;
-}
-
-static int
-in_dconn(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_ctrl cmd;
-
-	fsm_change_state(&idev->fi, ST_IN_WAIT_BCONN);
-	isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
-	return 0;
-}
-
-static int
-bconn(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-
-	fsm_change_state(&idev->fi, ST_ACTIVE);
-
-	if (mlp->onhtime) {
-		idev->huptimer = 0;
-		idev->dial_event = EV_NET_TIMER_HUP;
-		mod_timer(&idev->dial_timer, jiffies + HZ);
-	} else {
-		del_timer(&idev->dial_timer);
-	}
-
-	printk(KERN_INFO "%s connected\n", idev->name);
-	/* If first Chargeinfo comes before B-Channel connect,
-	 * we correct the timestamp here.
-	 */
-	idev->chargetime = jiffies;
-	idev->frame_cnt = 0;
-	idev->transcount = 0;
-	idev->cps = 0;
-	idev->last_jiffies = jiffies;
-
-	if (mlp->ops->connected)
-		mlp->ops->connected(idev);
-	else
-		isdn_net_online(idev);
-       
-	return 0;
-}
-
-static int
-bhup(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-
-	del_timer(&idev->dial_timer);
-	if (mlp->ops->disconnected)
-		mlp->ops->disconnected(idev);
-	else 
-		isdn_net_offline(idev);
-
-	printk(KERN_INFO "%s: disconnected\n", idev->name);
-	fsm_change_state(fi, ST_WAIT_DHUP);
-	return 0;
-}
-
-static int
-dhup(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-
-	printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
-	isdn_net_unbind_channel(idev);
-	return 0;
-}
-
-/* Check if it's time for idle hang-up */
-
-static int
-check_hup(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_net_local *mlp = idev->mlp;
-
-	dbg_net_dial("%s: huptimer %d onhtime %d chargetime %ld chargeint %d\n",
-		     idev->name, idev->huptimer, mlp->onhtime, idev->chargetime, idev->chargeint);
-
-	if (idev->huptimer++ <= mlp->onhtime)
-		goto mod_timer;
-
-	if (mlp->hupflags & ISDN_CHARGEHUP &&
-	    idev->charge_state == ST_CHARGE_HAVE_CINT) {
-		if (!time_after(jiffies, idev->chargetime 
-				+ idev->chargeint - 2 * HZ))
-			goto mod_timer;
-	}
-	if (idev->outgoing || mlp->hupflags & ISDN_INHUP) {
-		isdn_net_hangup(idev);
-		return 0;
-	}
- mod_timer:
-	mod_timer(&idev->dial_timer, idev->dial_timer.expires + HZ);
-	return 0;
-}
-
-/* Charge-info from TelCo. */
-
-static int
-got_cinf(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-
-	idev->charge++;
-	switch (idev->charge_state) {
-	case ST_CHARGE_NULL:
-		idev->charge_state = ST_CHARGE_GOT_CINF;
-		break;
-	case ST_CHARGE_GOT_CINF:
-		idev->charge_state = ST_CHARGE_HAVE_CINT;
-		/* fall through */
-	case ST_CHARGE_HAVE_CINT:
-		idev->chargeint = jiffies - idev->chargetime;
-		break;
-	}
-	idev->chargetime = jiffies;
-	dbg_net_dial("%s: got CINF\n", idev->name);
-	return 0;
-}
-
-/* Perform hangup for a net-interface. */
-
-int
-isdn_net_hangup(isdn_net_dev *idev)
-{
-	isdn_ctrl cmd;
-
-	del_timer(&idev->dial_timer);
-
-	printk(KERN_INFO "%s: local hangup\n", idev->name);
-	// FIXME via state machine
-	if (idev->isdn_slot)
-		isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
-	return 1;
-}
-
-static int isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb);
-
-/*
- * Handle status-messages from ISDN-interfacecard.
- * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the low-level driver.
- */
-static int
-isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg)
-{
-	isdn_net_dev *idev = slot->priv;
-
-	if (!idev) {
-		isdn_BUG();
-		return 0;
-	}
-	switch (pr) {
-	case EV_DATA_IND:
-		return isdn_net_rcv_skb(slot, arg);
-	case EV_STAT_DCONN:
-		return fsm_event(&idev->fi, EV_NET_STAT_DCONN, arg);
-	case EV_STAT_BCONN:
-		return fsm_event(&idev->fi, EV_NET_STAT_BCONN, arg);
-	case EV_STAT_BHUP:
-		return fsm_event(&idev->fi, EV_NET_STAT_BHUP, arg);
-	case EV_STAT_DHUP:
-		return fsm_event(&idev->fi, EV_NET_STAT_DHUP, arg);
-	case EV_STAT_CINF:
-		return fsm_event(&idev->fi, EV_NET_STAT_CINF, arg);
-	case EV_STAT_BSENT:
-		return fsm_event(&idev->fi, EV_NET_STAT_BSENT, arg);
-	default:
-		printk("unknown pr %d\n", pr);
-		return 0;
-	}
-}
-
-static int
-isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg)
-{
-	return fsm_event(&idev->fi, pr, arg);
-}
-
-static int
-hang_up(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-
-	isdn_net_hangup(idev);
-	return 0;
-}
-
-static int
-got_bsent(struct fsm_inst *fi, int pr, void *arg)
-{
-	isdn_net_dev *idev = fi->userdata;
-	isdn_ctrl *c = arg;
-	
-	isdn_net_bsent(idev, c);
-	return 0;
-}
-
-static struct fsm_node isdn_net_fn_tbl[] = {
-	{ ST_NULL,           EV_NET_DO_DIAL,         do_dial       },
-	{ ST_NULL,           EV_NET_DO_ACCEPT,       accept_icall  },
-	{ ST_NULL,           EV_NET_DO_CALLBACK,     do_callback   },
-
-	{ ST_OUT_WAIT_DCONN, EV_NET_TIMER_DIAL,      dial_timeout  },
-	{ ST_OUT_WAIT_DCONN, EV_NET_STAT_DCONN,      out_dconn     },
-	{ ST_OUT_WAIT_DCONN, EV_NET_STAT_DHUP,       connect_fail  },
-	{ ST_OUT_WAIT_DCONN, EV_NET_TIMER_CB_OUT,    hang_up       },
-
-	{ ST_OUT_WAIT_BCONN, EV_NET_TIMER_DIAL,      dial_timeout  },
-	{ ST_OUT_WAIT_BCONN, EV_NET_STAT_BCONN,      bconn         },
-	{ ST_OUT_WAIT_BCONN, EV_NET_STAT_DHUP,       connect_fail  },
-
-	{ ST_IN_WAIT_DCONN,  EV_NET_TIMER_INCOMING,  hang_up       },
-	{ ST_IN_WAIT_DCONN,  EV_NET_STAT_DCONN,      in_dconn      },
-	{ ST_IN_WAIT_DCONN,  EV_NET_STAT_DHUP,       connect_fail  },
-
-	{ ST_IN_WAIT_BCONN,  EV_NET_TIMER_INCOMING,  hang_up       },
-	{ ST_IN_WAIT_BCONN,  EV_NET_STAT_BCONN,      bconn         },
-	{ ST_IN_WAIT_BCONN,  EV_NET_STAT_DHUP,       connect_fail  },
-
-	{ ST_ACTIVE,         EV_NET_TIMER_HUP,       check_hup     },
-	{ ST_ACTIVE,         EV_NET_STAT_BHUP,       bhup          },
-	{ ST_ACTIVE,         EV_NET_STAT_CINF,       got_cinf      },
-	{ ST_ACTIVE,         EV_NET_STAT_BSENT,      got_bsent     },
-
-	{ ST_WAIT_DHUP,      EV_NET_STAT_DHUP,       dhup          },
-
-	{ ST_WAIT_BEFORE_CB, EV_NET_TIMER_CB_IN,     do_dial       },
-
-	{ ST_OUT_DIAL_WAIT,  EV_NET_TIMER_DIAL_WAIT, dialout_next  },
-};
-
-static struct fsm isdn_net_fsm = {
-	.st_cnt = ARRAY_SIZE(isdn_net_st_str),
-	.st_str = isdn_net_st_str,
-	.ev_cnt = ARRAY_SIZE(isdn_net_ev_str),
-	.ev_str = isdn_net_ev_str,
-	.fn_cnt = ARRAY_SIZE(isdn_net_fn_tbl),
-	.fn_tbl = isdn_net_fn_tbl,
-};
-
-static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...)
-{
-	va_list args;
-	isdn_net_dev *idev = fi->userdata;
-	char buf[128];
-	char *p = buf;
-
-	va_start(args, fmt);
-	p += sprintf(p, "%s: ", idev->name);
-	p += vsprintf(p, fmt, args);
-	va_end(args);
-	printk(KERN_DEBUG "%s\n", buf);
-}
-
-/* ====================================================================== */
-/* xmit path                                                              */
-/* ====================================================================== */
-
-#define ISDN_NET_MAX_QUEUE_LENGTH 2
-
-/*
- * is this particular channel busy?
- */
-static inline int
-isdn_net_dev_busy(isdn_net_dev *idev)
-{
-	return idev->frame_cnt >= ISDN_NET_MAX_QUEUE_LENGTH;
-}
-
-/*
- * find out if the net_device which this mlp is belongs to is busy.
- * It's busy iff all channels are busy.
- * must hold mlp->xmit_lock
- * FIXME: Use a mlp->frame_cnt instead of loop?
- */
-static inline int
-isdn_net_local_busy(isdn_net_local *mlp)
-{
-	isdn_net_dev *idev;
-
-	list_for_each_entry(idev, &mlp->online, online) {
-		if (!isdn_net_dev_busy(idev))
-			return 0;
-	}
-	return 1;
-}
-
-/*
- * For the given net device, this will get a non-busy channel out of the
- * corresponding bundle.
- * must hold mlp->xmit_lock
- */
-isdn_net_dev *
-isdn_net_get_xmit_dev(isdn_net_local *mlp)
-{
-	isdn_net_dev *idev;
-
-	list_for_each_entry(idev, &mlp->online, online) {
-		if (!isdn_net_dev_busy(idev)) {
-			/* point the head to next online channel */
-			list_del(&mlp->online);
-			list_add(&mlp->online, &idev->online);
-			return idev;
-		}
-	}
-	return NULL;
-}
-
-/* mlp->xmit_lock must be held */
-static inline void
-isdn_net_inc_frame_cnt(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-
-	if (isdn_net_dev_busy(idev))
-		isdn_BUG();
-		
-	idev->frame_cnt++;
-	if (isdn_net_local_busy(mlp))
-		netif_stop_queue(&mlp->dev);
-}
-
-/* mlp->xmit_lock must be held */
-static inline void
-isdn_net_dec_frame_cnt(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-
-	idev->frame_cnt--;
-
-	if (isdn_net_dev_busy(idev))
-		isdn_BUG();
-
-	if (!skb_queue_empty(&idev->super_tx_queue))
-		tasklet_schedule(&idev->tlet);
-	else
-		netif_wake_queue(&mlp->dev);
-}
-
-static void
-isdn_net_tasklet(unsigned long data)
-{
-	isdn_net_dev *idev = (isdn_net_dev *) data;
-	isdn_net_local *mlp = idev->mlp;
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mlp->xmit_lock, flags);
-	while (!isdn_net_dev_busy(idev) &&
-	       (skb = skb_dequeue(&idev->super_tx_queue))) {
-		isdn_net_writebuf_skb(idev, skb);
-	}
-	spin_unlock_irqrestore(&mlp->xmit_lock, flags);
-}
-
-/* We're good to accept (IP/whatever) traffic now */
-
-void
-isdn_net_online(isdn_net_dev *idev)
-{
-	// FIXME check we're connected
-	isdn_net_local *mlp = idev->mlp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mlp->xmit_lock, flags);
-	list_add(&idev->online, &mlp->online);
-	spin_unlock_irqrestore(&mlp->xmit_lock, flags);
-
-	netif_wake_queue(&mlp->dev);
-}
-
-/* No more (IP/whatever) traffic over the net interface */
-
-void
-isdn_net_offline(isdn_net_dev *idev)
-{
-	isdn_net_local *mlp = idev->mlp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mlp->xmit_lock, flags);
-	list_del(&idev->online);
-	spin_unlock_irqrestore(&mlp->xmit_lock, flags);
-	
-	skb_queue_purge(&idev->super_tx_queue);
-}
-
-/* 
- * all frames sent from the (net) LL to a HL driver should go via this function
- * must hold mlp->xmit_lock
- */
-void
-isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	isdn_net_local *mlp = idev->mlp;
-	int ret;
-	int len = skb->len;     /* save len */
-
-	/* before obtaining the lock the caller should have checked that
-	   the lp isn't busy */
-	if (isdn_net_dev_busy(idev)) {
-		isdn_BUG();
-		goto error;
-	}
-
-	if (!isdn_net_is_connected(idev)) {
-		isdn_BUG();
-		goto error;
-	}
-	ret = isdn_slot_write(idev->isdn_slot, skb);
-	if (ret != len) {
-		/* we should never get here */
-		printk(KERN_WARNING "%s: HL driver queue full\n", idev->name);
-		goto error;
-	}
-	
-	idev->transcount += len;
-	isdn_net_inc_frame_cnt(idev);
-	return;
-
- error:
-	dev_kfree_skb(skb);
-	mlp->stats.tx_errors++;
-}
-
-/* A packet has successfully been sent out. */
-
-static int
-isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c)
-{
-	isdn_net_local *mlp = idev->mlp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mlp->xmit_lock, flags);
-	isdn_net_dec_frame_cnt(idev);
-	spin_unlock_irqrestore(&mlp->xmit_lock, flags);
-	mlp->stats.tx_packets++;
-	mlp->stats.tx_bytes += c->parm.length;
-	return 1;
-}
-
-/*
- *  Based on cps-calculation, check if device is overloaded.
- *  If so, and if a slave exists, trigger dialing for it.
- *  If any slave is online, deliver packets using a simple round robin
- *  scheme.
- *
- *  Return: 0 on success, !0 on failure.
- */
-
-int
-isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
-	isdn_net_dev	*idev;
-	isdn_net_local	*mlp = ndev->priv;
-	unsigned long	flags;
-	int		retval;
-
-	ndev->trans_start = jiffies;
-
-	spin_lock_irqsave(&mlp->xmit_lock, flags);
-
-	if (list_empty(&mlp->online)) {
-		retval = isdn_net_autodial(skb, ndev);
-		goto out;
-	}
-
-	idev = isdn_net_get_xmit_dev(mlp);
-	if (!idev) {
-		printk(KERN_INFO "%s: all channels busy - requeuing!\n", ndev->name);
-		netif_stop_queue(ndev);
-		retval = 1;
-		goto out;
-	}
-
-	isdn_net_writebuf_skb(idev, skb);
-
-	/* the following stuff is here for backwards compatibility.
-	 * in future, start-up and hangup of slaves (based on current load)
-	 * should move to userspace and get based on an overall cps
-	 * calculation
-	 */
-	if (jiffies != idev->last_jiffies) {
-		idev->cps = idev->transcount * HZ / (jiffies - idev->last_jiffies);
-		idev->last_jiffies = jiffies;
-		idev->transcount = 0;
-	}
-	if ((get_isdn_dev())->net_verbose > 3)
-		printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps);
-
-	if (idev->cps > mlp->triggercps) {
-		if (!idev->sqfull) {
-			/* First time overload: set timestamp only */
-			idev->sqfull = 1;
-			idev->sqfull_stamp = jiffies;
-		} else {
-			/* subsequent overload: if slavedelay exceeded, start dialing */
-			if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) {
-				if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_AUTO)
-					__isdn_net_dial_slave(mlp);
-			}
-		}
-	} else {
-		if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) {
-			idev->sqfull = 0;
-		}
-		/* this is a hack to allow auto-hangup for slaves on moderate loads */
-		list_del(&mlp->online);
-		list_add_tail(&mlp->online, &idev->online);
-	}
-
-	retval = 0;
- out:
-	spin_unlock_irqrestore(&mlp->xmit_lock, flags);
-	return retval;
-}
-
-/*
- * this function is used to send supervisory data, i.e. data which was
- * not received from the network layer, but e.g. frames from ipppd, CCP
- * reset frames etc.
- * must hold mlp->xmit_lock
- */
-void
-isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	if (!isdn_net_dev_busy(idev)) {
-		isdn_net_writebuf_skb(idev, skb);
-	} else {
-		skb_queue_tail(&idev->super_tx_queue, skb);
-	}
-}
-
-/* ====================================================================== */
-/* receive path                                                           */
-/* ====================================================================== */
-
-/*
- * A packet arrived via ISDN. Search interface-chain for a corresponding
- * interface. If found, deliver packet to receiver-function and return 1,
- * else return 0.
- */
-static int
-isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb)
-{
-	isdn_net_dev *idev = slot->priv;
-	isdn_net_local *mlp;
-
-	if (!idev) {
-		isdn_BUG();
-		return 0;
-	}
-	if (!isdn_net_is_connected(idev)) {
-		isdn_BUG();
-		return 0;
-	}
-
-	mlp = idev->mlp;
-
-	idev->transcount += skb->len;
-
-	mlp->stats.rx_packets++;
-	mlp->stats.rx_bytes += skb->len;
-	skb->dev = &mlp->dev;
-	skb->pkt_type = PACKET_HOST;
-	isdn_dumppkt("R:", skb->data, skb->len, 40);
-
-	mlp->ops->receive(mlp, idev, skb);
-
-	return 1;
-}
-
-/*
- * After handling connection-type specific stuff, the receiver function
- * can use this function to pass the skb on to the network layer.
- */
-void
-isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol)
-{
-	idev->huptimer = 0;
-
-	skb->protocol = protocol;
-	skb->dev = &idev->mlp->dev;
-	netif_rx(skb);
-}
-
-/* ====================================================================== */
-/* init / exit                                                            */
-/* ====================================================================== */
-
-void
-isdn_net_lib_init(void)
-{
-	fsm_new(&isdn_net_fsm);
-
-#ifdef CONFIG_ISDN_NET_SIMPLE
-	register_isdn_netif(ISDN_NET_ENCAP_ETHER,      &isdn_ether_ops);
-	register_isdn_netif(ISDN_NET_ENCAP_RAWIP,      &isdn_rawip_ops);
-	register_isdn_netif(ISDN_NET_ENCAP_IPTYP,      &isdn_iptyp_ops);
-	register_isdn_netif(ISDN_NET_ENCAP_UIHDLC,     &isdn_uihdlc_ops);
-#endif
-#ifdef CONFIG_ISDN_NET_CISCO
-	register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLC,  &isdn_ciscohdlck_ops);
-	register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLCK, &isdn_ciscohdlck_ops);
-#endif
-#ifdef CONFIG_ISDN_X25
-	register_isdn_netif(ISDN_NET_ENCAP_X25IFACE,   &isdn_x25_ops);
-#endif
-#ifdef CONFIG_ISDN_PPP
-	register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP,    &isdn_ppp_ops);
-#endif
-}
-
-void
-isdn_net_lib_exit(void)
-{
-	fsm_free(&isdn_net_fsm);
-}
--- diff/drivers/isdn/i4l/isdn_net_lib.h	2003-09-17 12:28:06.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_net_lib.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,224 +0,0 @@
-/* Linux ISDN subsystem, network interface support code
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef __ISDN_NET_LIB_H__
-#define __ISDN_NET_LIB_H__
-
-#include <linux/isdn.h>
-
-typedef struct isdn_net_local_s isdn_net_local;
-typedef struct isdn_net_dev_s isdn_net_dev;
-
-struct isdn_netif_ops {
-	int			(*hard_start_xmit) (struct sk_buff *skb,
-						    struct net_device *dev);
-	int			(*hard_header) (struct sk_buff *skb,
-						struct net_device *dev,
-						unsigned short type,
-						void *daddr,
-						void *saddr,
-						unsigned len);
-	int			(*do_ioctl)(struct net_device *dev,
-					    struct ifreq *ifr, int cmd);
-
-	unsigned short		flags;	/* interface flags (a la BSD)	*/
-	unsigned short		type;	/* interface hardware type	*/
-	unsigned char		addr_len;/* hardware address length	*/
-	void                    (*receive)(struct isdn_net_local_s *,
-					   struct isdn_net_dev_s *,
-					   struct sk_buff *);
-	void                    (*connected)(struct isdn_net_dev_s *);
-	void                    (*disconnected)(struct isdn_net_dev_s *);
-	int                     (*bind)(struct isdn_net_dev_s *);
-	void                    (*unbind)(struct isdn_net_dev_s *);
-	int                     (*init)(struct isdn_net_local_s *);
-	void                    (*cleanup)(struct isdn_net_local_s *);
-	int                     (*open)(struct isdn_net_local_s *);
-	void                    (*close)(struct isdn_net_local_s *);
-};
-
-/* our interface to isdn_common.c */
-void isdn_net_lib_init(void);
-void isdn_net_lib_exit(void);
-void isdn_net_hangup_all(void);
-int  isdn_net_ioctl(struct inode *, struct file *, uint, ulong);
-int  isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup);
-
-/* provided for interface types to use */
-void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
-void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb);
-void isdn_net_online(isdn_net_dev *idev);
-void isdn_net_offline(isdn_net_dev *idev);
-int  isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
-void isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol);
-isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp);
-int  isdn_net_hangup(isdn_net_dev *);
-int  isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
-int  isdn_net_dial_req(isdn_net_dev *);
-int  register_isdn_netif(int encap, struct isdn_netif_ops *ops);
-
-/* ====================================================================== */
-
-/* Feature- and status-flags for a net-interface */
-#define ISDN_NET_SECURE     0x02       /* Accept calls from phonelist only  */
-#define ISDN_NET_CALLBACK   0x04       /* activate callback                 */
-#define ISDN_NET_CBHUP      0x08       /* hangup before callback            */
-#define ISDN_NET_CBOUT      0x10       /* remote machine does callback      */
-
-#define ISDN_NET_MAGIC      0x49344C02 /* for paranoia-checking             */
-
-/* Phone-list-element */
-struct isdn_net_phone {
-	struct list_head list;
-	char num[ISDN_MSNLEN];
-};
-
-/* per network interface data (dev->priv) */
-
-struct isdn_net_local_s {
-  ulong                  magic;
-  struct net_device      dev;          /* interface to upper levels        */
-  struct net_device_stats stats;       /* Ethernet Statistics              */
-  struct isdn_netif_ops *ops;
-  void                  *inl_priv;     /* interface types can put their
-					  private data here                */
-  int                    flags;        /* Connection-flags                 */
-  int                    dialmax;      /* Max. Number of Dial-retries      */
-  int	        	 dialtimeout;  /* How long shall we try on dialing */
-  int			 dialwait;     /* wait after failed attempt        */
-
-  int                    cbdelay;      /* Delay before Callback starts     */
-  char                   msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
-
-  u_char                 cbhup;        /* Flag: Reject Call before Callback*/
-  int                    hupflags;     /* Flags for charge-unit-hangup:    */
-  int                    onhtime;      /* Time to keep link up             */
-
-  u_char                 p_encap;      /* Packet encapsulation             */
-  u_char                 l2_proto;     /* Layer-2-protocol                 */
-  u_char                 l3_proto;     /* Layer-3-protocol                 */
-
-  ulong                  slavedelay;   /* Dynamic bundling delaytime       */
-  int                    triggercps;   /* BogoCPS needed for trigger slave */
-  struct list_head       phone[2];     /* List of remote-phonenumbers      */
-				       /* phone[0] = Incoming Numbers      */
-				       /* phone[1] = Outgoing Numbers      */
-
-  struct list_head       slaves;       /* list of all bundled channels    
-					  protected by serializing config
-					  ioctls / no change allowed when
-					  interface is running             */
-  struct list_head       online;       /* list of all bundled channels 
-					  which can be used for actual
-					  data (IP) transfer              
-					  protected by xmit_lock           */
-
-  spinlock_t             xmit_lock;    /* used to protect the xmit path of 
-					  a net_device, including all
-					  associated channels's frame_cnt  */
-  struct list_head       running_devs; /* member of global running_devs    */
-  atomic_t               refcnt;       /* references held by ISDN code     */
-
-};
-
-
-/* per ISDN channel (ISDN interface) data */
-
-struct isdn_net_dev_s {
-  struct isdn_slot	*isdn_slot;	/* Index to isdn device/channel     */
-  struct isdn_slot	*exclusive;	/* NULL if non excl                 */
-  int			pre_device;	/* Preselected isdn-device          */
-  int			pre_channel;	/* Preselected isdn-channel         */
-
-  struct timer_list	dial_timer;	/* dial events timer                */
-  struct fsm_inst	fi;		/* call control state machine       */
-  int			dial_event;	/* event in case of timer expiry    */
-  int			dial;		/* # of phone number just dialed    */
-  int			outgoing;	/* Flag: outgoing call              */
-  int			dialretry;	/* Counter for Dialout-retries      */
-
-  int			cps;		/* current speed of this interface  */
-  int			transcount;	/* byte-counter for cps-calculation */
-  u_long		last_jiffies;	/* when transcount was reset        */
-  int			sqfull;		/* Flag: netdev-queue overloaded    */
-  u_long		sqfull_stamp;	/* Start-Time of overload           */
-
-  int			huptimer;	/* Timeout-counter for auto-hangup  */
-  int			charge;		/* Counter for charging units       */
-  int			charge_state;	/* ChargeInfo state machine         */
-  u_long		chargetime;	/* Timer for Charging info          */
-  int			chargeint;	/* Interval between charge-infos    */
-
-  int			pppbind;	/* ippp device for bindings         */
-
-  struct sk_buff_head	super_tx_queue;	/* List of supervisory frames to  */
-					/* be transmitted asap              */
-  int			frame_cnt;	/* number of frames currently       */
-					/* queued in HL driver              */
-  struct tasklet_struct	tlet;
-
-  isdn_net_local	*mlp;		/* Ptr to master device for all devs*/
-
-  struct list_head	slaves;		/* member of local->slaves          */
-  struct list_head	online;		/* member of local->online          */
-
-  char			name[10];	/* Name of device                   */
-  struct list_head	global_list;	/* global list of all isdn_net_devs */
-  void			*ind_priv;	/* interface types can put their
-					   private data here                */
-};
-
-/* ====================================================================== */
-
-static inline int
-put_u8(unsigned char *p, u8 x)
-{
-	*p = x;
-	return 1;
-}
-
-static inline int
-put_u16(unsigned char *p, u16 x)
-{
-	*((u16 *)p) = htons(x);
-	return 2;
-}
-
-static inline int
-put_u32(unsigned char *p, u32 x)
-{
-	*((u32 *)p) = htonl(x);
-	return 4;
-}
-
-static inline int
-get_u8(unsigned char *p, u8 *x)
-{
-	*x = *p;
-	return 1;
-}
-
-static inline int
-get_u16(unsigned char *p, u16 *x)
-{
-	*x = ntohs(*((u16 *)p));
-	return 2;
-}
-
-static inline int
-get_u32(unsigned char *p, u32 *x)
-{
-	*x = ntohl(*((u32 *)p));
-	return 4;
-}
-
-
-#endif
--- diff/drivers/isdn/i4l/isdn_ppp_ccp.c	2004-01-19 10:22:56.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ppp_ccp.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,657 +0,0 @@
-/* Linux ISDN subsystem, PPP CCP support
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include "isdn_ppp_ccp.h"
-#include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_ppp.h"
-#include <linux/ppp-comp.h>
-
-/* ====================================================================== */                                                                       
-enum ippp_ccp_reset_states {
-	CCPResetIdle,
-	CCPResetSentReq,
-	CCPResetRcvdReq,
-	CCPResetSentAck,
-	CCPResetRcvdAck
-};
-
-struct ippp_ccp_reset_state {
-	enum ippp_ccp_reset_states state;/* State of this transaction */
-	struct ippp_ccp *ccp;            /* Backlink */
-	unsigned char id;		 /* id index */
-	unsigned char ta:1;		 /* The timer is active (flag) */
-	unsigned char expra:1;		 /* We expect a ResetAck at all */
-	int dlen;			 /* Databytes stored in data */
-	struct timer_list timer;	 /* For timeouts/retries */
-	/* This is a hack but seems sufficient for the moment. We do not want
-	   to have this be yet another allocation for some bytes, it is more
-	   memory management overhead than the whole mess is worth. */
-	unsigned char data[IPPP_RESET_MAXDATABYTES];
-};
-
-/* The data structure keeping track of the currently outstanding CCP Reset
-   transactions. */
-struct ippp_ccp_reset {
-	struct ippp_ccp_reset_state *rs[256];	/* One per possible id */
-	unsigned char lastid;			/* Last id allocated */
-};
-
-/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
-   but absolutely nontrivial. The most abstruse problem we are facing is
-   that the generation, reception and all the handling of timeouts and
-   resends including proper request id management should be entirely left
-   to the (de)compressor, but indeed is not covered by the current API to
-   the (de)compressor. The API is a prototype version from PPP where only
-   some (de)compressors have yet been implemented and all of them are
-   rather simple in their reset handling. Especially, their is only one
-   outstanding ResetAck at a time with all of them and ResetReq/-Acks do
-   not have parameters. For this very special case it was sufficient to
-   just return an error code from the decompressor and have a single
-   reset() entry to communicate all the necessary information between
-   the framework and the (de)compressor. Bad enough, LZS is different
-   (and any other compressor may be different, too). It has multiple
-   histories (eventually) and needs to Reset each of them independently
-   and thus uses multiple outstanding Acks and history numbers as an
-   additional parameter to Reqs/Acks.
-   All that makes it harder to port the reset state engine into the
-   kernel because it is not just the same simple one as in (i)pppd but
-   it must be able to pass additional parameters and have multiple out-
-   standing Acks. We are trying to achieve the impossible by handling
-   reset transactions independent by their id. The id MUST change when
-   the data portion changes, thus any (de)compressor who uses more than
-   one resettable state must provide and recognize individual ids for
-   each individual reset transaction. The framework itself does _only_
-   differentiate them by id, because it has no other semantics like the
-   (de)compressor might.
-   This looks like a major redesign of the interface would be nice,
-   but I don't have an idea how to do it better. */
-
-/* ====================================================================== */
-
-/* Free a given state and clear everything up for later reallocation */
-static void
-ippp_ccp_reset_free_state(struct ippp_ccp *ccp, unsigned char id)
-{
-	struct ippp_ccp_reset_state *rs	= ccp->reset->rs[id];
-
-	if (!rs)
-		return;
-	
-	if (rs->ta) // FIXME?
-		del_timer_sync(&rs->timer);
-
-	kfree(rs);
-	ccp->reset->rs[id] = NULL;
-}
-
-static void
-do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id,
-	      unsigned char *data, int len)
-{
-	struct sk_buff *skb;
-	unsigned char *p;
-	u16 proto = ccp->proto == PPP_COMP ? PPP_CCP : PPP_CCPFRAG;
-
-	skb = ccp->alloc_skb(ccp->priv, 4 + len, GFP_ATOMIC);
-
-	p = skb_put(skb, 4);
-	p += put_u8 (p, code);
-	p += put_u8 (p, id);
-	p += put_u16(p, len + 4);
-
-	if (len)
-		memcpy(skb_put(skb, len), data, len);
-
-	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1);
-
-	ccp->xmit(ccp->priv, skb, proto);
-}
-
-/* The timer callback function which is called when a ResetReq has timed out,
-   aka has never been answered by a ResetAck */
-static void
-isdn_ppp_ccp_timer_callback(unsigned long data)
-{
-	struct ippp_ccp_reset_state *rs = (struct ippp_ccp_reset_state *) data;
-
-	if (!rs->ta) {
-		isdn_BUG();
-		return;
-	}
-	if (rs->state != CCPResetSentReq) {
-		printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
-		       rs->state);
-		rs->ta = 0;
-		return;
-	}
-	/* We are correct here */
-	if (!rs->expra) {
-		/* Hmm, there is no Ack really expected. We can clean
-		   up the state now, it will be reallocated if the
-		   decompressor insists on another reset */
-		rs->ta = 0;
-		ippp_ccp_reset_free_state(rs->ccp, rs->id);
-		return;
-	}
-	printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
-	       rs->id);
-	/* Push it again */
-	do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen);
-
-	mod_timer(&rs->timer, jiffies + 5 * HZ);
-}
-
-/* Allocate a new reset transaction state */
-static struct ippp_ccp_reset_state *
-ippp_ccp_reset_alloc_state(struct ippp_ccp *ccp, unsigned char id)
-{
-	struct ippp_ccp_reset_state *rs;
-
-	rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
-	if(!rs)
-		return NULL;
-	memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
-	rs->state = CCPResetIdle;
-	rs->ccp = ccp;
-	rs->id = id;
-	init_timer(&rs->timer);
-	rs->timer.data = (unsigned long)rs;
-	rs->timer.function = isdn_ppp_ccp_timer_callback;
-
-	ccp->reset->rs[id] = rs;
-	return rs;
-}
-
-/* A decompressor wants a reset with a set of parameters - do what is
-   necessary to fulfill it */
-static void
-ippp_ccp_reset_xmit(struct ippp_ccp *ccp,
-		    struct isdn_ppp_resetparams *rp)
-{
-	struct ippp_ccp_reset_state *rs;
-	int id;
-
-	if (rp->valid) {
-		/* The decompressor defines parameters by itself */
-		if (!rp->rsend)
-			return;
-
-		/* And it wants us to send a request */
-		if (!rp->idval) {
-			isdn_BUG();
-			return;
-		}
-		id = rp->id;
-	} else {
-		/* The reset params are invalid. The decompressor does not
-		   care about them, so we just send the minimal requests
-		   and increase ids only when an Ack is received for a
-		   given id */
-		id = ccp->reset->lastid++;
-		/* We always expect an Ack if the decompressor doesn't
-		   know	better */
-		rp->expra = 1;
-		rp->dtval = 0;
-	}
-	rs = ccp->reset->rs[id];
-	if (rs) {
-		printk(KERN_INFO "ippp_ccp: reset xmit in wrong state %d "
-		       "for id %d (%d)\n", rs->state, id, rs->ta);
-		return;
-	}
-	/* Ok, this is a new transaction */
-	printk(KERN_DEBUG "ippp_ccp: new xmit for id %d\n", id);
-	rs = ippp_ccp_reset_alloc_state(ccp, id);
-	if(!rs) {
-		printk(KERN_INFO "ippp_ccp: out of mem allocing ccp trans\n");
-		return;
-	}
-	rs->expra = rp->expra;
-	rs->id = id;
-	if (rp->dtval) {
-		rs->dlen = rp->dlen;
-		memcpy(rs->data, rp->data, rp->dlen);
-	} else {
-		rs->dlen = 0;
-	}
-
-	rs->state = CCPResetSentReq;
-	do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen);
-
-	/* Start the timer */
-	rs->timer.expires = jiffies + 5*HZ;
-	add_timer(&rs->timer);
-	rs->ta = 1;
-}
-
-/* ====================================================================== */
-
-struct ippp_ccp *
-ippp_ccp_alloc(void)
-{
-	struct ippp_ccp *ccp;
-
-	ccp = kmalloc(sizeof(*ccp), GFP_ATOMIC); // FIXME
-	if (!ccp)
-		return NULL;
-	memset(ccp, 0, sizeof(*ccp));
-	ccp->mru = 1524;      /* MRU, default 1524 */
-	ccp->reset = kmalloc(sizeof(*ccp->reset), GFP_ATOMIC); // FIXME alloc together?
-	if (!ccp->reset) {
-		kfree(ccp);
-		return NULL;
-	}
-	memset(ccp->reset, 0, sizeof(*ccp->reset));
-	return ccp;
-}
-
-void
-ippp_ccp_free(struct ippp_ccp *ccp)
-{
-	int id;
-
-	if (ccp->comp_stat) {
-		ccp->compressor->free(ccp->comp_stat);
-		module_put(ccp->compressor->owner);
-	}
-	if (ccp->decomp_stat) {
-		ccp->decompressor->free(ccp->decomp_stat);
-		module_put(ccp->decompressor->owner);
-	}
-	for (id = 0; id < 256; id++) {
-		if (ccp->reset->rs[id])
-			ippp_ccp_reset_free_state(ccp, id);
-	}
-	kfree(ccp->reset);
-	kfree(ccp);
-}
-
-int
-ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru)
-{
-	ccp->mru = mru;
-	return 0;
-}
-
-unsigned int
-ippp_ccp_get_flags(struct ippp_ccp *ccp)
-{
-	return ccp->compflags & (SC_DC_ERROR|SC_DC_FERROR);
-}
-
-/*
- * compress a frame 
- * returns original skb if we did not compress the frame
- * and a new skb otherwise
- */
-struct sk_buff *
-ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto)
-{
-	struct sk_buff *skb;
-
-	if (!(ccp->compflags & (SC_COMP_ON|SC_DECOMP_ON))) {
-		/* We send compressed only if both down- und upstream
-		   compression is negotiated, that means, CCP is up */
-		return skb_in;
-	}
-	/* we do not compress control protocols */
-	if (*proto > 0x3fff) {
-		return skb_in;
-	}
-	if (!ccp->compressor || !ccp->comp_stat) {
-		isdn_BUG();
-		return skb_in;
-	}
-	/* Allow for at least 150 % expansion (for now) */
-	skb = alloc_skb(skb_in->len*2 + skb_headroom(skb_in), GFP_ATOMIC);
-	if (!skb)
-		return skb_in;
-
-	skb_reserve(skb, skb_headroom(skb_in));
-	if (!ccp->compressor->compress(ccp->comp_stat, skb_in, skb, *proto)) {
-		dev_kfree_skb(skb);
-		return skb_in;
-	}
-	isdn_ppp_frame_log("comp  in:", skb_in->data, skb_in->len, 20, -1, -1);
-	isdn_ppp_frame_log("comp out:", skb->data, skb->len, 20, -1, -1);
-	dev_kfree_skb(skb_in);
-	*proto = ccp->proto;
-	return skb;
-}
-
-/* 
- * decompress packet
- *
- * proto is updated to protocol field of uncompressed packet.
- * retval: decompressed packet,
- *         same packet if uncompressed,
- *	   NULL if decompression error
- */
-
-struct sk_buff *
-ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto)
-{
-	struct sk_buff *skb;
-	struct isdn_ppp_resetparams rsparm;
-	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-	int len;
-
-	if (!(ccp->compflags & SC_DECOMP_ON)) {
-		return skb_in;
-	}
-	if (!ccp->decompressor || !ccp->decomp_stat) {
-		isdn_BUG();
-		return skb_in;
-	}
-	if (*proto != ccp->proto) {
-		/* uncompressed packets are fed through the decompressor to
-		 * update the decompressor state */
-		ccp->decompressor->incomp(ccp->decomp_stat, skb_in, *proto);
-		return skb_in;
-	}
-	skb = dev_alloc_skb(ccp->mru + PPP_HDRLEN); // FIXME oom?
-
-	// Set up reset params for the decompressor
-	memset(&rsparm, 0, sizeof(rsparm));
-	rsparm.data = rsdata;
-	rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
-
-	len = ccp->decompressor->decompress(ccp->decomp_stat, skb_in, skb,
-					    &rsparm);
-	isdn_ppp_frame_log("deco  in:", skb_in->data, skb_in->len, 20, -1, -1);
-	isdn_ppp_frame_log("deco out:", skb->data, skb->len, 20, -1, -1);
-	kfree_skb(skb_in);
-
-	if (len <= 0) {
-		switch(len) {
-		case DECOMP_ERROR:
-			printk(KERN_INFO "ippp: decomp wants reset with%s params\n",
-			       rsparm.valid ? "" : "out");
-			
-			ippp_ccp_reset_xmit(ccp, &rsparm);
-			break;
-		case DECOMP_FATALERROR:
-			ccp->compflags |= SC_DC_FERROR;
-			/* Kick ipppd to recognize the error */
-			ccp->kick_up(ccp->priv);
-			break;
-		}
-		kfree_skb(skb);
-		return NULL;
-	}
-	if (isdn_ppp_strip_proto(skb, proto)) {
-		kfree_skb(skb);
-		return NULL;
-	}
-	return skb;
-}
-
-/* An Ack was received for this id. This means we stop the timer and clean
-   up the state prior to calling the decompressors reset routine. */
-static void
-isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp *ccp, unsigned char id)
-{
-	struct ippp_ccp_reset_state *rs = ccp->reset->rs[id];
-
-	if (!rs) {
-		printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
-		       " %d\n", id);
-		return;
-	}
-
-	if (rs->ta && rs->state == CCPResetSentReq) {
-		/* Great, we are correct */
-		if(!rs->expra)
-			printk(KERN_DEBUG "ippp_ccp: ResetAck received"
-			       " for id %d but not expected\n", id);
-	} else {
-		printk(KERN_INFO "ippp_ccp: ResetAck received out of"
-		       "sync for id %d\n", id);
-	}
-	if(rs->ta) {
-		rs->ta = 0;
-		del_timer(&rs->timer);
-	}
-	ippp_ccp_reset_free_state(ccp, id);
-}
-
-void
-ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb)
-{
-	int len;
-	struct isdn_ppp_resetparams rsparm;
-	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
-
-	isdn_ppp_frame_log("ccp-recv", skb->data, skb->len, 32, -1, -1);
-
-	switch(skb->data[0]) {
-	case CCP_CONFREQ:
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Disable compression here!\n");
-
-		ccp->compflags &= ~SC_COMP_ON;		
-		break;
-	case CCP_TERMREQ:
-	case CCP_TERMACK:
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Disable (de)compression here!\n");
-
-		ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);		
-		break;
-	case CCP_CONFACK:
-		/* if we RECEIVE an ackowledge we enable the decompressor */
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Enable decompression here!\n");
-
-		if (!ccp->decomp_stat)
-			break;
-		ccp->compflags |= SC_DECOMP_ON;
-		break;
-	case CCP_RESETACK:
-		printk(KERN_DEBUG "Received ResetAck from peer\n");
-		len = (skb->data[2] << 8) | skb->data[3];
-		len -= 4;
-
-		/* If a reset Ack was outstanding for this id, then
-		   clean up the state engine */
-		isdn_ppp_ccp_reset_ack_rcvd(ccp, skb->data[1]);
-		if (ccp->decomp_stat)
-			ccp->decompressor->reset(ccp->decomp_stat,
-						 skb->data[0], skb->data[1],
-						 len ? &skb->data[4] : NULL,
-						 len, NULL);
-		/* TODO: This is not easy to decide here */
-		ccp->compflags &= ~SC_DECOMP_DISCARD;
-		break;
-	case CCP_RESETREQ:
-		printk(KERN_DEBUG "Received ResetReq from peer\n");
-		/* Receiving a ResetReq means we must reset our compressor */
-		/* Set up reset params for the reset entry */
-		memset(&rsparm, 0, sizeof(rsparm));
-		rsparm.data = rsdata;
-		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; 
-		/* Isolate data length */
-		len = (skb->data[2] << 8) | skb->data[3];
-		len -= 4;
-		if (ccp->comp_stat)
-			ccp->compressor->reset(ccp->comp_stat,
-					       skb->data[0], skb->data[1],
-					       len ? &skb->data[4] : NULL,
-					       len, &rsparm);
-		/* Ack the Req as specified by rsparm */
-		if (rsparm.valid) {
-			/* Compressor reset handler decided how to answer */
-			if (!rsparm.rsend) {
-				printk(KERN_DEBUG "ResetAck suppressed\n");
-				return;
-			}
-			/* We should send a Frame */
-			do_xmit_reset(ccp, CCP_RESETACK,
-				      rsparm.idval ? rsparm.id : skb->data[1],
-				      rsparm.data,
-				      rsparm.dtval ? rsparm.dlen : 0);
-			return;
-		}
-		/* We answer with a straight reflected Ack */
-		do_xmit_reset(ccp, CCP_RESETACK, skb->data[1], 
-			      skb->data + 4, len);
-	}
-}
-
-void
-ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb)
-{
-	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1);
-
-        switch (skb->data[2]) {
-	case CCP_CONFREQ:
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Disable decompression here!\n");
-
-		ccp->compflags &= ~SC_DECOMP_ON;
-		break;
-	case CCP_TERMREQ:
-	case CCP_TERMACK:
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Disable (de)compression here!\n");
-
-		ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);
-		break;
-	case CCP_CONFACK:
-		/* if we SEND an ackowledge we can/must enable the compressor */
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Enable compression here!\n");
-
-		if (!ccp->compressor)
-			break;
-
-		ccp->compflags |= SC_COMP_ON;
-		break;
-	case CCP_RESETACK:
-		/* If we send a ACK we should reset our compressor */
-		if (ccp->debug & 0x10)
-			printk(KERN_DEBUG "Reset decompression state here!\n");
-
-		printk(KERN_DEBUG "ResetAck from daemon passed by\n");
-
-		if (!ccp->comp_stat)
-			break;
-
-		ccp->compressor->reset(ccp->comp_stat, 0, 0, NULL, 0, NULL);
-		ccp->compflags &= ~SC_COMP_DISCARD;	
-		break;
-	case CCP_RESETREQ:
-		/* Just let it pass by */
-		printk(KERN_DEBUG "ResetReq from daemon passed by\n");
-		break;
-	}
-}
-
-static LIST_HEAD(ipc_head);
-static spinlock_t ipc_head_lock = SPIN_LOCK_UNLOCKED;
-
-int
-ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
-			struct isdn_ppp_comp_data *data)
-{
-	struct isdn_ppp_compressor *ipc;
-	int ret;
-	void *stat;
-	int num = data->num;
-
-	if (ccp->debug & 0x10)
-		printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit,
-		       data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num);
-
-	spin_lock(&ipc_head_lock);
-	list_for_each_entry(ipc, &ipc_head, list) {
-		if (ipc->num == num &&
-		    try_module_get(ipc->owner))
-			goto found;
-	}
-	spin_unlock(&ipc_head_lock);
-	return -EINVAL;
-
- found:
-	spin_unlock(&ipc_head_lock);
-
-	stat = ipc->alloc(data);
-	if (!stat) {
-		printk(KERN_ERR "Can't alloc (de)compression!\n");
-		goto err;
-	}
-	ret = ipc->init(stat, data, unit, 0);
-	if(!ret) {
-		printk(KERN_ERR "Can't init (de)compression!\n");
-		ipc->free(stat);
-		goto err;
-	}
-	if (data->flags & IPPP_COMP_FLAG_XMIT) {
-		if (ccp->comp_stat) {
-			ccp->compressor->free(ccp->comp_stat);
-			module_put(ccp->compressor->owner);
-		}
-			ccp->comp_stat = stat;
-			ccp->compressor = ipc;
-	} else {
-		if (ccp->decomp_stat) {
-			ccp->decompressor->free(ccp->decomp_stat);
-			module_put(ccp->decompressor->owner);
-		}
-		ccp->decomp_stat = stat;
-		ccp->decompressor = ipc;
-	}
-	return 0;
-
- err:
-	module_put(ipc->owner);
-	return -EINVAL;
-}
-
-void
-ippp_ccp_get_compressors(unsigned long protos[8])
-{
-	struct isdn_ppp_compressor *ipc;
-	int i, j;
-
-	memset(protos, 0, sizeof(unsigned long) * 8);
-
-	spin_lock(&ipc_head_lock);
-	list_for_each_entry(ipc, &ipc_head, list) {
-		j = ipc->num / (sizeof(long)*8);
-		i = ipc->num % (sizeof(long)*8);
-		if (j < 8)
-			protos[j] |= 1 << i;
-	}
-	spin_unlock(&ipc_head_lock);
-}
-
-int
-isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
-{
-	spin_lock(&ipc_head_lock);
-	list_add_tail(&ipc->list, &ipc_head);
-	spin_unlock(&ipc_head_lock);
-
-	return 0;
-}
-
-int
-isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
-{
-	spin_lock(&ipc_head_lock);
-	list_del(&ipc->list);
-	spin_unlock(&ipc_head_lock);
-
-	return 0;
-}
-
--- diff/drivers/isdn/i4l/isdn_ppp_ccp.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ppp_ccp.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,75 +0,0 @@
-/* Linux ISDN subsystem, PPP CCP support
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/kernel.h>
-#include <linux/isdn_ppp.h>
-
-/* for ippp_ccp::flags */
-
-#define SC_DECOMP_ON		0x01
-#define SC_COMP_ON		0x02
-#define SC_DECOMP_DISCARD	0x04
-#define SC_COMP_DISCARD		0x08
-
-/* SC_DC_ERROR/FERROR go in here as well, but are defined elsewhere
-
-   #define SC_DC_FERROR	0x00800000
-   #define SC_DC_ERROR	0x00400000
-*/
-
-struct ippp_ccp {
-	u16                         proto;
-	struct isdn_ppp_compressor *compressor;
-	struct isdn_ppp_compressor *decompressor;
-	void                       *comp_stat;
-	void                       *decomp_stat;
-	unsigned long               compflags;
-	struct ippp_ccp_reset      *reset;
-	int                         mru;
-	int                         debug;
-	void                       *priv;
-	void            (*xmit)(void *priv, struct sk_buff *skb, u16 proto);
-	void            (*kick_up)(void *priv);
-	struct sk_buff *(*alloc_skb)(void *priv, int len, int gfp_mask);
-};
-
-struct ippp_ccp *
-ippp_ccp_alloc(void);
-
-void
-ippp_ccp_free(struct ippp_ccp *ccp);
-
-int
-ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru);
-
-unsigned int
-ippp_ccp_get_flags(struct ippp_ccp *ccp);
-
-struct sk_buff *
-ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto);
-
-struct sk_buff *
-ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto);
-
-void
-ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb);
-
-void
-ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb);
-
-void
-ippp_ccp_get_compressors(unsigned long protos[8]);
-
-int
-ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
-			struct isdn_ppp_comp_data *data);
-
-
--- diff/drivers/isdn/i4l/isdn_ppp_mp.c	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_ppp_mp.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,353 +0,0 @@
-/* Linux ISDN subsystem, PPP CCP support
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include "isdn_ppp_mp.h"
-#include "isdn_ppp_ccp.h"
-#include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_ppp.h"
-
-/* ====================================================================== */
-
-#define MP_END_FRAG             0x40
-#define MP_BEGIN_FRAG           0x80
-
-#define MP_MAX_QUEUE_LEN	16
-
-/* ====================================================================== */
-
-int
-ippp_mp_bind(isdn_net_dev *idev)
-{
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-
-	/* seq no last seen, maybe set to bundle min, when joining? */
-	ind_ppp->mp_rxseq = 0;
-
-	if (!list_empty(&idev->mlp->online))
-		return 0;
-
-	/* first channel for this link, do some setup */
-
-	inl_ppp->mp_cfg   = 0;        /* MPPP configuration */
-	inl_ppp->mp_txseq = 0;        /* MPPP tx sequence number */
-	inl_ppp->mp_rxseq = (u32) -1;
-	skb_queue_head_init(&inl_ppp->mp_frags);
-
-	return 0;
-}
-
-int
-ippp_mp_bundle(isdn_net_dev *idev, int unit)
-{
-	isdn_net_local *lp = idev->mlp;
-	char ifn[IFNAMSIZ + 1];
-	isdn_net_dev *n_idev;
-	struct ind_ppp *ind_ppp;
-
-	printk(KERN_DEBUG "%s: %s: slave unit: %d\n",
-	       __FUNCTION__, idev->name, unit);
-
-	sprintf(ifn, "ippp%d", unit);
-	list_for_each_entry(n_idev, &lp->slaves, slaves) {
-		if (strcmp(n_idev->name, ifn) == 0)
-			goto found;
-	}
-	
-	printk(KERN_INFO "%s: cannot find %s\n", __FUNCTION__, ifn);
-	return -ENODEV;
-
- found:
-	ind_ppp = n_idev->ind_priv;
-	if (!ind_ppp->ipppd) {
-		printk(KERN_INFO "%s: no ipppd?\n", __FUNCTION__);
-		return -ENXIO;
-	}
-	ind_ppp->pppcfg |= SC_ENABLE_IP;
-	isdn_net_online(n_idev);
-
-	return 0;
-}
-  
-void
-ippp_mp_disconnected(isdn_net_dev *idev)
-{
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-
-	if (!list_empty(&idev->mlp->online))
-		return;
-
-	/* we're the last link going down */
-	skb_queue_purge(&inl_ppp->mp_frags);
-}
-
-void
-ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-	unsigned char *p;
-	u32 txseq;
-	u16 proto;
-
-	if (!(inl_ppp->mp_cfg & SC_MP_PROT)) {
-		return ippp_xmit(idev, skb);
-	}
-
-	/* we could do something smarter than just sending
-	 * the complete packet as fragment... */
-
-	txseq = inl_ppp->mp_txseq++;
-	
-	if (inl_ppp->mp_cfg & SC_OUT_SHORT_SEQ) {
-		/* sequence number: 12bit */
-		p = skb_push(skb, 2);
-		p[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((txseq >> 8) & 0xf);
-		p[1] = txseq & 0xff;
-	} else {
-		/* sequence number: 24bit */
-		p = skb_push(skb, 4);
-		p[0] = MP_BEGIN_FRAG | MP_END_FRAG;
-		p[1] = (txseq >> 16) & 0xff;
-		p[2] = (txseq >>  8) & 0xff;
-		p[3] = (txseq >>  0) & 0xff;
-	}
-	proto = PPP_MP;
-	skb = ippp_ccp_compress(ind_ppp->ccp, skb, &proto);
-	ippp_push_proto(ind_ppp, skb, proto);
-	ippp_xmit(idev, skb);
-}
-
-static void mp_receive(isdn_net_dev *idev, struct sk_buff *skb);
-
-void
-ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
-{
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-
- 	if (inl_ppp->mp_cfg & SC_REJ_MP_PROT)
-		goto out;
-
-	skb = ippp_ccp_decompress(ind_ppp->ccp, skb, &proto);
-	if (!skb)
-		goto drop;
-
-	if (proto == PPP_MP)
-		return mp_receive(idev, skb);
-
- out:
-	return ippp_receive(idev, skb, proto);
-
- drop:
-	idev->mlp->stats.rx_errors++;
-	kfree_skb(skb);
-}
-
-#define MP_LONGSEQ_MASK		0x00ffffff
-#define MP_SHORTSEQ_MASK	0x00000fff
-#define MP_LONGSEQ_MAX		MP_LONGSEQ_MASK
-#define MP_SHORTSEQ_MAX		MP_SHORTSEQ_MASK
-#define MP_LONGSEQ_MAXBIT	((MP_LONGSEQ_MASK+1)>>1)
-#define MP_SHORTSEQ_MAXBIT	((MP_SHORTSEQ_MASK+1)>>1)
-
-/* sequence-wrap safe comparisions (for long sequence)*/ 
-#define MP_LT(a,b)	((a-b)&MP_LONGSEQ_MAXBIT)
-#define MP_LE(a,b) 	!((b-a)&MP_LONGSEQ_MAXBIT)
-#define MP_GT(a,b) 	((b-a)&MP_LONGSEQ_MAXBIT)
-#define MP_GE(a,b)	!((a-b)&MP_LONGSEQ_MAXBIT)
-
-#define MP_SEQUENCE(skb) (skb)->priority
-#define MP_FLAGS(skb)    (skb)->cb[0]
-
-static u32
-get_seq(struct sk_buff *skb, u32 last_seq, int short_seq)
-{
-	u32 seq;
-	u16 shseq;
-	u8  flags;
-	int delta;
-   
-	get_u8(skb->data, &flags);
-   	if (short_seq) {
-		/* convert 12-bit short seq number to 24-bit long one */
-		get_u16(skb->data, &shseq);
-		delta = (shseq & MP_SHORTSEQ_MASK) - 
-			(last_seq & MP_SHORTSEQ_MASK);
-		/* check for seqence wrap */
-		if (delta < 0)
-			delta += MP_SHORTSEQ_MAX + 1;
-
-		seq = last_seq + delta;
-		skb_pull(skb, 2);
-	} else {
-		get_u32(skb->data, &seq);
-		skb_pull(skb, 4);
-	}
-	seq &= MP_LONGSEQ_MASK;
-	MP_SEQUENCE(skb) = seq;
-	MP_FLAGS(skb) = flags;
-	return seq;
-}
-
-static int
-mp_insert_frag(struct sk_buff_head *frags, struct sk_buff *skb)
-{
-	struct sk_buff *p;
-
-	/* If our queue of not yet reassembled fragments grows too
-	   large, throw away the oldest fragment */
-	if (skb_queue_len(frags) > MP_MAX_QUEUE_LEN)
-		kfree_skb(skb_dequeue(frags));
-	
-	for (p = frags->next; p != (struct sk_buff *) frags; p = p->next) {
-		if (MP_LE(MP_SEQUENCE(skb), MP_SEQUENCE(p)))
-			break;
-	}
-	/* duplicate ? */
-	if (MP_SEQUENCE(skb) == MP_SEQUENCE(p))
-		return -EBUSY;
-
-	__skb_insert(skb, p->prev, p, frags);
-	return 0;
-}
-
-struct sk_buff *
-mp_complete_seq(isdn_net_local *lp, struct sk_buff *b, struct sk_buff *e)
-{
-	struct sk_buff *p, *n, *skb;
-	int len = 0;
-
-	if (b->next == e) {
-		/* sequence with only one frag */
-		skb_unlink(b);
-		return b;
-	}
-	for (p = b, n = p->next; p != e; p = n, n = p->next ) {
-		len += p->len;
-	}
-	// FIXME check against mrru?
-	skb = dev_alloc_skb(len);
-	if (!skb)
-		lp->stats.rx_errors++;
-
-	for (p = b, n = p->next; p != e; p = n, n = p->next ) {
-		if (skb)
-			memcpy(skb_put(skb, p->len), p->data, p->len);
-		
-		skb_unlink(p);
-		kfree_skb(p);
-	}
-	return skb;
-}
-
-struct sk_buff *
-mp_reassemble(isdn_net_local *lp)
-{
-	struct inl_ppp *inl_ppp = lp->inl_priv;
-	struct sk_buff_head *frags = &inl_ppp->mp_frags;
-	struct sk_buff *p, *n, *pp, *start;
-	u32 min_seq = inl_ppp->mp_rxseq;
-	u32 next_seq = 0;
-
- again:
-	start = NULL;
-	for (p = frags->next, n = p->next; p != (struct sk_buff *) frags; p = n, n = p->next ) {
-		if (!start) {
-			if (MP_FLAGS(p) & MP_BEGIN_FRAG) {
-				start = p;
-				next_seq = MP_SEQUENCE(p);
-			} else {
-				/* start frag is missing */
-				goto frag_missing;
-			}
-		}
-		/* we've seen the first fragment of this series */
-		if (MP_SEQUENCE(p) != next_seq) {
-			/* previous frag is missing */
-			goto frag_missing;
-		}
-		if (MP_FLAGS(p) & MP_END_FRAG) {
-			/* we got a full sequence */
-			return mp_complete_seq(lp, start, p->next);
-		}
-		next_seq = MP_SEQUENCE(p) + 1;
-	}
-	return NULL;
-	
- frag_missing:
-	if (MP_SEQUENCE(p) - 1 > min_seq)
-		/* may come later */
-		return NULL;
-
-	/* for all fragments up to p */
-	p = p->next;
-	for (pp = frags->next, n = pp->next; pp != p; pp = n, n = pp->next ) {
-		skb_unlink(pp);
-		kfree_skb(pp);
-		lp->stats.rx_errors++;
-	}
-	goto again;
-
-}
-
-static void
-mp_receive(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	isdn_net_local *lp = idev->mlp;
-	struct inl_ppp *inl_ppp = lp->inl_priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	isdn_net_dev *qdev;
-	struct sk_buff_head *frags = &inl_ppp->mp_frags;
-	u32 seq;
-	u16 proto;
-
-	if (skb->len < (inl_ppp->mp_cfg & SC_IN_SHORT_SEQ ? 2 : 4))
-		goto drop;
-
-	seq = get_seq(skb, ind_ppp->mp_rxseq, inl_ppp->mp_cfg & SC_IN_SHORT_SEQ);
-	ind_ppp->mp_rxseq = seq;
-
-	if (inl_ppp->mp_rxseq == (u32) -1) { 
-		/* first packet */
-		inl_ppp->mp_rxseq = seq;
-	}
-	if (MP_LT(seq, inl_ppp->mp_rxseq)) {
-		goto drop;
-	}
-	/* Find the minimum sequence number received over all channels.
-	 * No fragments with numbers lower than this will arrive later. */
-	inl_ppp->mp_rxseq = seq;
-	list_for_each_entry(qdev, &lp->online, online) {
-		struct ind_ppp *ind_ppp = qdev->ind_priv;
-		if (MP_LT(ind_ppp->mp_rxseq, inl_ppp->mp_rxseq))
-			inl_ppp->mp_rxseq = ind_ppp->mp_rxseq;
-	}
-
-	/* Insert the skb into the list of received fragments, ordered by
-	 * sequence number */
-	if (mp_insert_frag(frags, skb))
-		goto drop;
-
-	while ((skb = mp_reassemble(lp))) {
-		if (isdn_ppp_strip_proto(skb, &proto)) {
-			kfree_skb(skb);
-			continue;
-		}
-		ippp_receive(idev, skb, proto);
-	}
-	return;
-	
- drop:
-	lp->stats.rx_errors++;
-	kfree_skb(skb);
-}
--- diff/drivers/isdn/i4l/isdn_ppp_mp.h	2003-05-21 11:49:50.000000000 +0100
+++ source/drivers/isdn/i4l/isdn_ppp_mp.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,58 +0,0 @@
-/* Linux ISDN subsystem, PPP CCP support
- *
- * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- *           1995,96    by Thinking Objects Software GmbH Wuerzburg
- *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef __ISDN_PPP_MP_H__
-#define __ISDN_PPP_MP_H__
-
-#include "isdn_net_lib.h"
-
-#ifdef CONFIG_ISDN_MPP
-
-int  ippp_mp_bind(isdn_net_dev *idev);
-void ippp_mp_disconnected(isdn_net_dev *idev);
-int  ippp_mp_bundle(isdn_net_dev *idev, int val);
-void ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb);
-void ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto);
-
-#else
-
-static inline int
-ippp_mp_bind(isdn_net_dev *idev)
-{
-	return 0;
-}
-
-static void
-ippp_mp_disconnected(isdn_net_dev *idev)
-{
-}
-
-static inline int
-ippp_mp_bundle(isdn_net_dev *idev, int val)
-{
-	return -EINVAL;
-}
-
-static inline void
-ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb)
-{
-	ippp_xmit(idev, skb);
-}
-
-static inline void 
-ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
-{
-	ippp_receive(idev, skb, proto);
-}
-
-#endif
-
-#endif
--- diff/drivers/isdn/i4l/isdn_ppp_vj.c	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ppp_vj.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,128 +0,0 @@
-/* Linux ISDN subsystem, PPP VJ header compression
- *
- * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include "isdn_ppp_vj.h"
-#include "isdn_common.h"
-#include "isdn_net_lib.h"
-#include "isdn_ppp.h"
-
-struct slcompress *
-ippp_vj_alloc(void)
-{
-	return slhc_init(16, 16);
-}
-
-void
-ippp_vj_free(struct slcompress *slcomp)
-{
-	slhc_free(slcomp);
-}
-
-int
-ippp_vj_set_maxcid(isdn_net_dev *idev, int val)
-{
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-	struct slcompress *sltmp;
-
-	sltmp = slhc_init(16, val + 1);
-	if (!sltmp)
-		return -ENOMEM;
-
-	if (inl_ppp->slcomp)
-		slhc_free(inl_ppp->slcomp);
-
-	inl_ppp->slcomp = sltmp;
-	return 0;
-}
-
-void
-ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto)
-{
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-	struct slcompress *slcomp = inl_ppp->slcomp;
-	struct sk_buff *skb;
-	int len;
-
-	switch (proto) {
-	case PPP_VJC_UNCOMP:
-		if (slhc_remember(slcomp, skb_old->data, skb_old->len) <= 0)
-			goto drop;
-		
-		skb = skb_old;
-		break;
-	case PPP_VJC_COMP:
-		skb = dev_alloc_skb(skb_old->len + 128);
-		if (!skb)
-			goto drop;
-
-		memcpy(skb->data, skb_old->data, skb_old->len);
-		len = slhc_uncompress(slcomp, skb->data, skb_old->len);
-		if (len < 0)
-			goto drop_both;
-
-		skb_put(skb, len);
-		kfree_skb(skb_old);
-		break;
-	default:
-		isdn_BUG();
-		goto drop;
-	}
-	isdn_netif_rx(idev, skb, htons(ETH_P_IP));
-	return;
-
- drop_both:
-	kfree_skb(skb);
- drop:
-	kfree_skb(skb_old);
-	idev->mlp->stats.rx_dropped++;
-}
-
-struct sk_buff *
-ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto)
-{
-	struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
-	struct ind_ppp *ind_ppp = idev->ind_priv;
-	struct slcompress *slcomp = inl_ppp->slcomp;
-	struct sk_buff *skb;
-	unsigned char *buf;
-	int len;
-
-	if (!(ind_ppp->pppcfg & SC_COMP_TCP) || *proto != PPP_IP)
-		return skb_old;
-
-	skb = isdn_ppp_dev_alloc_skb(idev, skb_old->len, GFP_ATOMIC);
-	if (!skb)
-		return skb_old;
-
-	skb_put(skb, skb_old->len);
-	buf = skb_old->data;
-	// FIXME flag should be per bundle
-	len = slhc_compress(slcomp, skb_old->data, skb_old->len, skb->data,
-			    &buf, !(ind_ppp->pppcfg & SC_NO_TCP_CCID)); 
-
-	if (buf == skb_old->data) {
-		kfree_skb(skb);
-		skb = skb_old;
-	} else {
-		kfree_skb(skb_old);
-	}
-	skb_trim(skb, len);
-			
-	/* cslip style -> PPP */
-	if ((skb->data[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) {
-		skb->data[0] &= ~SL_TYPE_COMPRESSED_TCP;
-		*proto = PPP_VJC_COMP;
-	} else if ((skb->data[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) {
-		skb->data[0] &= ~SL_TYPE_UNCOMPRESSED_TCP;
-		skb->data[0] |= SL_TYPE_IP;
-		*proto = PPP_VJC_UNCOMP;
-	}
-	return skb;
-}
-
--- diff/drivers/isdn/i4l/isdn_ppp_vj.h	2002-11-11 11:09:36.000000000 +0000
+++ source/drivers/isdn/i4l/isdn_ppp_vj.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,61 +0,0 @@
-/* Linux ISDN subsystem, PPP VJ header compression
- *
- * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef __ISDN_PPP_VJ_H__
-#define __ISDN_PPP_VJ_H__
-
-#include "isdn_net_lib.h"
-
-#ifdef CONFIG_ISDN_PPP_VJ
-
-
-struct slcompress *
-ippp_vj_alloc(void);
-
-void
-ippp_vj_free(struct slcompress *slcomp);
-
-int
-ippp_vj_set_maxcid(isdn_net_dev *idev, int val);
-
-void
-ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto);
-
-struct sk_buff *
-ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto);
-
-
-#else
-
-
-static inline struct slcompress *
-ippp_vj_alloc(void)
-{ return (struct slcompress *) !NULL; }
-
-static inline void
-ippp_vj_free(struct slcompress *slcomp) 
-{ }
-
-static inline int
-ippp_vj_set_maxcid(isdn_net_dev *idev, int val)
-{ return -EINVAL; }
-
-static inline struct sk_buff *
-ippp_vj_decompress(struct slcompress *slcomp, struct sk_buff *skb_old, 
-		   u16 proto)
-{ return skb_old; }
-
-static inline struct sk_buff *
-ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto)
-{ return skb_old; }
-
-
-#endif
-
-#endif
--- diff/drivers/net/e100/LICENSE	2002-10-16 04:28:27.000000000 +0100
+++ source/drivers/net/e100/LICENSE	1970-01-01 01:00:00.000000000 +0100
@@ -1,339 +0,0 @@
-
-"This software program is licensed subject to the GNU General Public License 
-(GPL). Version 2, June 1991, available at 
-<http://www.fsf.org/copyleft/gpl.html>"
-
-GNU General Public License 
-
-Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
-59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
-
-Everyone is permitted to copy and distribute verbatim copies of this license
-document, but changing it is not allowed.
-
-Preamble
-
-The licenses for most software are designed to take away your freedom to 
-share and change it. By contrast, the GNU General Public License is intended
-to guarantee your freedom to share and change free software--to make sure 
-the software is free for all its users. This General Public License applies 
-to most of the Free Software Foundation's software and to any other program 
-whose authors commit to using it. (Some other Free Software Foundation 
-software is covered by the GNU Library General Public License instead.) You 
-can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the freedom 
-to distribute copies of free software (and charge for this service if you 
-wish), that you receive source code or can get it if you want it, that you 
-can change the software or use pieces of it in new free programs; and that 
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to 
-deny you these rights or to ask you to surrender the rights. These 
-restrictions translate to certain responsibilities for you if you distribute
-copies of the software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or 
-for a fee, you must give the recipients all the rights that you have. You 
-must make sure that they, too, receive or can get the source code. And you 
-must show them these terms so they know their rights.
- 
-We protect your rights with two steps: (1) copyright the software, and (2) 
-offer you this license which gives you legal permission to copy, distribute 
-and/or modify the software. 
-
-Also, for each author's protection and ours, we want to make certain that 
-everyone understands that there is no warranty for this free software. If 
-the software is modified by someone else and passed on, we want its 
-recipients to know that what they have is not the original, so that any 
-problems introduced by others will not reflect on the original authors' 
-reputations. 
-
-Finally, any free program is threatened constantly by software patents. We 
-wish to avoid the danger that redistributors of a free program will 
-individually obtain patent licenses, in effect making the program 
-proprietary. To prevent this, we have made it clear that any patent must be 
-licensed for everyone's free use or not licensed at all. 
-
-The precise terms and conditions for copying, distribution and modification 
-follow. 
-
-TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-   placed by the copyright holder saying it may be distributed under the 
-   terms of this General Public License. The "Program", below, refers to any
-   such program or work, and a "work based on the Program" means either the 
-   Program or any derivative work under copyright law: that is to say, a 
-   work containing the Program or a portion of it, either verbatim or with 
-   modifications and/or translated into another language. (Hereinafter, 
-   translation is included without limitation in the term "modification".) 
-   Each licensee is addressed as "you". 
-
-   Activities other than copying, distribution and modification are not 
-   covered by this License; they are outside its scope. The act of running 
-   the Program is not restricted, and the output from the Program is covered 
-   only if its contents constitute a work based on the Program (independent 
-   of having been made by running the Program). Whether that is true depends
-   on what the Program does. 
-
-1. You may copy and distribute verbatim copies of the Program's source code 
-   as you receive it, in any medium, provided that you conspicuously and 
-   appropriately publish on each copy an appropriate copyright notice and 
-   disclaimer of warranty; keep intact all the notices that refer to this 
-   License and to the absence of any warranty; and give any other recipients 
-   of the Program a copy of this License along with the Program. 
-
-   You may charge a fee for the physical act of transferring a copy, and you 
-   may at your option offer warranty protection in exchange for a fee. 
-
-2. You may modify your copy or copies of the Program or any portion of it, 
-   thus forming a work based on the Program, and copy and distribute such 
-   modifications or work under the terms of Section 1 above, provided that 
-   you also meet all of these conditions: 
-
-   * a) You must cause the modified files to carry prominent notices stating 
-        that you changed the files and the date of any change. 
-
-   * b) You must cause any work that you distribute or publish, that in 
-        whole or in part contains or is derived from the Program or any part 
-        thereof, to be licensed as a whole at no charge to all third parties
-        under the terms of this License. 
-
-   * c) If the modified program normally reads commands interactively when 
-        run, you must cause it, when started running for such interactive 
-        use in the most ordinary way, to print or display an announcement 
-        including an appropriate copyright notice and a notice that there is
-        no warranty (or else, saying that you provide a warranty) and that 
-        users may redistribute the program under these conditions, and 
-        telling the user how to view a copy of this License. (Exception: if 
-        the Program itself is interactive but does not normally print such 
-        an announcement, your work based on the Program is not required to 
-        print an announcement.) 
-
-   These requirements apply to the modified work as a whole. If identifiable 
-   sections of that work are not derived from the Program, and can be 
-   reasonably considered independent and separate works in themselves, then 
-   this License, and its terms, do not apply to those sections when you 
-   distribute them as separate works. But when you distribute the same 
-   sections as part of a whole which is a work based on the Program, the 
-   distribution of the whole must be on the terms of this License, whose 
-   permissions for other licensees extend to the entire whole, and thus to 
-   each and every part regardless of who wrote it. 
-
-   Thus, it is not the intent of this section to claim rights or contest 
-   your rights to work written entirely by you; rather, the intent is to 
-   exercise the right to control the distribution of derivative or 
-   collective works based on the Program. 
-
-   In addition, mere aggregation of another work not based on the Program 
-   with the Program (or with a work based on the Program) on a volume of a 
-   storage or distribution medium does not bring the other work under the 
-   scope of this License. 
-
-3. You may copy and distribute the Program (or a work based on it, under 
-   Section 2) in object code or executable form under the terms of Sections 
-   1 and 2 above provided that you also do one of the following: 
-
-   * a) Accompany it with the complete corresponding machine-readable source 
-        code, which must be distributed under the terms of Sections 1 and 2 
-        above on a medium customarily used for software interchange; or, 
-
-   * b) Accompany it with a written offer, valid for at least three years, 
-        to give any third party, for a charge no more than your cost of 
-        physically performing source distribution, a complete machine-
-        readable copy of the corresponding source code, to be distributed 
-        under the terms of Sections 1 and 2 above on a medium customarily 
-        used for software interchange; or, 
-
-   * c) Accompany it with the information you received as to the offer to 
-        distribute corresponding source code. (This alternative is allowed 
-        only for noncommercial distribution and only if you received the 
-        program in object code or executable form with such an offer, in 
-        accord with Subsection b above.) 
-
-   The source code for a work means the preferred form of the work for 
-   making modifications to it. For an executable work, complete source code 
-   means all the source code for all modules it contains, plus any 
-   associated interface definition files, plus the scripts used to control 
-   compilation and installation of the executable. However, as a special 
-   exception, the source code distributed need not include anything that is 
-   normally distributed (in either source or binary form) with the major 
-   components (compiler, kernel, and so on) of the operating system on which
-   the executable runs, unless that component itself accompanies the 
-   executable. 
-
-   If distribution of executable or object code is made by offering access 
-   to copy from a designated place, then offering equivalent access to copy 
-   the source code from the same place counts as distribution of the source 
-   code, even though third parties are not compelled to copy the source 
-   along with the object code. 
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-   expressly provided under this License. Any attempt otherwise to copy, 
-   modify, sublicense or distribute the Program is void, and will 
-   automatically terminate your rights under this License. However, parties 
-   who have received copies, or rights, from you under this License will not
-   have their licenses terminated so long as such parties remain in full 
-   compliance. 
-
-5. You are not required to accept this License, since you have not signed 
-   it. However, nothing else grants you permission to modify or distribute 
-   the Program or its derivative works. These actions are prohibited by law 
-   if you do not accept this License. Therefore, by modifying or 
-   distributing the Program (or any work based on the Program), you 
-   indicate your acceptance of this License to do so, and all its terms and
-   conditions for copying, distributing or modifying the Program or works 
-   based on it. 
-
-6. Each time you redistribute the Program (or any work based on the 
-   Program), the recipient automatically receives a license from the 
-   original licensor to copy, distribute or modify the Program subject to 
-   these terms and conditions. You may not impose any further restrictions 
-   on the recipients' exercise of the rights granted herein. You are not 
-   responsible for enforcing compliance by third parties to this License. 
-
-7. If, as a consequence of a court judgment or allegation of patent 
-   infringement or for any other reason (not limited to patent issues), 
-   conditions are imposed on you (whether by court order, agreement or 
-   otherwise) that contradict the conditions of this License, they do not 
-   excuse you from the conditions of this License. If you cannot distribute 
-   so as to satisfy simultaneously your obligations under this License and 
-   any other pertinent obligations, then as a consequence you may not 
-   distribute the Program at all. For example, if a patent license would 
-   not permit royalty-free redistribution of the Program by all those who 
-   receive copies directly or indirectly through you, then the only way you 
-   could satisfy both it and this License would be to refrain entirely from 
-   distribution of the Program. 
-
-   If any portion of this section is held invalid or unenforceable under any
-   particular circumstance, the balance of the section is intended to apply
-   and the section as a whole is intended to apply in other circumstances. 
-
-   It is not the purpose of this section to induce you to infringe any 
-   patents or other property right claims or to contest validity of any 
-   such claims; this section has the sole purpose of protecting the 
-   integrity of the free software distribution system, which is implemented 
-   by public license practices. Many people have made generous contributions
-   to the wide range of software distributed through that system in 
-   reliance on consistent application of that system; it is up to the 
-   author/donor to decide if he or she is willing to distribute software 
-   through any other system and a licensee cannot impose that choice. 
-
-   This section is intended to make thoroughly clear what is believed to be 
-   a consequence of the rest of this License. 
-
-8. If the distribution and/or use of the Program is restricted in certain 
-   countries either by patents or by copyrighted interfaces, the original 
-   copyright holder who places the Program under this License may add an 
-   explicit geographical distribution limitation excluding those countries, 
-   so that distribution is permitted only in or among countries not thus 
-   excluded. In such case, this License incorporates the limitation as if 
-   written in the body of this License. 
-
-9. The Free Software Foundation may publish revised and/or new versions of 
-   the General Public License from time to time. Such new versions will be 
-   similar in spirit to the present version, but may differ in detail to 
-   address new problems or concerns. 
-
-   Each version is given a distinguishing version number. If the Program 
-   specifies a version number of this License which applies to it and "any 
-   later version", you have the option of following the terms and 
-   conditions either of that version or of any later version published by 
-   the Free Software Foundation. If the Program does not specify a version 
-   number of this License, you may choose any version ever published by the 
-   Free Software Foundation. 
-
-10. If you wish to incorporate parts of the Program into other free programs
-    whose distribution conditions are different, write to the author to ask 
-    for permission. For software which is copyrighted by the Free Software 
-    Foundation, write to the Free Software Foundation; we sometimes make 
-    exceptions for this. Our decision will be guided by the two goals of 
-    preserving the free status of all derivatives of our free software and 
-    of promoting the sharing and reuse of software generally. 
-
-   NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
-    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
-    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
-    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
-    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
-    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
-    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
-    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
-    NECESSARY SERVICING, REPAIR OR CORRECTION. 
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
-    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
-    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
-    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
-    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
-    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
-    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
-    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
-    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
-
-END OF TERMS AND CONDITIONS
-
-How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest 
-possible use to the public, the best way to achieve this is to make it free 
-software which everyone can redistribute and change under these terms. 
-
-To do so, attach the following notices to the program. It is safest to 
-attach them to the start of each source file to most effectively convey the
-exclusion of warranty; and each file should have at least the "copyright" 
-line and a pointer to where the full notice is found. 
-
-one line to give the program's name and an idea of what it does.
-Copyright (C) yyyy  name of author
-
-This program is free software; you can redistribute it and/or modify it 
-under the terms of the GNU General Public License as published by the Free 
-Software Foundation; either version 2 of the License, or (at your option) 
-any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT 
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc., 59 
-Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-Also add information on how to contact you by electronic and paper mail. 
-
-If the program is interactive, make it output a short notice like this when 
-it starts in an interactive mode: 
-
-Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
-with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
-software, and you are welcome to redistribute it under certain conditions; 
-type 'show c' for details.
-
-The hypothetical commands 'show w' and 'show c' should show the appropriate 
-parts of the General Public License. Of course, the commands you use may be 
-called something other than 'show w' and 'show c'; they could even be 
-mouse-clicks or menu items--whatever suits your program. 
-
-You should also get your employer (if you work as a programmer) or your 
-school, if any, to sign a "copyright disclaimer" for the program, if 
-necessary. Here is a sample; alter the names: 
-
-Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
-'Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-signature of Ty Coon, 1 April 1989
-Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into 
-proprietary programs. If your program is a subroutine library, you may 
-consider it more useful to permit linking proprietary applications with the 
-library. If this is what you want to do, use the GNU Library General Public 
-License instead of this License.
--- diff/drivers/net/e100/Makefile	2003-02-13 11:46:52.000000000 +0000
+++ source/drivers/net/e100/Makefile	1970-01-01 01:00:00.000000000 +0100
@@ -1,8 +0,0 @@
-#
-# Makefile for the Intel's E100 ethernet driver
-#
-
-obj-$(CONFIG_E100) += e100.o
-
-e100-objs := e100_main.o e100_config.o e100_phy.o \
-	     e100_eeprom.o e100_test.o
--- diff/drivers/net/e100/e100.h	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/net/e100/e100.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,999 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef _E100_INC_
-#define _E100_INC_
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <linux/reboot.h>
-#include <asm/io.h>
-#include <asm/unaligned.h>
-#include <asm/processor.h>
-#include <linux/ethtool.h>
-#include <linux/inetdevice.h>
-#include <linux/bitops.h>
-
-#include <linux/if.h>
-#include <asm/uaccess.h>
-#include <linux/ip.h>
-#include <linux/if_vlan.h>
-#include <linux/mii.h>
-
-#define E100_CABLE_UNKNOWN	0
-#define E100_CABLE_OK		1		
-#define E100_CABLE_OPEN_NEAR	2	/* Open Circuit Near End  */
-#define E100_CABLE_OPEN_FAR	3	/* Open Circuit Far End   */
-#define E100_CABLE_SHORT_NEAR	4	/* Short Circuit Near End */
-#define E100_CABLE_SHORT_FAR	5	/* Short Circuit Far End  */
-
-#define E100_REGS_LEN 2
-/*
- *  Configure parameters for buffers per controller.
- *  If the machine this is being used on is a faster machine (i.e. > 150MHz)
- *  and running on a 10MBS network then more queueing of data occurs. This
- *  may indicate the some of the numbers below should be adjusted.  Here are
- *  some typical numbers:
- *                             MAX_TCB 64
- *                             MAX_RFD 64
- *  The default numbers give work well on most systems tests so no real
- *  adjustments really need to take place.  Also, if the machine is connected
- *  to a 100MBS network the numbers described above can be lowered from the
- *  defaults as considerably less data will be queued.
- */
-
-#define TX_FRAME_CNT   8	/* consecutive transmit frames per interrupt */
-/* TX_FRAME_CNT must be less than MAX_TCB    */
-
-#define E100_DEFAULT_TCB   64
-#define E100_MIN_TCB       2*TX_FRAME_CNT + 3	/* make room for at least 2 interrupts */
-#define E100_MAX_TCB       1024
-
-#define E100_DEFAULT_RFD   64
-#define E100_MIN_RFD       8
-#define E100_MAX_RFD       1024
-
-#define E100_DEFAULT_XSUM         true
-#define E100_DEFAULT_BER          ZLOCK_MAX_ERRORS
-#define E100_DEFAULT_SPEED_DUPLEX 0
-#define E100_DEFAULT_FC           0
-#define E100_DEFAULT_IFS          true
-#define E100_DEFAULT_UCODE        true
-
-#define TX_THRSHLD     8
-
-/* IFS parameters */
-#define MIN_NUMBER_OF_TRANSMITS_100 1000
-#define MIN_NUMBER_OF_TRANSMITS_10  100
-
-#define E100_MAX_NIC 16
-
-#define E100_MAX_SCB_WAIT	100	/* Max udelays in wait_scb */
-#define E100_MAX_CU_IDLE_WAIT	50	/* Max udelays in wait_cus_idle */
-
-/* HWI feature related constant */
-#define HWI_REGISTER_GRANULARITY        80	/* register granularity = 80 Cm */
-#define HWI_NEAR_END_BOUNDARY           1000	/* Near end is defined as < 10 meters */
-
-/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled.
- * In some situations, such as the TCP windowing algorithm, it may be
- * better to limit the growth of the bundle size than let it go as
- * high as it can, because that could cause too much added latency.
- * The default is six, because this is the number of packets in the
- * default TCP window size.  A value of 1 would make CPUSaver indicate
- * an interrupt for every frame received.  If you do not want to put
- * a limit on the bundle size, set this value to xFFFF.
- */
-#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX	6
-#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY	0x600
-#define E100_DEFAULT_BUNDLE_SMALL_FR		false
-
-/* end of configurables */
-
-/* ====================================================================== */
-/*                                hw                                      */
-/* ====================================================================== */
-
-/* timeout for command completion */
-#define E100_CMD_WAIT   100	/* iterations */
-
-struct driver_stats {
-	struct net_device_stats net_stats;
-
-	unsigned long tx_late_col;
-	unsigned long tx_ok_defrd;
-	unsigned long tx_one_retry;
-	unsigned long tx_mt_one_retry;
-	unsigned long rcv_cdt_frames;
-	unsigned long xmt_fc_pkts;
-	unsigned long rcv_fc_pkts;
-	unsigned long rcv_fc_unsupported;
-	unsigned long xmt_tco_pkts;
-	unsigned long rcv_tco_pkts;
-	unsigned long rx_intr_pkts;
-};
-
-/* TODO: kill me when we can do C99 */
-#define false		(0)
-#define true		(1)
-
-/* Changed for 82558 and 82559 enhancements */
-/* defines for 82558/9 flow control CSR values */
-#define DFLT_FC_THLD       0x00	/* Rx FIFO threshold of 0.5KB free  */
-#define DFLT_FC_CMD        0x00	/* FC Command in CSR */
-
-/* ====================================================================== */
-/*                              equates                                   */
-/* ====================================================================== */
-
-/*
- * These are general purpose defines 
- */
-
-/* Bit Mask definitions */
-#define BIT_0       0x0001
-#define BIT_1       0x0002
-#define BIT_2       0x0004
-#define BIT_3       0x0008
-#define BIT_4       0x0010
-#define BIT_5       0x0020
-#define BIT_6       0x0040
-#define BIT_7       0x0080
-#define BIT_8       0x0100
-#define BIT_9       0x0200
-#define BIT_10      0x0400
-#define BIT_11      0x0800
-#define BIT_12      0x1000
-#define BIT_13      0x2000
-#define BIT_14      0x4000
-#define BIT_15      0x8000
-#define BIT_28      0x10000000
-
-#define BIT_0_2     0x0007
-#define BIT_0_3     0x000F
-#define BIT_0_4     0x001F
-#define BIT_0_5     0x003F
-#define BIT_0_6     0x007F
-#define BIT_0_7     0x00FF
-#define BIT_0_8     0x01FF
-#define BIT_0_13    0x3FFF
-#define BIT_0_15    0xFFFF
-#define BIT_1_2     0x0006
-#define BIT_1_3     0x000E
-#define BIT_2_5     0x003C
-#define BIT_3_4     0x0018
-#define BIT_4_5     0x0030
-#define BIT_4_6     0x0070
-#define BIT_4_7     0x00F0
-#define BIT_5_7     0x00E0
-#define BIT_5_12    0x1FE0
-#define BIT_5_15    0xFFE0
-#define BIT_6_7     0x00c0
-#define BIT_7_11    0x0F80
-#define BIT_8_10    0x0700
-#define BIT_9_13    0x3E00
-#define BIT_12_15   0xF000
-#define BIT_8_15    0xFF00
-
-#define BIT_16_20   0x001F0000
-#define BIT_21_25   0x03E00000
-#define BIT_26_27   0x0C000000
-
-/* Transmit Threshold related constants */
-#define DEFAULT_TX_PER_UNDERRUN         20000
-
-#define MAX_MULTICAST_ADDRS             64
-#define MAX_FILTER                      16
-
-#define FULL_DUPLEX      2
-#define HALF_DUPLEX      1
-
-/*
- * These defines are specific to the 82557 
- */
-
-/* E100 PORT functions -- lower 4 bits */
-#define PORT_SOFTWARE_RESET         0
-#define PORT_SELFTEST               1
-#define PORT_SELECTIVE_RESET        2
-#define PORT_DUMP                   3
-
-/* SCB Status Word bit definitions */
-/* Interrupt status/ack fields */
-/* ER and FCP interrupts for 82558 masks  */
-#define SCB_STATUS_ACK_MASK        BIT_8_15	/* Status Mask */
-#define SCB_STATUS_ACK_CX          BIT_15	/* CU Completed Action Cmd */
-#define SCB_STATUS_ACK_FR          BIT_14	/* RU Received A Frame */
-#define SCB_STATUS_ACK_CNA         BIT_13	/* CU Became Inactive (IDLE) */
-#define SCB_STATUS_ACK_RNR         BIT_12	/* RU Became Not Ready */
-#define SCB_STATUS_ACK_MDI         BIT_11	/* MDI read or write done */
-#define SCB_STATUS_ACK_SWI         BIT_10	/* S/W generated interrupt */
-#define SCB_STATUS_ACK_ER          BIT_9	/* Early Receive */
-#define SCB_STATUS_ACK_FCP         BIT_8	/* Flow Control Pause */
-
-/*- CUS Fields */
-#define SCB_CUS_MASK            (BIT_6 | BIT_7)	/* CUS 2-bit Mask */
-#define SCB_CUS_IDLE            0	/* CU Idle */
-#define SCB_CUS_SUSPEND         BIT_6	/* CU Suspended */
-#define SCB_CUS_ACTIVE          BIT_7	/* CU Active */
-
-/*- RUS Fields */
-#define SCB_RUS_IDLE            0	/* RU Idle */
-#define SCB_RUS_MASK            BIT_2_5	/* RUS 3-bit Mask */
-#define SCB_RUS_SUSPEND         BIT_2	/* RU Suspended */
-#define SCB_RUS_NO_RESOURCES    BIT_3	/* RU Out Of Resources */
-#define SCB_RUS_READY           BIT_4	/* RU Ready */
-#define SCB_RUS_SUSP_NO_RBDS    (BIT_2 | BIT_5)	/* RU No More RBDs */
-#define SCB_RUS_NO_RBDS         (BIT_3 | BIT_5)	/* RU No More RBDs */
-#define SCB_RUS_READY_NO_RBDS   (BIT_4 | BIT_5)	/* RU Ready, No RBDs */
-
-/* SCB Command Word bit definitions */
-/*- CUC fields */
-/* Changing mask to 4 bits */
-#define SCB_CUC_MASK            BIT_4_7	/* CUC 4-bit Mask */
-#define SCB_CUC_NOOP            0
-#define SCB_CUC_START           BIT_4	/* CU Start */
-#define SCB_CUC_RESUME          BIT_5	/* CU Resume */
-#define SCB_CUC_UNKNOWN         BIT_7	/* CU unknown command */
-/* Changed for 82558 enhancements */
-#define SCB_CUC_STATIC_RESUME   (BIT_5 | BIT_7)	/* 82558/9 Static Resume */
-#define SCB_CUC_DUMP_ADDR       BIT_6	/* CU Dump Counters Address */
-#define SCB_CUC_DUMP_STAT       (BIT_4 | BIT_6)	/* CU Dump stat. counters */
-#define SCB_CUC_LOAD_BASE       (BIT_5 | BIT_6)	/* Load the CU base */
-/* Below was defined as BIT_4_7 */
-#define SCB_CUC_DUMP_RST_STAT   BIT_4_6	/* CU Dump & reset statistics cntrs */
-
-/*- RUC fields */
-#define SCB_RUC_MASK            BIT_0_2	/* RUC 3-bit Mask */
-#define SCB_RUC_START           BIT_0	/* RU Start */
-#define SCB_RUC_RESUME          BIT_1	/* RU Resume */
-#define SCB_RUC_ABORT           BIT_2	/* RU Abort */
-#define SCB_RUC_LOAD_HDS        (BIT_0 | BIT_2)	/* Load RFD Header Data Size */
-#define SCB_RUC_LOAD_BASE       (BIT_1 | BIT_2)	/* Load the RU base */
-#define SCB_RUC_RBD_RESUME      BIT_0_2	/* RBD resume */
-
-/* Interrupt fields (assuming byte addressing) */
-#define SCB_INT_MASK            BIT_0	/* Mask interrupts */
-#define SCB_SOFT_INT            BIT_1	/* Generate a S/W interrupt */
-/*  Specific Interrupt Mask Bits (upper byte of SCB Command word) */
-#define SCB_FCP_INT_MASK        BIT_2	/* Flow Control Pause */
-#define SCB_ER_INT_MASK         BIT_3	/* Early Receive */
-#define SCB_RNR_INT_MASK        BIT_4	/* RU Not Ready */
-#define SCB_CNA_INT_MASK        BIT_5	/* CU Not Active */
-#define SCB_FR_INT_MASK         BIT_6	/* Frame Received */
-#define SCB_CX_INT_MASK         BIT_7	/* CU eXecution w/ I-bit done */
-#define SCB_BACHELOR_INT_MASK   BIT_2_7	/* 82558 interrupt mask bits */
-
-#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7
-
-/* EEPROM bit definitions */
-/*- EEPROM control register bits */
-#define EEPROM_FLAG_ASF  0x8000
-#define EEPROM_FLAG_GCL  0x4000
-
-#define EN_TRNF          0x10	/* Enable turnoff */
-#define EEDO             0x08	/* EEPROM data out */
-#define EEDI             0x04	/* EEPROM data in (set for writing data) */
-#define EECS             0x02	/* EEPROM chip select (1=hi, 0=lo) */
-#define EESK             0x01	/* EEPROM shift clock (1=hi, 0=lo) */
-
-/*- EEPROM opcodes */
-#define EEPROM_READ_OPCODE          06
-#define EEPROM_WRITE_OPCODE         05
-#define EEPROM_ERASE_OPCODE         07
-#define EEPROM_EWEN_OPCODE          19	/* Erase/write enable */
-#define EEPROM_EWDS_OPCODE          16	/* Erase/write disable */
-
-/*- EEPROM data locations */
-#define EEPROM_NODE_ADDRESS_BYTE_0      0
-#define EEPROM_COMPATIBILITY_WORD       3
-#define EEPROM_PWA_NO                   8
-#define EEPROM_ID_WORD			0x0A
-#define EEPROM_CONFIG_ASF		0x0D
-#define EEPROM_SMBUS_ADDR		0x90
-
-#define EEPROM_SUM                      0xbaba
-
-// Zero Locking Algorithm definitions:
-#define ZLOCK_ZERO_MASK		0x00F0
-#define ZLOCK_MAX_READS		50	
-#define ZLOCK_SET_ZERO		0x2010
-#define ZLOCK_MAX_SLEEP		300 * HZ	
-#define ZLOCK_MAX_ERRORS	300
-
-/* E100 Action Commands */
-#define CB_IA_ADDRESS           1
-#define CB_CONFIGURE            2
-#define CB_MULTICAST            3
-#define CB_TRANSMIT             4
-#define CB_LOAD_MICROCODE       5
-#define CB_LOAD_FILTER		8
-#define CB_MAX_NONTX_CMD        9
-#define CB_IPCB_TRANSMIT        9
-
-/* Pre-defined Filter Bits */
-#define CB_FILTER_EL            0x80000000
-#define CB_FILTER_FIX           0x40000000
-#define CB_FILTER_ARP           0x08000000
-#define CB_FILTER_IA_MATCH      0x02000000
-
-/* Command Block (CB) Field Definitions */
-/*- CB Command Word */
-#define CB_EL_BIT           BIT_15	/* CB EL Bit */
-#define CB_S_BIT            BIT_14	/* CB Suspend Bit */
-#define CB_I_BIT            BIT_13	/* CB Interrupt Bit */
-#define CB_TX_SF_BIT        BIT_3	/* TX CB Flexible Mode */
-#define CB_CMD_MASK         BIT_0_3	/* CB 4-bit CMD Mask */
-#define CB_CID_DEFAULT      (0x1f << 8)	/* CB 5-bit CID (max value) */
-
-/*- CB Status Word */
-#define CB_STATUS_MASK          BIT_12_15	/* CB Status Mask (4-bits) */
-#define CB_STATUS_COMPLETE      BIT_15	/* CB Complete Bit */
-#define CB_STATUS_OK            BIT_13	/* CB OK Bit */
-#define CB_STATUS_VLAN          BIT_12 /* CB Valn detected Bit */
-#define CB_STATUS_FAIL          BIT_11	/* CB Fail (F) Bit */
-
-/*misc command bits */
-#define CB_TX_EOF_BIT           BIT_15	/* TX CB/TBD EOF Bit */
-
-/* Config params */
-#define CB_CFIG_BYTE_COUNT          22	/* 22 config bytes */
-#define CB_CFIG_D102_BYTE_COUNT    10
-
-/* Receive Frame Descriptor Fields */
-
-/*- RFD Status Bits */
-#define RFD_RECEIVE_COLLISION   BIT_0	/* Collision detected on Receive */
-#define RFD_IA_MATCH            BIT_1	/* Indv Address Match Bit */
-#define RFD_RX_ERR              BIT_4	/* RX_ERR pin on Phy was set */
-#define RFD_FRAME_TOO_SHORT     BIT_7	/* Receive Frame Short */
-#define RFD_DMA_OVERRUN         BIT_8	/* Receive DMA Overrun */
-#define RFD_NO_RESOURCES        BIT_9	/* No Buffer Space */
-#define RFD_ALIGNMENT_ERROR     BIT_10	/* Alignment Error */
-#define RFD_CRC_ERROR           BIT_11	/* CRC Error */
-#define RFD_STATUS_OK           BIT_13	/* RFD OK Bit */
-#define RFD_STATUS_COMPLETE     BIT_15	/* RFD Complete Bit */
-
-/*- RFD Command Bits*/
-#define RFD_EL_BIT      BIT_15	/* RFD EL Bit */
-#define RFD_S_BIT       BIT_14	/* RFD Suspend Bit */
-#define RFD_H_BIT       BIT_4	/* Header RFD Bit */
-#define RFD_SF_BIT      BIT_3	/* RFD Flexible Mode */
-
-/*- RFD misc bits*/
-#define RFD_EOF_BIT         BIT_15	/* RFD End-Of-Frame Bit */
-#define RFD_F_BIT           BIT_14	/* RFD Buffer Fetch Bit */
-#define RFD_ACT_COUNT_MASK  BIT_0_13	/* RFD Actual Count Mask */
-
-/* Receive Buffer Descriptor Fields*/
-#define RBD_EOF_BIT             BIT_15	/* RBD End-Of-Frame Bit */
-#define RBD_F_BIT               BIT_14	/* RBD Buffer Fetch Bit */
-#define RBD_ACT_COUNT_MASK      BIT_0_13	/* RBD Actual Count Mask */
-
-#define SIZE_FIELD_MASK     BIT_0_13	/* Size of the associated buffer */
-#define RBD_EL_BIT          BIT_15	/* RBD EL Bit */
-
-/* Self Test Results*/
-#define CB_SELFTEST_FAIL_BIT        BIT_12
-#define CB_SELFTEST_DIAG_BIT        BIT_5
-#define CB_SELFTEST_REGISTER_BIT    BIT_3
-#define CB_SELFTEST_ROM_BIT         BIT_2
-
-#define CB_SELFTEST_ERROR_MASK ( \
-                CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \
-                CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT)
-
-/* adapter vendor & device ids */
-#define PCI_OHIO_BOARD   0x10f0	/* subdevice ID, Ohio dual port nic */
-
-/* Values for PCI_REV_ID_REGISTER values */
-#define D101A4_REV_ID      4	/* 82558 A4 stepping */
-#define D101B0_REV_ID      5	/* 82558 B0 stepping */
-#define D101MA_REV_ID      8	/* 82559 A0 stepping */
-#define D101S_REV_ID      9	/* 82559S A-step */
-#define D102_REV_ID      12
-#define D102C_REV_ID     13	/* 82550 step C */
-#define D102E_REV_ID     15
-
-/* ############Start of 82555 specific defines################## */
-
-#define PHY_82555_LED_SWITCH_CONTROL    	0x1b	/* 82555 led switch control register */
-
-/* 82555 led switch control reg. opcodes */
-#define PHY_82555_LED_NORMAL_CONTROL    0	// control back to the 8255X
-#define PHY_82555_LED_DRIVER_CONTROL    BIT_2	// the driver is in control
-#define PHY_82555_LED_OFF               BIT_2	// activity LED is off
-#define PHY_82555_LED_ON_559           (BIT_0 | BIT_2)	// activity LED is on for 559 and later
-#define PHY_82555_LED_ON_PRE_559       (BIT_0 | BIT_1 | BIT_2)	// activity LED is on for 558 and before
-
-// Describe the state of the phy led.
-// needed for the function : 'e100_blink_timer'
-enum led_state_e {
-	LED_OFF = 0,
-	LED_ON,
-};
-
-/* ############End of 82555 specific defines##################### */
-
-#define RFD_PARSE_BIT			BIT_3
-#define RFD_TCP_PACKET			0x00
-#define RFD_UDP_PACKET			0x01
-#define TCPUDP_CHECKSUM_BIT_VALID	BIT_4
-#define TCPUDP_CHECKSUM_VALID		BIT_5
-#define CHECKSUM_PROTOCOL_MASK		0x03
-
-#define VLAN_SIZE   4
-#define CHKSUM_SIZE 2
-#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE)
-
-/* Bits for bdp->flags */
-#define DF_LINK_FC_CAP     0x00000001	/* Link is flow control capable */
-#define DF_CSUM_OFFLOAD    0x00000002
-#define DF_UCODE_LOADED    0x00000004
-#define USE_IPCB           0x00000008	/* set if using ipcb for transmits */
-#define IS_BACHELOR        0x00000010	/* set if 82558 or newer board */
-#define IS_ICH             0x00000020
-#define DF_SPEED_FORCED    0x00000040	/* set if speed is forced */
-#define LED_IS_ON	   0x00000080	/* LED is turned ON by the driver */
-#define DF_LINK_FC_TX_ONLY 0x00000100	/* Received PAUSE frames are honored*/
-
-typedef struct net_device_stats net_dev_stats_t;
-
-/* needed macros */
-/* These macros use the bdp pointer. If you use them it better be defined */
-#define PREV_TCB_USED(X)  ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1)
-#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1)
-#define TCB_TO_USE(X)     ((X).tail)
-#define TCBS_AVAIL(X)     (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head)
-
-#define RFD_POINTER(skb,bdp)      ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size)))
-#define SKB_RFD_STATUS(skb,bdp)   ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status)
-
-/* ====================================================================== */
-/*                              82557                                     */
-/* ====================================================================== */
-
-/* Changed for 82558 enhancement */
-typedef struct _d101_scb_ext_t {
-	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
-	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
-	u8 scb_fc_thld;	/* Flow Control threshold */
-	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
-	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
-} d101_scb_ext __attribute__ ((__packed__));
-
-/* Changed for 82559 enhancement */
-typedef struct _d101m_scb_ext_t {
-	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
-	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
-	u8 scb_fc_thld;	/* Flow Control threshold */
-	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
-	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
-	u8 scb_gen_ctrl;	/* General Control */
-	u8 scb_gen_stat;	/* General Status */
-	u16 scb_reserved;	/* Reserved */
-	u32 scb_function_event;	/* Cardbus Function Event */
-	u32 scb_function_event_mask;	/* Cardbus Function Mask */
-	u32 scb_function_present_state;	/* Cardbus Function state */
-	u32 scb_force_event;	/* Cardbus Force Event */
-} d101m_scb_ext __attribute__ ((__packed__));
-
-/* Changed for 82550 enhancement */
-typedef struct _d102_scb_ext_t {
-	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
-	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
-	u8 scb_fc_thld;	/* Flow Control threshold */
-	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
-	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
-	u8 scb_gen_ctrl;	/* General Control */
-	u8 scb_gen_stat;	/* General Status */
-	u8 scb_gen_ctrl2;
-	u8 scb_reserved;	/* Reserved */
-	u32 scb_scheduling_reg;
-	u32 scb_reserved2;
-	u32 scb_function_event;	/* Cardbus Function Event */
-	u32 scb_function_event_mask;	/* Cardbus Function Mask */
-	u32 scb_function_present_state;	/* Cardbus Function state */
-	u32 scb_force_event;	/* Cardbus Force Event */
-} d102_scb_ext __attribute__ ((__packed__));
-
-/*
- * 82557 status control block. this will be memory mapped & will hang of the
- * the bdp, which hangs of the bdp. This is the brain of it.
- */
-typedef struct _scb_t {
-	u16 scb_status;	/* SCB Status register */
-	u8 scb_cmd_low;	/* SCB Command register (low byte) */
-	u8 scb_cmd_hi;	/* SCB Command register (high byte) */
-	u32 scb_gen_ptr;	/* SCB General pointer */
-	u32 scb_port;	/* PORT register */
-	u16 scb_flsh_cntrl;	/* Flash Control register */
-	u16 scb_eprm_cntrl;	/* EEPROM control register */
-	u32 scb_mdi_cntrl;	/* MDI Control Register */
-	/* Changed for 82558 enhancement */
-	union {
-		u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
-		d101_scb_ext d101_scb;	/* 82558/9 specific fields */
-		d101m_scb_ext d101m_scb;	/* 82559 specific fields */
-		d102_scb_ext d102_scb;
-	} scb_ext;
-} scb_t __attribute__ ((__packed__));
-
-/* Self test
- * This is used to dump results of the self test 
- */
-typedef struct _self_test_t {
-	u32 st_sign;	/* Self Test Signature */
-	u32 st_result;	/* Self Test Results */
-} self_test_t __attribute__ ((__packed__));
-
-/* 
- *  Statistical Counters 
- */
-/* 82557 counters */
-typedef struct _basic_cntr_t {
-	u32 xmt_gd_frames;	/* Good frames transmitted */
-	u32 xmt_max_coll;	/* Fatal frames -- had max collisions */
-	u32 xmt_late_coll;	/* Fatal frames -- had a late coll. */
-	u32 xmt_uruns;	/* Xmit underruns (fatal or re-transmit) */
-	u32 xmt_lost_crs;	/* Frames transmitted without CRS */
-	u32 xmt_deferred;	/* Deferred transmits */
-	u32 xmt_sngl_coll;	/* Transmits that had 1 and only 1 coll. */
-	u32 xmt_mlt_coll;	/* Transmits that had multiple coll. */
-	u32 xmt_ttl_coll;	/* Transmits that had 1+ collisions. */
-	u32 rcv_gd_frames;	/* Good frames received */
-	u32 rcv_crc_errs;	/* Aligned frames that had a CRC error */
-	u32 rcv_algn_errs;	/* Receives that had alignment errors */
-	u32 rcv_rsrc_err;	/* Good frame dropped cuz no resources */
-	u32 rcv_oruns;	/* Overrun errors - bus was busy */
-	u32 rcv_err_coll;	/* Received frms. that encountered coll. */
-	u32 rcv_shrt_frames;	/* Received frames that were to short */
-} basic_cntr_t;
-
-/* 82558 extended statistic counters */
-typedef struct _ext_cntr_t {
-	u32 xmt_fc_frames;
-	u32 rcv_fc_frames;
-	u32 rcv_fc_unsupported;
-} ext_cntr_t;
-
-/* 82559 TCO statistic counters */
-typedef struct _tco_cntr_t {
-	u16 xmt_tco_frames;
-	u16 rcv_tco_frames;
-} tco_cntr_t;
-
-/* Structures to access thet physical dump area */
-/* Use one of these types, according to the statisitcal counters mode,
-   to cast the pointer to the physical dump area and access the cmd_complete
-   DWORD. */
-
-/* 557-mode : only basic counters + cmd_complete */
-typedef struct _err_cntr_557_t {
-	basic_cntr_t basic_stats;
-	u32 cmd_complete;
-} err_cntr_557_t;
-
-/* 558-mode : basic + extended counters + cmd_complete */
-typedef struct _err_cntr_558_t {
-	basic_cntr_t basic_stats;
-	ext_cntr_t extended_stats;
-	u32 cmd_complete;
-} err_cntr_558_t;
-
-/* 559-mode : basic + extended + TCO counters + cmd_complete */
-typedef struct _err_cntr_559_t {
-	basic_cntr_t basic_stats;
-	ext_cntr_t extended_stats;
-	tco_cntr_t tco_stats;
-	u32 cmd_complete;
-} err_cntr_559_t;
-
-/* This typedef defines the struct needed to hold the largest number of counters */
-typedef err_cntr_559_t max_counters_t;
-
-/* Different statistical-counters mode the controller may be in */
-typedef enum _stat_mode_t {
-	E100_BASIC_STATS = 0,	/* 82557 stats : 16 counters / 16 dw */
-	E100_EXTENDED_STATS,	/* 82558 stats : 19 counters / 19 dw */
-	E100_TCO_STATS		/* 82559 stats : 21 counters / 20 dw */
-} stat_mode_t;
-
-/* dump statistical counters complete codes */
-#define DUMP_STAT_COMPLETED	0xA005
-#define DUMP_RST_STAT_COMPLETED	0xA007
-
-/* Command Block (CB) Generic Header Structure*/
-typedef struct _cb_header_t {
-	u16 cb_status;	/* Command Block Status */
-	u16 cb_cmd;	/* Command Block Command */
-	u32 cb_lnk_ptr;	/* Link To Next CB */
-} cb_header_t __attribute__ ((__packed__));
-
-//* Individual Address Command Block (IA_CB)*/
-typedef struct _ia_cb_t {
-	cb_header_t ia_cb_hdr;
-	u8 ia_addr[ETH_ALEN];
-} ia_cb_t __attribute__ ((__packed__));
-
-/* Configure Command Block (CONFIG_CB)*/
-typedef struct _config_cb_t {
-	cb_header_t cfg_cbhdr;
-	u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
-} config_cb_t __attribute__ ((__packed__));
-
-/* MultiCast Command Block (MULTICAST_CB)*/
-typedef struct _multicast_cb_t {
-	cb_header_t mc_cbhdr;
-	u16 mc_count;	/* Number of multicast addresses */
-	u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)];
-} mltcst_cb_t __attribute__ ((__packed__));
-
-#define UCODE_MAX_DWORDS	134
-/* Load Microcode Command Block (LOAD_UCODE_CB)*/
-typedef struct _load_ucode_cb_t {
-	cb_header_t load_ucode_cbhdr;
-	u32 ucode_dword[UCODE_MAX_DWORDS];
-} load_ucode_cb_t __attribute__ ((__packed__));
-
-/* Load Programmable Filter Data*/
-typedef struct _filter_cb_t {
-	cb_header_t filter_cb_hdr;
-	u32 filter_data[MAX_FILTER];
-} filter_cb_t __attribute__ ((__packed__));
-
-/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block 
- */
-typedef struct _nxmit_cb_t {
-	union {
-		config_cb_t config;
-		ia_cb_t setup;
-		load_ucode_cb_t load_ucode;
-		mltcst_cb_t multicast;
-		filter_cb_t filter;
-	} ntcb;
-} nxmit_cb_t __attribute__ ((__packed__));
-
-/*Block for queuing for postponed execution of the non-transmit commands*/
-typedef struct _nxmit_cb_entry_t {
-	struct list_head list_elem;
-	nxmit_cb_t *non_tx_cmd;
-	dma_addr_t dma_addr;
-	unsigned long expiration_time;
-} nxmit_cb_entry_t;
-
-/* States for postponed non tx commands execution */
-typedef enum _non_tx_cmd_state_t {
-	E100_NON_TX_IDLE = 0,	/* No queued NON-TX commands */
-	E100_WAIT_TX_FINISH,	/* Wait for completion of the TX activities */
-	E100_WAIT_NON_TX_FINISH	/* Wait for completion of the non TX command */
-} non_tx_cmd_state_t;
-
-/* some defines for the ipcb */
-#define IPCB_IP_CHECKSUM_ENABLE 	BIT_4
-#define IPCB_TCPUDP_CHECKSUM_ENABLE	BIT_5
-#define IPCB_TCP_PACKET 		BIT_6
-#define IPCB_LARGESEND_ENABLE 		BIT_7
-#define IPCB_HARDWAREPARSING_ENABLE	BIT_0
-#define IPCB_INSERTVLAN_ENABLE 		BIT_1
-#define IPCB_IP_ACTIVATION_DEFAULT      IPCB_HARDWAREPARSING_ENABLE
-
-/* Transmit Buffer Descriptor (TBD)*/
-typedef struct _tbd_t {
-	u32 tbd_buf_addr;	/* Physical Transmit Buffer Address */
-	u16 tbd_buf_cnt;	/* Actual Count Of Bytes */
-	u16 padd;
-} tbd_t __attribute__ ((__packed__));
-
-/* d102 specific fields */
-typedef struct _tcb_ipcb_t {
-	u16 schedule_low;
-	u8 ip_schedule;
-	u8 ip_activation_high;
-	u16 vlan;
-	u8 ip_header_offset;
-	u8 tcp_header_offset;
-	union {
-		u32 sec_rec_phys_addr;
-		u32 tbd_zero_address;
-	} tbd_sec_addr;
-	union {
-		u16 sec_rec_size;
-		u16 tbd_zero_size;
-	} tbd_sec_size;
-	u16 total_tcp_payload;
-} tcb_ipcb_t __attribute__ ((__packed__));
-
-#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS)
-
-/* Transmit Command Block (TCB)*/
-struct _tcb_t {
-	cb_header_t tcb_hdr;
-	u32 tcb_tbd_ptr;	/* TBD address */
-	u16 tcb_cnt;	/* Data Bytes In TCB past header */
-	u8 tcb_thrshld;	/* TX Threshold for FIFO Extender */
-	u8 tcb_tbd_num;
-
-	union {
-		tcb_ipcb_t ipcb;	/* d102 ipcb fields */
-		tbd_t tbd_array[E100_TBD_ARRAY_SIZE];
-	} tcbu;
-
-	/* From here onward we can dump anything we want as long as the
-	 * size of the total structure is a multiple of a paragraph
-	 * boundary ( i.e. -16 bit aligned ).
-	 */
-	tbd_t *tbd_ptr;
-
-	u32 tcb_tbd_dflt_ptr;	/* TBD address for non-segmented packet */
-	u32 tcb_tbd_expand_ptr;	/* TBD address for segmented packet */
-
-	struct sk_buff *tcb_skb;	/* the associated socket buffer */
-	dma_addr_t tcb_phys;	/* phys addr of the TCB */
-} __attribute__ ((__packed__));
-
-#define _TCB_T_
-typedef struct _tcb_t tcb_t;
-
-/* Receive Frame Descriptor (RFD) - will be using the simple model*/
-struct _rfd_t {
-	/* 8255x */
-	cb_header_t rfd_header;
-	u32 rfd_rbd_ptr;	/* Receive Buffer Descriptor Addr */
-	u16 rfd_act_cnt;	/* Number Of Bytes Received */
-	u16 rfd_sz;	/* Number Of Bytes In RFD */
-	/* D102 aka Gamla */
-	u16 vlanid;
-	u8 rcvparserstatus;
-	u8 reserved;
-	u16 securitystatus;
-	u8 checksumstatus;
-	u8 zerocopystatus;
-	u8 pad[8];	/* data should be 16 byte aligned */
-	u8 data[RFD_DATA_SIZE];
-
-} __attribute__ ((__packed__));
-
-#define _RFD_T_
-typedef struct _rfd_t rfd_t;
-
-/* Receive Buffer Descriptor (RBD)*/
-typedef struct _rbd_t {
-	u16 rbd_act_cnt;	/* Number Of Bytes Received */
-	u16 rbd_filler;
-	u32 rbd_lnk_addr;	/* Link To Next RBD */
-	u32 rbd_rcb_addr;	/* Receive Buffer Address */
-	u16 rbd_sz;	/* Receive Buffer Size */
-	u16 rbd_filler1;
-} rbd_t __attribute__ ((__packed__));
-
-/*
- * This structure is used to maintain a FIFO access to a resource that is 
- * maintained as a circular queue. The resource to be maintained is pointed
- * to by the "data" field in the structure below. In this driver the TCBs', 
- * TBDs' & RFDs' are maintained  as a circular queue & are managed thru this
- * structure.
- */
-typedef struct _buf_pool_t {
-	unsigned int head;	/* index to first used resource */
-	unsigned int tail;	/* index to last used resource */
-	void *data;		/* points to resource pool */
-} buf_pool_t;
-
-/*Rx skb holding structure*/
-struct rx_list_elem {
-	struct list_head list_elem;
-	dma_addr_t dma_addr;
-	struct sk_buff *skb;
-};
-
-enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT };
-enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING };
-enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP };
-
-/* 64 bit aligned size */
-#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7)
-
-typedef struct _bd_dma_able_t {
-	char selftest[E100_SIZE_64A(self_test_t)];
-	char stats_counters[E100_SIZE_64A(max_counters_t)];
-} bd_dma_able_t;
-
-/* bit masks for bool parameters */
-#define PRM_XSUMRX       0x00000001
-#define PRM_UCODE        0x00000002
-#define PRM_FC           0x00000004
-#define PRM_IFS          0x00000008
-#define PRM_BUNDLE_SMALL 0x00000010
-
-struct cfg_params {
-	int e100_speed_duplex;
-	int RxDescriptors;
-	int TxDescriptors;
-	int IntDelay;
-	int BundleMax;
-	int ber;
-	u32 b_params;
-};
-struct ethtool_lpbk_data{
-        dma_addr_t dma_handle;
-        tcb_t *tcb;
-        rfd_t *rfd;
-
-};
-
-struct e100_private {
-	struct vlan_group *vlgrp;
-	u32 flags;		/* board management flags */
-	u32 tx_per_underrun;	/* number of good tx frames per underrun */
-	unsigned int tx_count;	/* count of tx frames, so we can request an interrupt */
-	u8 tx_thld;		/* stores transmit threshold */
-	u16 eeprom_size;
-	u32 pwa_no;		/* PWA: xxxxxx-0xx */
-	u8 perm_node_address[ETH_ALEN];
-	struct list_head active_rx_list;	/* list of rx buffers */
-	struct list_head rx_struct_pool;	/* pool of rx buffer struct headers */
-	u16 rfd_size;			/* size of the adapter's RFD struct */
-	int skb_req;			/* number of skbs neede by the adapter */
-	u8 intr_mask;			/* mask for interrupt status */
-
-	void *dma_able;			/* dma allocated structs */
-	dma_addr_t dma_able_phys;
-	self_test_t *selftest;		/* pointer to self test area */
-	dma_addr_t selftest_phys;	/* phys addr of selftest */
-	max_counters_t *stats_counters;	/* pointer to stats table */
-	dma_addr_t stat_cnt_phys;	/* phys addr of stat counter area */
-
-	stat_mode_t stat_mode;	/* statistics mode: extended, TCO, basic */
-	scb_t *scb;		/* memory mapped ptr to 82557 scb */
-
-	tcb_t *last_tcb;	/* pointer to last tcb sent */
-	buf_pool_t tcb_pool;	/* adapter's TCB array */
-	dma_addr_t tcb_phys;	/* phys addr of start of TCBs */
-
-	u16 cur_line_speed;
-	u16 cur_dplx_mode;
-
-	struct net_device *device;
-	struct pci_dev *pdev;
-	struct driver_stats drv_stats;
-
-	u8 rev_id;		/* adapter PCI revision ID */
-
-	unsigned int phy_addr;	/* address of PHY component */
-	unsigned int PhyId;	/* ID of PHY component */
-	unsigned int PhyState;	/* state for the fix squelch algorithm */
-	unsigned int PhyDelay;	/* delay for the fix squelch algorithm */
-
-	/* Lock defintions for the driver */
-	spinlock_t bd_lock;		/* board lock */
-	spinlock_t bd_non_tx_lock;	/* Non transmit command lock  */
-	spinlock_t config_lock;		/* config block lock */
-	spinlock_t mdi_access_lock;	/* mdi lock */
-
-	struct timer_list watchdog_timer;	/* watchdog timer id */
-
-	/* non-tx commands parameters */
-	struct timer_list nontx_timer_id;	/* non-tx timer id */
-	struct list_head non_tx_cmd_list;
-	non_tx_cmd_state_t non_tx_command_state;
-	nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD];
-
-	enum next_cu_cmd_e next_cu_cmd;
-
-	/* Zero Locking Algorithm data members */
-	enum zlock_state_e zlock_state;
-	u8 zlock_read_data[16];	/* number of times each value 0-15 was read */
-	u16 zlock_read_cnt;	/* counts number of reads */
-	ulong zlock_sleep_cnt;	/* keeps track of "sleep" time */
-
-	u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
-
-	/* IFS params */
-	u8 ifs_state;
-	u8 ifs_value;
-
-	struct cfg_params params;	/* adapter's command line parameters */
-
-	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
-
-	/* WOL params for ethtool */
-	u32 wolsupported;
-	u32 wolopts;
-	u16 ip_lbytes;
-	struct ethtool_lpbk_data loopback;
-	struct timer_list blink_timer;	/* led blink timer id */
-
-#ifdef CONFIG_PM
-	u32 pci_state[16];
-#endif
-#ifdef E100_CU_DEBUG	
-	u8 last_cmd;
-	u8 last_sub_cmd;
-#endif	
-};
-
-#define E100_AUTONEG        0
-#define E100_SPEED_10_HALF  1
-#define E100_SPEED_10_FULL  2
-#define E100_SPEED_100_HALF 3
-#define E100_SPEED_100_FULL 4
-
-/********* function prototypes *************/
-extern int e100_open(struct net_device *);
-extern int e100_close(struct net_device *);
-extern void e100_isolate_driver(struct e100_private *bdp);
-extern unsigned char e100_hw_init(struct e100_private *);
-extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
-extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
-extern void e100_free_non_tx_cmd(struct e100_private *bdp,
-				 nxmit_cb_entry_t *non_tx_cmd);
-extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
-extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp,
-					  nxmit_cb_entry_t *cmd);
-extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout,
-				   u32 *st_result);
-extern unsigned char e100_get_link_state(struct e100_private *bdp);
-extern unsigned char e100_wait_scb(struct e100_private *bdp);
-
-extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset);
-extern unsigned char e100_configure_device(struct e100_private *bdp);
-#ifdef E100_CU_DEBUG
-extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
-#endif
-
-#define ROM_TEST_FAIL		0x01
-#define REGISTER_TEST_FAIL	0x02
-#define SELF_TEST_FAIL		0x04
-#define TEST_TIMEOUT		0x08
-
-enum test_offsets {
-	test_link,
-	test_eeprom,
-	test_self_test,
-	test_loopback_mac,
-	test_loopback_phy,
-	cable_diag,
-	max_test_res,  /* must be last */
-};
-
-#endif
--- diff/drivers/net/e100/e100_config.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/net/e100/e100_config.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,639 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-/**********************************************************************
-*                                                                     *
-* INTEL CORPORATION                                                   *
-*                                                                     *
-* This software is supplied under the terms of the license included   *
-* above.  All use of this driver must be in accordance with the terms *
-* of that license.                                                    *
-*                                                                     *
-* Module Name:  e100_config.c                                         *
-*                                                                     *
-* Abstract:     Functions for configuring the network adapter.        *
-*                                                                     *
-* Environment:  This file is intended to be specific to the Linux     *
-*               operating system.                                     *
-*                                                                     *
-**********************************************************************/
-#include "e100_config.h"
-
-static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable);
-
-static const u8 def_config[] = {
-	CB_CFIG_BYTE_COUNT,
-	0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01,
-	0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00,
-	0x40, 0xf2, 0x80, 0x3f, 0x05
-};
-
-/**
- * e100_config_init_82557 - config the 82557 adapter
- * @bdp: atapter's private data struct
- *
- * This routine will initialize the 82557 configure block.
- * All other init functions will only set values that are
- * different from the 82557 default.
- */
-void
-e100_config_init_82557(struct e100_private *bdp)
-{
-	/* initialize config block */
-	memcpy(bdp->config, def_config, sizeof (def_config));
-	bdp->config[0] = CB_CFIG_BYTE_COUNT;	/* just in case */
-
-	e100_config_ifs(bdp);
-
-	/*
-	 * Enable extended statistical counters (82558 and up) and TCO counters
-	 * (82559 and up) and set the statistical counters' mode in bdp 
-	 *  
-	 *  stat. mode      |    TCO stat. bit (2)  |  Extended stat. bit (5)
-	 * ------------------------------------------------------------------
-	 *  Basic (557)     |       0               |         1
-	 * ------------------------------------------------------------------
-	 *  Extended (558)  |       0               |         0
-	 * ------------------------------------------------------------------
-	 *  TCO (559)       |       1               |         1
-	 * ------------------------------------------------------------------
-	 *  Reserved        |       1               |         0
-	 * ------------------------------------------------------------------
-	 */
-	bdp->config[6] &= ~CB_CFIG_TCO_STAT;
-	bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
-	bdp->stat_mode = E100_BASIC_STATS;
-
-	/* Setup for MII or 503 operation.  The CRS+CDT bit should only be set */
-	/* when operating in 503 mode. */
-	if (bdp->phy_addr == 32) {
-		bdp->config[8] &= ~CB_CFIG_503_MII;
-		bdp->config[15] |= CB_CFIG_CRS_OR_CDT;
-	} else {
-		bdp->config[8] |= CB_CFIG_503_MII;
-		bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT;
-	}
-
-	e100_config_fc(bdp);
-	e100_config_force_dplx(bdp);
-	e100_config_promisc(bdp, false);
-	e100_config_mulcast_enbl(bdp, false);
-}
-
-static void
-e100_config_init_82558(struct e100_private *bdp)
-{
-	/* MWI enable. This should be turned on only if the adapter is a 82558/9
-	 * and if the PCI command reg. has enabled the MWI bit. */
-	bdp->config[3] |= CB_CFIG_MWI_EN;
-
-	bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS;
-
-	if (bdp->rev_id >= D101MA_REV_ID) {
-		/* this is 82559 and up - enable TCO counters */
-		bdp->config[6] |= CB_CFIG_TCO_STAT;
-		bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
-		bdp->stat_mode = E100_TCO_STATS;
-
-		if ((bdp->rev_id < D102_REV_ID) &&
-		    (bdp->params.b_params & PRM_XSUMRX) &&
-		    (bdp->pdev->device != 0x1209)) {
-
-			bdp->flags |= DF_CSUM_OFFLOAD;
-			bdp->config[9] |= 1;
-		}
-	} else {
-		/* this is 82558 */
-		bdp->config[6] &= ~CB_CFIG_TCO_STAT;
-		bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS;
-		bdp->stat_mode = E100_EXTENDED_STATS;
-	}
-
-	e100_config_long_rx(bdp, true);
-}
-
-static void
-e100_config_init_82550(struct e100_private *bdp)
-{
-	/* The D102 chip allows for 32 config bytes.  This value is
-	 * supposed to be in Byte 0.  Just add the extra bytes to
-	 * what was already setup in the block. */
-	bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
-
-	/* now we need to enable the extended RFD.  When this is
-	 * enabled, the immediated receive data buffer starts at offset
-	 * 32 from the RFD base address, instead of at offset 16. */
-	bdp->config[7] |= CB_CFIG_EXTENDED_RFD;
-
-	/* put the chip into D102 receive mode.  This is necessary
-	 * for any parsing and offloading features. */
-	bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE;
-
-	/* set the flag if checksum offloading was enabled */
-	if (bdp->params.b_params & PRM_XSUMRX) {
-		bdp->flags |= DF_CSUM_OFFLOAD;
-	}
-}
-
-/* Initialize the adapter's configure block */
-void
-e100_config_init(struct e100_private *bdp)
-{
-	e100_config_init_82557(bdp);
-
-	if (bdp->flags & IS_BACHELOR)
-		e100_config_init_82558(bdp);
-
-	if (bdp->rev_id >= D102_REV_ID)
-		e100_config_init_82550(bdp);
-}
-
-/**
- * e100_force_config - force a configure command
- * @bdp: atapter's private data struct
- *
- * This routine will force a configure command to the adapter.
- * The command will be executed in polled mode as interrupts
- * are _disabled_ at this time.
- *
- * Returns:
- *      true: if the configure command was successfully issued and completed
- *      false: otherwise
- */
-unsigned char
-e100_force_config(struct e100_private *bdp)
-{
-	spin_lock_bh(&(bdp->config_lock));
-
-	bdp->config[0] = CB_CFIG_BYTE_COUNT;
-	if (bdp->rev_id >= D102_REV_ID) {
-		/* The D102 chip allows for 32 config bytes.  This value is
-		   supposed to be in Byte 0.  Just add the extra bytes to
-		   what was already setup in the block. */
-		bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
-	}
-
-	spin_unlock_bh(&(bdp->config_lock));
-
-	// although we call config outside the lock, there is no
-	// race condition because config byte count has maximum value
-	return e100_config(bdp);
-}
-
-/**
- * e100_config - issue a configure command
- * @bdp: atapter's private data struct
- *
- * This routine will issue a configure command to the 82557.
- * This command will be executed in polled mode as interrupts
- * are _disabled_ at this time.
- *
- * Returns:
- *      true: if the configure command was successfully issued and completed
- *      false: otherwise
- */
-unsigned char
-e100_config(struct e100_private *bdp)
-{
-	cb_header_t *pntcb_hdr;
-	unsigned char res = true;
-	nxmit_cb_entry_t *cmd;
-
-	if (bdp->config[0] == 0) {
-		goto exit;
-	}
-
-	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
-		res = false;
-		goto exit;
-	}
-
-	pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
-	pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE);
-
-	spin_lock_bh(&bdp->config_lock);
-
-	if (bdp->config[0] < CB_CFIG_MIN_PARAMS) {
-		bdp->config[0] = CB_CFIG_MIN_PARAMS;
-	}
-
-	/* Copy the device's config block to the device's memory */
-	memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config,
-	       bdp->config[0]);
-	/* reset number of bytes to config next time */
-	bdp->config[0] = 0;
-
-	spin_unlock_bh(&bdp->config_lock);
-
-	res = e100_exec_non_cu_cmd(bdp, cmd);
-
-exit:
-	if (netif_running(bdp->device))
-		netif_wake_queue(bdp->device);
-	return res;
-}
-
-/**
- * e100_config_fc - config flow-control state
- * @bdp: adapter's private data struct
- *
- * This routine will enable or disable flow control support in the adapter's
- * config block. Flow control will be enable only if requested using the command
- * line option, and if the link is flow-contorl capable (both us and the link
- * partner). But, if link partner is capable of autoneg, but not capable of
- * flow control, received PAUSE	frames are still honored.
- */
-void
-e100_config_fc(struct e100_private *bdp)
-{
-	unsigned char enable = false;
-	/* 82557 doesn't support fc. Don't touch this option */
-	if (!(bdp->flags & IS_BACHELOR))
-		return;
-
-	/* Enable fc if requested and if the link supports it */
-	if ((bdp->params.b_params & PRM_FC) && (bdp->flags & 
-		(DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) {
-		enable = true;
-	}
-
-	spin_lock_bh(&(bdp->config_lock));
-
-	if (enable) {
-		if (bdp->flags & DF_LINK_FC_TX_ONLY) {
-			/* If link partner is capable of autoneg, but  */
-			/* not capable of flow control, Received PAUSE */
-			/* frames are still honored, i.e.,             */
-			/* transmitted frames would be paused by       */
-			/* incoming PAUSE frames                       */
-			bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
-			bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
-			bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART);
-			bdp->config[19] |= CB_CFIG_FC_REJECT;
-			bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
-		} else {
-			bdp->config[16] = DFLT_FC_DELAY_LSB;
-			bdp->config[17] = DFLT_FC_DELAY_MSB;
-			bdp->config[19] |= CB_CFIG_FC_OPTS;
-			bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
-		}
-	} else {
-		bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
-		bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
-		bdp->config[19] &= ~CB_CFIG_FC_OPTS;
-		bdp->config[19] |= CB_CFIG_TX_FC_DIS;
-	}
-	E100_CONFIG(bdp, 19);
-	spin_unlock_bh(&(bdp->config_lock));
-
-	return;
-}
-
-/**
- * e100_config_promisc - configure promiscuous mode
- * @bdp: atapter's private data struct
- * @enable: should we enable this option or not
- *
- * This routine will enable or disable promiscuous mode
- * in the adapter's config block.
- */
-void
-e100_config_promisc(struct e100_private *bdp, unsigned char enable)
-{
-	spin_lock_bh(&(bdp->config_lock));
-
-	/* if in promiscuous mode, save bad frames */
-	if (enable) {
-
-		if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) {
-			bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES;
-			E100_CONFIG(bdp, 6);
-		}
-
-		if (bdp->config[7] & (u8) BIT_0) {
-			bdp->config[7] &= (u8) (~BIT_0);
-			E100_CONFIG(bdp, 7);
-		}
-
-		if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) {
-			bdp->config[15] |= CB_CFIG_PROMISCUOUS;
-			E100_CONFIG(bdp, 15);
-		}
-
-	} else {		/* not in promiscuous mode */
-
-		if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) {
-			bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES;
-			E100_CONFIG(bdp, 6);
-		}
-
-		if (!(bdp->config[7] & (u8) BIT_0)) {
-			bdp->config[7] |= (u8) (BIT_0);
-			E100_CONFIG(bdp, 7);
-		}
-
-		if (bdp->config[15] & CB_CFIG_PROMISCUOUS) {
-			bdp->config[15] &= ~CB_CFIG_PROMISCUOUS;
-			E100_CONFIG(bdp, 15);
-		}
-	}
-
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-/**
- * e100_config_mulcast_enbl - configure allmulti mode
- * @bdp: atapter's private data struct
- * @enable: should we enable this option or not
- *
- * This routine will enable or disable reception of all multicast packets
- * in the adapter's config block.
- */
-void
-e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable)
-{
-	spin_lock_bh(&(bdp->config_lock));
-
-	/* this flag is used to enable receiving all multicast packet */
-	if (enable) {
-		if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) {
-			bdp->config[21] |= CB_CFIG_MULTICAST_ALL;
-			E100_CONFIG(bdp, 21);
-		}
-
-	} else {
-		if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) {
-			bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL;
-			E100_CONFIG(bdp, 21);
-		}
-	}
-
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-/**
- * e100_config_ifs - configure the IFS parameter
- * @bdp: atapter's private data struct
- *
- * This routine will configure the adaptive IFS value
- * in the adapter's config block. IFS values are only
- * relevant in half duplex, so set to 0 in full duplex.
- */
-void
-e100_config_ifs(struct e100_private *bdp)
-{
-	u8 value = 0;
-
-	spin_lock_bh(&(bdp->config_lock));
-
-	/* IFS value is only needed to be specified at half-duplex mode */
-	if (bdp->cur_dplx_mode == HALF_DUPLEX) {
-		value = (u8) bdp->ifs_value;
-	}
-
-	if (bdp->config[2] != value) {
-		bdp->config[2] = value;
-		E100_CONFIG(bdp, 2);
-	}
-
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-/**
- * e100_config_force_dplx - configure the forced full duplex mode
- * @bdp: atapter's private data struct
- *
- * This routine will enable or disable force full duplex
- * in the adapter's config block. If the PHY is 503, and
- * the duplex is full, consider the adapter forced.
- */
-void
-e100_config_force_dplx(struct e100_private *bdp)
-{
-	spin_lock_bh(&(bdp->config_lock));
-
-	/* We must force full duplex on if we are using PHY 0, and we are */
-	/* supposed to run in FDX mode. We do this because the e100 has only */
-	/* one FDX# input pin, and that pin will be connected to PHY 1. */
-	/* Changed the 'if' condition below to fix performance problem * at 10
-	 * full. The Phy was getting forced to full duplex while the MAC * was
-	 * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. *
-	 * This is how the condition was, initially. * This has been changed so
-	 * that the MAC gets forced to full duplex * simply if the user has
-	 * forced full duplex. * * if (( bdp->phy_addr == 0 ) && (
-	 * bdp->cur_dplx_mode == 2 )) */
-	/* The rest of the fix is in the PhyDetect code. */
-	if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) ||
-	    (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) ||
-	    ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) {
-		if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) {
-			bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX;
-			E100_CONFIG(bdp, 19);
-		}
-
-	} else {
-		if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) {
-			bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX);
-			E100_CONFIG(bdp, 19);
-		}
-	}
-
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-/**
- * e100_config_long_rx
- * @bdp: atapter's private data struct
- * @enable: should we enable this option or not
- *
- * This routine will enable or disable reception of larger packets.
- * This is needed by VLAN implementations.
- */
-static void
-e100_config_long_rx(struct e100_private *bdp, unsigned char enable)
-{
-	if (enable) {
-		if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
-			bdp->config[18] |= CB_CFIG_LONG_RX_OK;
-			E100_CONFIG(bdp, 18);
-		}
-
-	} else {
-		if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
-			bdp->config[18] &= ~CB_CFIG_LONG_RX_OK;
-			E100_CONFIG(bdp, 18);
-		}
-	}
-}
-
-/**
- * e100_config_wol
- * @bdp: atapter's private data struct
- *
- * This sets configuration options for PHY and Magic Packet WoL 
- */
-void
-e100_config_wol(struct e100_private *bdp)
-{
-	spin_lock_bh(&(bdp->config_lock));
-
-	if (bdp->wolopts & WAKE_PHY) {
-		bdp->config[9] |= CB_LINK_STATUS_WOL;
-	}
-	else {
-		/* Disable PHY WoL */
-		bdp->config[9] &= ~CB_LINK_STATUS_WOL;
-	}
-
-	if (bdp->wolopts & WAKE_MAGIC) {
-		bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE;
-	}
-	else {
-		/* Disable Magic Packet WoL */
-		bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE;
-	}
-
-	E100_CONFIG(bdp, 19);
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-void
-e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable)
-{
-	spin_lock_bh(&(bdp->config_lock));
-	if (enable) {
-		if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
-			bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE;
-			E100_CONFIG(bdp, 22);
-		}
-
-	} else {
-		if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) {
-			bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE;
-			E100_CONFIG(bdp, 22);
-		}
-	}
-	spin_unlock_bh(&(bdp->config_lock));
-}
-
-/**
- * e100_config_loopback_mode
- * @bdp: atapter's private data struct
- * @mode: loopback mode(phy/mac/none)
- *
- */
-unsigned char
-e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
-{
-	unsigned char bc_changed = false;
-	u8 config_byte;
-
-	spin_lock_bh(&(bdp->config_lock));
-
-	switch (mode) {
-	case NO_LOOPBACK:
-		config_byte = CB_CFIG_LOOPBACK_NORMAL;
-		break;
-	case MAC_LOOPBACK:
-		config_byte = CB_CFIG_LOOPBACK_INTERNAL;
-		break;
-	case PHY_LOOPBACK:
-		config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
-		break;
-	default:
-		printk(KERN_NOTICE "e100: e100_config_loopback_mode: "
-		       "Invalid argument 'mode': %d\n", mode);
-		goto exit;
-	}
-
-	if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
-
-		bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
-		bdp->config[10] |= config_byte;
-		E100_CONFIG(bdp, 10);
-		bc_changed = true;
-	}
-
-exit:
-	spin_unlock_bh(&(bdp->config_lock));
-	return bc_changed;
-}
-unsigned char
-e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
-{
-        unsigned char bc_changed = false;
- 
-        spin_lock_bh(&(bdp->config_lock));
- 
-        if (enable) {
-                if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
- 
-                        bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
-                        E100_CONFIG(bdp, 6);
-                        bc_changed = true;
-                }
- 
-        } else {
-                if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
- 
-                        bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
-                        E100_CONFIG(bdp, 6);
-                        bc_changed = true;
-                }
-        }
-        spin_unlock_bh(&(bdp->config_lock));
- 
-        return bc_changed;
-}
-unsigned char
-e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
-{
-        unsigned char bc_changed = false;
- 
-        spin_lock_bh(&(bdp->config_lock));
- 
-        if (enable) {
-                if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
- 
-                        bdp->config[7] |= CB_CFIG_DYNTBD_EN;
-                        E100_CONFIG(bdp, 7);
-                        bc_changed = true;
-                }
- 
-        } else {
-                if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
- 
-                        bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
-                        E100_CONFIG(bdp, 7);
-                        bc_changed = true;
-                }
-        }
-        spin_unlock_bh(&(bdp->config_lock));
- 
-        return bc_changed;
-}
-
--- diff/drivers/net/e100/e100_config.h	2003-09-30 15:46:15.000000000 +0100
+++ source/drivers/net/e100/e100_config.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,168 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef _E100_CONFIG_INC_
-#define _E100_CONFIG_INC_
-
-#include "e100.h"
-
-#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1))
-
-#define CB_CFIG_MIN_PARAMS         8
-
-/* byte 0 bit definitions*/
-#define CB_CFIG_BYTE_COUNT_MASK     BIT_0_5	/* Byte count occupies bit 5-0 */
-
-/* byte 1 bit definitions*/
-#define CB_CFIG_RXFIFO_LIMIT_MASK   BIT_0_4	/* RxFifo limit mask */
-#define CB_CFIG_TXFIFO_LIMIT_MASK   BIT_4_7	/* TxFifo limit mask */
-
-/* byte 2 bit definitions -- ADAPTIVE_IFS*/
-
-/* word 3 bit definitions -- RESERVED*/
-/* Changed for 82558 enhancements */
-/* byte 3 bit definitions */
-#define CB_CFIG_MWI_EN      BIT_0	/* Enable MWI on PCI bus */
-#define CB_CFIG_TYPE_EN     BIT_1	/* Type Enable */
-#define CB_CFIG_READAL_EN   BIT_2	/* Enable Read Align */
-#define CB_CFIG_TERMCL_EN   BIT_3	/* Cache line write  */
-
-/* byte 4 bit definitions*/
-#define CB_CFIG_RX_MIN_DMA_MASK     BIT_0_6	/* Rx minimum DMA count mask */
-
-/* byte 5 bit definitions*/
-#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6	/* Tx minimum DMA count mask */
-#define CB_CFIG_DMBC_EN         BIT_7	/* Enable Tx/Rx min. DMA counts */
-
-/* Changed for 82558 enhancements */
-/* byte 6 bit definitions*/
-#define CB_CFIG_LATE_SCB           BIT_0	/* Update SCB After New Tx Start */
-#define CB_CFIG_DIRECT_DMA_DIS     BIT_1	/* Direct DMA mode */
-#define CB_CFIG_TNO_INT            BIT_2	/* Tx Not OK Interrupt */
-#define CB_CFIG_TCO_STAT           BIT_2	/* TCO statistics in 559 and above */
-#define CB_CFIG_CI_INT             BIT_3	/* Command Complete Interrupt */
-#define CB_CFIG_EXT_TCB_DIS        BIT_4	/* Extended TCB */
-#define CB_CFIG_EXT_STAT_DIS       BIT_5	/* Extended Stats */
-#define CB_CFIG_SAVE_BAD_FRAMES    BIT_7	/* Save Bad Frames Enabled */
-
-/* byte 7 bit definitions*/
-#define CB_CFIG_DISC_SHORT_FRAMES   BIT_0	/* Discard Short Frames */
-#define CB_CFIG_DYNTBD_EN           BIT_7	/* Enable dynamic TBD */
-/* Enable extended RFD's on D102 */
-#define CB_CFIG_EXTENDED_RFD        BIT_5
-
-/* byte 8 bit definitions*/
-#define CB_CFIG_503_MII             BIT_0	/* 503 vs. MII mode */
-
-/* byte 9 bit definitions -- pre-defined all zeros*/
-#define CB_LINK_STATUS_WOL	BIT_5
-
-/* byte 10 bit definitions*/
-#define CB_CFIG_NO_SRCADR       BIT_3	/* No Source Address Insertion */
-#define CB_CFIG_PREAMBLE_LEN    BIT_4_5	/* Preamble Length */
-#define CB_CFIG_LOOPBACK_MODE   BIT_6_7	/* Loopback Mode */
-#define CB_CFIG_LOOPBACK_NORMAL 0
-#define CB_CFIG_LOOPBACK_INTERNAL BIT_6
-#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7
-
-/* byte 11 bit definitions*/
-#define CB_CFIG_LINEAR_PRIORITY     BIT_0_2	/* Linear Priority */
-
-/* byte 12 bit definitions*/
-#define CB_CFIG_LINEAR_PRI_MODE     BIT_0	/* Linear Priority mode */
-#define CB_CFIG_IFS_MASK            BIT_4_7	/* Interframe Spacing mask */
-
-/* byte 13 bit definitions -- pre-defined all zeros*/
-
-/* byte 14 bit definitions -- pre-defined 0xf2*/
-
-/* byte 15 bit definitions*/
-#define CB_CFIG_PROMISCUOUS         BIT_0	/* Promiscuous Mode Enable */
-#define CB_CFIG_BROADCAST_DIS       BIT_1	/* Broadcast Mode Disable */
-#define CB_CFIG_CRS_OR_CDT          BIT_7	/* CRS Or CDT */
-
-/* byte 16 bit definitions -- pre-defined all zeros*/
-#define DFLT_FC_DELAY_LSB  0x1f	/* Delay for outgoing Pause frames */
-#define DFLT_NO_FC_DELAY_LSB  0x00	/* no flow control default value */
-
-/* byte 17 bit definitions -- pre-defined 0x40*/
-#define DFLT_FC_DELAY_MSB  0x01	/* Delay for outgoing Pause frames */
-#define DFLT_NO_FC_DELAY_MSB  0x40	/* no flow control default value */
-
-/* byte 18 bit definitions*/
-#define CB_CFIG_STRIPPING           BIT_0	/* Padding Disabled */
-#define CB_CFIG_PADDING             BIT_1	/* Padding Disabled */
-#define CB_CFIG_CRC_IN_MEM          BIT_2	/* Transfer CRC To Memory */
-
-/* byte 19 bit definitions*/
-#define CB_CFIG_TX_ADDR_WAKE        BIT_0	/* Address Wakeup */
-#define CB_DISABLE_MAGPAK_WAKE      BIT_1	/* Magic Packet Wakeup disable */
-/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */
-#define CB_CFIG_TX_FC_DIS           BIT_2	/* Tx Flow Control Disable */
-#define CB_CFIG_FC_RESTOP           BIT_3	/* Rx Flow Control Restop */
-#define CB_CFIG_FC_RESTART          BIT_4	/* Rx Flow Control Restart */
-#define CB_CFIG_FC_REJECT           BIT_5	/* Rx Flow Control Restart */
-#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT)
-
-/* end 82558/9 specifics */
-
-#define CB_CFIG_FORCE_FDX           BIT_6	/* Force Full Duplex */
-#define CB_CFIG_FDX_ENABLE          BIT_7	/* Full Duplex Enabled */
-
-/* byte 20 bit definitions*/
-#define CB_CFIG_MULTI_IA            BIT_6	/* Multiple IA Addr */
-
-/* byte 21 bit definitions*/
-#define CB_CFIG_MULTICAST_ALL       BIT_3	/* Multicast All */
-
-/* byte 22 bit defines */
-#define CB_CFIG_RECEIVE_GAMLA_MODE  BIT_0	/* D102 receive mode */
-#define CB_CFIG_VLAN_DROP_ENABLE    BIT_1	/* vlan stripping */
-
-#define CB_CFIG_LONG_RX_OK	    BIT_3
-
-#define NO_LOOPBACK	0	
-#define MAC_LOOPBACK	0x01
-#define PHY_LOOPBACK	0x02
-
-/* function prototypes */
-extern void e100_config_init(struct e100_private *bdp);
-extern void e100_config_init_82557(struct e100_private *bdp);
-extern unsigned char e100_force_config(struct e100_private *bdp);
-extern unsigned char e100_config(struct e100_private *bdp);
-extern void e100_config_fc(struct e100_private *bdp);
-extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable);
-extern void e100_config_brdcast_dsbl(struct e100_private *bdp);
-extern void e100_config_mulcast_enbl(struct e100_private *bdp,
-				     unsigned char enable);
-extern void e100_config_ifs(struct e100_private *bdp);
-extern void e100_config_force_dplx(struct e100_private *bdp);
-extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
-extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
-extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
-extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable);
-#endif /* _E100_CONFIG_INC_ */
--- diff/drivers/net/e100/e100_eeprom.c	2003-05-21 11:49:55.000000000 +0100
+++ source/drivers/net/e100/e100_eeprom.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,565 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-/**********************************************************************
-*                                                                     *
-* INTEL CORPORATION                                                   *
-*                                                                     *
-* This software is supplied under the terms of the license included   *
-* above.  All use of this driver must be in accordance with the terms *
-* of that license.                                                    *
-*                                                                     *
-* Module Name:  e100_eeprom.c                                         *
-*                                                                     *
-* Abstract:     This module contains routines to read and write to a  *
-*               serial EEPROM                                         *
-*                                                                     *
-* Environment:  This file is intended to be specific to the Linux     *
-*               operating system.                                     *
-*                                                                     *
-**********************************************************************/
-#include "e100.h"
-
-#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl)
-
-#define CSR_GENERAL_CONTROL2_FIELD(bdp) \
-	           ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2)
-
-#define EEPROM_STALL_TIME	4
-#define EEPROM_CHECKSUM		((u16) 0xBABA)
-#define EEPROM_MAX_WORD_SIZE	256
-
-void e100_eeprom_cleanup(struct e100_private *adapter);
-u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
-static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg,
-				   u16 data);
-void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
-			     u16 size);
-u16 e100_eeprom_size(struct e100_private *adapter);
-u16 e100_eeprom_read(struct e100_private *adapter, u16 reg);
-
-static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count);
-static u16 shift_in_bits(struct e100_private *adapter);
-static void raise_clock(struct e100_private *adapter, u16 *x);
-static void lower_clock(struct e100_private *adapter, u16 *x);
-static u16 eeprom_wait_cmd_done(struct e100_private *adapter);
-static void eeprom_stand_by(struct e100_private *adapter);
-
-//----------------------------------------------------------------------------------------
-// Procedure:   eeprom_set_semaphore
-//
-// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR).
-//
-// Arguments:
-//      Adapter                 - Adapter context
-//
-// Returns:  true if success
-//           else return false 
-//
-//----------------------------------------------------------------------------------------
-
-inline u8
-eeprom_set_semaphore(struct e100_private *adapter)
-{
-	u16 data = 0;
-	unsigned long expiration_time = jiffies + HZ / 100 + 1;
-
-	do {
-		// Get current value of General Control 2
-		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
-
-		// Set bit 23 word 0x1C in the CSR.
-		data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE;
-		writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
-
-		// Check to see if this bit set or not.
-		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
-
-		if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) {
-			return true;
-		}
-
-		if (time_before(jiffies, expiration_time))
-			yield();
-		else
-			return false;
-
-	} while (true);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   eeprom_reset_semaphore
-//
-// Description: This function reset (write 0) Gamla EEPROM semaphore bit 
-//              (bit 23 word 0x1C in the CSR).
-//
-// Arguments:  struct e100_private * adapter - Adapter context
-//----------------------------------------------------------------------------------------
-
-inline void
-eeprom_reset_semaphore(struct e100_private *adapter)
-{
-	u16 data = 0;
-
-	data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
-	data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE);
-	writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   e100_eeprom_size
-//
-// Description: This routine determines the size of the EEPROM.  This value should be
-//              checked for validity - ie. is it too big or too small.  The size returned
-//              is then passed to the read/write functions.
-//
-// Returns:
-//      Size of the eeprom, or zero if an error occurred
-//----------------------------------------------------------------------------------------
-u16
-e100_eeprom_size(struct e100_private *adapter)
-{
-	u16 x, size = 1;	// must be one to accumulate a product
-
-	// if we've already stored this data, read from memory
-	if (adapter->eeprom_size) {
-		return adapter->eeprom_size;
-	}
-	// otherwise, read from the eeprom
-	// Set EEPROM semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		if (!eeprom_set_semaphore(adapter))
-			return 0;
-	}
-	// enable the eeprom by setting EECS.
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	x &= ~(EEDI | EEDO | EESK);
-	x |= EECS;
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	// write the read opcode
-	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
-
-	// experiment to discover the size of the eeprom.  request register zero
-	// and wait for the eeprom to tell us it has accepted the entire address.
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	do {
-		size *= 2;	// each bit of address doubles eeprom size
-		x |= EEDO;	// set bit to detect "dummy zero"
-		x &= ~EEDI;	// address consists of all zeros
-
-		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-		readw(&(adapter->scb->scb_status));
-		udelay(EEPROM_STALL_TIME);
-		raise_clock(adapter, &x);
-		lower_clock(adapter, &x);
-
-		// check for "dummy zero"
-		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-		if (size > EEPROM_MAX_WORD_SIZE) {
-			size = 0;
-			break;
-		}
-	} while (x & EEDO);
-
-	// read in the value requested
-	(void) shift_in_bits(adapter);
-	e100_eeprom_cleanup(adapter);
-
-	// Clear EEPROM Semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		eeprom_reset_semaphore(adapter);
-	}
-
-	return size;
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   eeprom_address_size
-//
-// Description: determines the number of bits in an address for the eeprom acceptable
-//              values are 64, 128, and 256
-// Arguments: size of the eeprom
-// Returns: bits in an address for that size eeprom
-//----------------------------------------------------------------------------------------
-
-static inline int
-eeprom_address_size(u16 size)
-{
-	int isize = size;
-	
-	return (ffs(isize) - 1);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   e100_eeprom_read
-//
-// Description: This routine serially reads one word out of the EEPROM.
-//
-// Arguments:
-//      adapter - our adapter context
-//      reg - EEPROM word to read.
-//
-// Returns:
-//      Contents of EEPROM word (reg).
-//----------------------------------------------------------------------------------------
-
-u16
-e100_eeprom_read(struct e100_private *adapter, u16 reg)
-{
-	u16 x, data, bits;
-
-	// Set EEPROM semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		if (!eeprom_set_semaphore(adapter))
-			return 0;
-	}
-	// eeprom size is initialized to zero
-	if (!adapter->eeprom_size)
-		adapter->eeprom_size = e100_eeprom_size(adapter);
-
-	bits = eeprom_address_size(adapter->eeprom_size);
-
-	// select EEPROM, reset bits, set EECS
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	x &= ~(EEDI | EEDO | EESK);
-	x |= EECS;
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	// write the read opcode and register number in that order
-	// The opcode is 3bits in length, reg is 'bits' bits long
-	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
-	shift_out_bits(adapter, reg, bits);
-
-	// Now read the data (16 bits) in from the selected EEPROM word
-	data = shift_in_bits(adapter);
-
-	e100_eeprom_cleanup(adapter);
-
-	// Clear EEPROM Semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		eeprom_reset_semaphore(adapter);
-	}
-
-	return data;
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   shift_out_bits
-//
-// Description: This routine shifts data bits out to the EEPROM.
-//
-// Arguments:
-//      data - data to send to the EEPROM.
-//      count - number of data bits to shift out.
-//
-// Returns: (none)
-//----------------------------------------------------------------------------------------
-
-static void
-shift_out_bits(struct e100_private *adapter, u16 data, u16 count)
-{
-	u16 x, mask;
-
-	mask = 1 << (count - 1);
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	x &= ~(EEDO | EEDI);
-
-	do {
-		x &= ~EEDI;
-		if (data & mask)
-			x |= EEDI;
-
-		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-		readw(&(adapter->scb->scb_status)); /* flush command to card */
-		udelay(EEPROM_STALL_TIME);
-		raise_clock(adapter, &x);
-		lower_clock(adapter, &x);
-		mask = mask >> 1;
-	} while (mask);
-
-	x &= ~EEDI;
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   raise_clock
-//
-// Description: This routine raises the EEPROM's clock input (EESK)
-//
-// Arguments:
-//      x - Ptr to the EEPROM control register's current value
-//
-// Returns: (none)
-//----------------------------------------------------------------------------------------
-
-void
-raise_clock(struct e100_private *adapter, u16 *x)
-{
-	*x = *x | EESK;
-	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-	readw(&(adapter->scb->scb_status)); /* flush command to card */
-	udelay(EEPROM_STALL_TIME);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   lower_clock
-//
-// Description: This routine lower's the EEPROM's clock input (EESK)
-//
-// Arguments:
-//      x - Ptr to the EEPROM control register's current value
-//
-// Returns: (none)
-//----------------------------------------------------------------------------------------
-
-void
-lower_clock(struct e100_private *adapter, u16 *x)
-{
-	*x = *x & ~EESK;
-	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-	readw(&(adapter->scb->scb_status)); /* flush command to card */
-	udelay(EEPROM_STALL_TIME);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   shift_in_bits
-//
-// Description: This routine shifts data bits in from the EEPROM.
-//
-// Arguments:
-//
-// Returns:
-//      The contents of that particular EEPROM word
-//----------------------------------------------------------------------------------------
-
-static u16
-shift_in_bits(struct e100_private *adapter)
-{
-	u16 x, d, i;
-
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	x &= ~(EEDO | EEDI);
-	d = 0;
-
-	for (i = 0; i < 16; i++) {
-		d <<= 1;
-		raise_clock(adapter, &x);
-
-		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-
-		x &= ~EEDI;
-		if (x & EEDO)
-			d |= 1;
-
-		lower_clock(adapter, &x);
-	}
-
-	return d;
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   e100_eeprom_cleanup
-//
-// Description: This routine returns the EEPROM to an idle state
-//----------------------------------------------------------------------------------------
-
-void
-e100_eeprom_cleanup(struct e100_private *adapter)
-{
-	u16 x;
-
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	x &= ~(EECS | EEDI);
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	raise_clock(adapter, &x);
-	lower_clock(adapter, &x);
-}
-
-//**********************************************************************************
-// Procedure:   e100_eeprom_update_chksum
-//
-// Description: Calculates the checksum and writes it to the EEProm. 
-//              It calculates the checksum accroding to the formula: 
-//                              Checksum = 0xBABA - (sum of first 63 words).
-//
-//-----------------------------------------------------------------------------------
-u16
-e100_eeprom_calculate_chksum(struct e100_private *adapter)
-{
-	u16 idx, xsum_index, checksum = 0;
-
-	// eeprom size is initialized to zero
-	if (!adapter->eeprom_size)
-		adapter->eeprom_size = e100_eeprom_size(adapter);
-
-	xsum_index = adapter->eeprom_size - 1;
-	for (idx = 0; idx < xsum_index; idx++)
-		checksum += e100_eeprom_read(adapter, idx);
-
-	checksum = EEPROM_CHECKSUM - checksum;
-	return checksum;
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   e100_eeprom_write_word
-//
-// Description: This routine writes a word to a specific EEPROM location without.
-//              taking EEPROM semaphore and updating checksum. 
-//              Use e100_eeprom_write_block for the EEPROM update
-// Arguments: reg - The EEPROM word that we are going to write to.
-//            data - The data (word) that we are going to write to the EEPROM.
-//----------------------------------------------------------------------------------------
-static void
-e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data)
-{
-	u16 x;
-	u16 bits;
-
-	bits = eeprom_address_size(adapter->eeprom_size);
-
-	/* select EEPROM, mask off ASIC and reset bits, set EECS */
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	x &= ~(EEDI | EEDO | EESK);
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-	readw(&(adapter->scb->scb_status)); /* flush command to card */
-	udelay(EEPROM_STALL_TIME);
-	x |= EECS;
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-
-	shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5);
-	shift_out_bits(adapter, reg, (u16) (bits - 2));
-	if (!eeprom_wait_cmd_done(adapter))
-		return;
-
-	/* write the new word to the EEPROM & send the write opcode the EEPORM */
-	shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3);
-
-	/* select which word in the EEPROM that we are writing to */
-	shift_out_bits(adapter, reg, bits);
-
-	/* write the data to the selected EEPROM word */
-	shift_out_bits(adapter, data, 16);
-	if (!eeprom_wait_cmd_done(adapter))
-		return;
-
-	shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5);
-	shift_out_bits(adapter, reg, (u16) (bits - 2));
-	if (!eeprom_wait_cmd_done(adapter))
-		return;
-
-	e100_eeprom_cleanup(adapter);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   e100_eeprom_write_block
-//
-// Description: This routine writes a block of words starting from specified EEPROM 
-//              location and updates checksum
-// Arguments: reg - The EEPROM word that we are going to write to.
-//            data - The data (word) that we are going to write to the EEPROM.
-//----------------------------------------------------------------------------------------
-void
-e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
-			u16 size)
-{
-	u16 checksum;
-	u16 i;
-
-	if (!adapter->eeprom_size)
-		adapter->eeprom_size = e100_eeprom_size(adapter);
-
-	// Set EEPROM semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		if (!eeprom_set_semaphore(adapter))
-			return;
-	}
-
-	for (i = 0; i < size; i++) {
-		e100_eeprom_write_word(adapter, start + i, data[i]);
-	}
-	//Update checksum
-	checksum = e100_eeprom_calculate_chksum(adapter);
-	e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum);
-
-	// Clear EEPROM Semaphore.
-	if (adapter->rev_id >= D102_REV_ID) {
-		eeprom_reset_semaphore(adapter);
-	}
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   eeprom_wait_cmd_done
-//
-// Description: This routine waits for the the EEPROM to finish its command.  
-//                              Specifically, it waits for EEDO (data out) to go high.
-// Returns:     true - If the command finished
-//              false - If the command never finished (EEDO stayed low)
-//----------------------------------------------------------------------------------------
-static u16
-eeprom_wait_cmd_done(struct e100_private *adapter)
-{
-	u16 x;
-	unsigned long expiration_time = jiffies + HZ / 100 + 1;
-
-	eeprom_stand_by(adapter);
-
-	do {
-		rmb();
-		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-		if (x & EEDO)
-			return true;
-		if (time_before(jiffies, expiration_time))
-			yield();
-		else
-			return false;
-	} while (true);
-}
-
-//----------------------------------------------------------------------------------------
-// Procedure:   eeprom_stand_by
-//
-// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds.
-//----------------------------------------------------------------------------------------
-static void
-eeprom_stand_by(struct e100_private *adapter)
-{
-	u16 x;
-
-	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
-	x &= ~(EECS | EESK);
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-	readw(&(adapter->scb->scb_status)); /* flush command to card */
-	udelay(EEPROM_STALL_TIME);
-	x |= EECS;
-	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
-	readw(&(adapter->scb->scb_status)); /* flush command to card */
-	udelay(EEPROM_STALL_TIME);
-}
--- diff/drivers/net/e100/e100_main.c	2004-02-18 08:54:10.000000000 +0000
+++ source/drivers/net/e100/e100_main.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,4341 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-/**********************************************************************
-*                                                                     *
-* INTEL CORPORATION                                                   *
-*                                                                     *
-* This software is supplied under the terms of the license included   *
-* above.  All use of this driver must be in accordance with the terms *
-* of that license.                                                    *
-*                                                                     *
-* Module Name:  e100_main.c                                           *
-*                                                                     *
-* Abstract:     Functions for the driver entry points like load,      *
-*               unload, open and close. All board specific calls made *
-*               by the network interface section of the driver.       *
-*                                                                     *
-* Environment:  This file is intended to be specific to the Linux     *
-*               operating system.                                     *
-*                                                                     *
-**********************************************************************/
-
-/* Change Log
- * 
- * 2.3.36       11/13/03
- * o Moved to 2.6 APIs: pci_name() and free_netdev().
- * o Removed some __devinit from some functions that shouldn't be marked
- *   as such (Anton Blanchard [anton@samba.org]).
- * 
- * 2.3.33       10/21/03
- * o Bug fix (Bugzilla 97908): Loading e100 was causing crash on Itanium2
- *   with HP chipset
- * o Bug fix (Bugzilla 101583): e100 can't pass traffic with ipv6
- * o Bug fix (Bugzilla 101360): PRO/10+ can't pass traffic
- * 
- * 2.3.27       08/08/03
- */
- 
-#include <linux/config.h>
-#include <net/checksum.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#include "e100.h"
-#include "e100_ucode.h"
-#include "e100_config.h"
-#include "e100_phy.h"
-
-extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp);
-
-static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
-	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
-	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
-	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
-	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
-	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
-	"tx_heartbeat_errors", "tx_window_errors",
-};
-#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
-
-static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
-static void e100_get_speed_duplex_caps(struct e100_private *);
-static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);
-static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);
-
-static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);
-static int e100_ethtool_eeprom(struct net_device *, struct ifreq *);
-
-#define E100_EEPROM_MAGIC 0x1234
-static int e100_ethtool_glink(struct net_device *, struct ifreq *);
-static int e100_ethtool_gregs(struct net_device *, struct ifreq *);
-static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
-static int e100_ethtool_wol(struct net_device *, struct ifreq *);
-#ifdef CONFIG_PM
-static unsigned char e100_setup_filter(struct e100_private *bdp);
-static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
-#endif
-static u16 e100_get_ip_lbytes(struct net_device *dev);
-extern void e100_config_wol(struct e100_private *bdp);
-extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
-static int e100_ethtool_test(struct net_device *, struct ifreq *);
-static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
-static char test_strings[][ETH_GSTRING_LEN] = {
-	"Link test     (on/offline)",
-	"Eeprom test   (on/offline)",
-	"Self test        (offline)",
-	"Mac loopback     (offline)",
-	"Phy loopback     (offline)",
-	"Cable diagnostic (offline)"
-};
-
-static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
-
-static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
-
-static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
-						  nxmit_cb_entry_t *);
-static void e100_free_nontx_list(struct e100_private *);
-static void e100_non_tx_background(unsigned long);
-static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb);
-/* Global Data structures and variables */
-char e100_copyright[] = "Copyright (c) 2003 Intel Corporation";
-char e100_driver_version[]="2.3.36-k1";
-const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
-char e100_short_driver_name[] = "e100";
-static int e100nics = 0;
-static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
-		*grp);
-static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
-static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
-
-#ifdef CONFIG_PM
-static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
-static int e100_suspend(struct pci_dev *pcid, u32 state);
-static int e100_resume(struct pci_dev *pcid);
-static unsigned char e100_asf_enabled(struct e100_private *bdp);
-struct notifier_block e100_notifier_reboot = {
-        .notifier_call  = e100_notify_reboot,
-        .next           = NULL,
-        .priority       = 0
-};
-#endif
-
-/*********************************************************************/
-/*! This is a GCC extension to ANSI C.
- *  See the item "Labeled Elements in Initializers" in the section
- *  "Extensions to the C Language Family" of the GCC documentation.
- *********************************************************************/
-#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 }
-
-/* All parameters are treated the same, as an integer array of values.
- * This macro just reduces the need to repeat the same declaration code
- * over and over (plus this helps to avoid typo bugs).
- */
-#define E100_PARAM(X, S)                                        \
-        static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \
-        MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \
-        MODULE_PARM_DESC(X, S);
-
-/* ====================================================================== */
-static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
-static u8 e100_D102_check_checksum(rfd_t *);
-static int e100_ioctl(struct net_device *, struct ifreq *, int);
-static int e100_change_mtu(struct net_device *, int);
-static int e100_xmit_frame(struct sk_buff *, struct net_device *);
-static unsigned char e100_init(struct e100_private *);
-static int e100_set_mac(struct net_device *, void *);
-struct net_device_stats *e100_get_stats(struct net_device *);
-
-static irqreturn_t e100intr(int, void *, struct pt_regs *);
-static void e100_print_brd_conf(struct e100_private *);
-static void e100_set_multi(struct net_device *);
-
-static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
-static u8 e100_sw_init(struct e100_private *);
-static void e100_tco_workaround(struct e100_private *);
-static unsigned char e100_alloc_space(struct e100_private *);
-static void e100_dealloc_space(struct e100_private *);
-static int e100_alloc_tcb_pool(struct e100_private *);
-static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *);
-static void e100_free_tcb_pool(struct e100_private *);
-static int e100_alloc_rfd_pool(struct e100_private *);
-static void e100_free_rfd_pool(struct e100_private *);
-
-static void e100_rd_eaddr(struct e100_private *);
-static void e100_rd_pwa_no(struct e100_private *);
-extern u16 e100_eeprom_read(struct e100_private *, u16);
-extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);
-extern u16 e100_eeprom_size(struct e100_private *);
-u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
-
-static unsigned char e100_clr_cntrs(struct e100_private *);
-static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
-static unsigned char e100_update_stats(struct e100_private *bdp);
-
-static void e100_start_ru(struct e100_private *);
-static void e100_dump_stats_cntrs(struct e100_private *);
-
-static void e100_check_options(int board, struct e100_private *bdp);
-static void e100_set_int_option(int *, int, int, int, int, char *);
-static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
-				 char *);
-unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
-void e100_exec_cmplx(struct e100_private *, u32, u8);
-
-/**
- * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
- * @bdp: atapter's private data struct
- *
- * Returns the new cell to hold sk_buff or %NULL.
- */
-static inline struct rx_list_elem *
-e100_get_rx_struct(struct e100_private *bdp)
-{
-	struct rx_list_elem *rx_struct = NULL;
-
-	if (!list_empty(&(bdp->rx_struct_pool))) {
-		rx_struct = list_entry(bdp->rx_struct_pool.next,
-				       struct rx_list_elem, list_elem);
-		list_del(&(rx_struct->list_elem));
-	}
-
-	return rx_struct;
-}
-
-/**
- * e100_alloc_skb - allocate an skb for the adapter
- * @bdp: atapter's private data struct
- *
- * Allocates skb with enough room for rfd, and data, and reserve non-data space.
- * Returns the new cell with sk_buff or %NULL.
- */
-static inline struct rx_list_elem *
-e100_alloc_skb(struct e100_private *bdp)
-{
-	struct sk_buff *new_skb;
-	u32 skb_size = sizeof (rfd_t);
-	struct rx_list_elem *rx_struct;
-
-	new_skb = (struct sk_buff *) dev_alloc_skb(skb_size);
-	if (new_skb) {
-		/* The IP data should be 
-		   DWORD aligned. since the ethernet header is 14 bytes long, 
-		   we need to reserve 2 extra bytes so that the TCP/IP headers
-		   will be DWORD aligned. */
-		skb_reserve(new_skb, 2);
-		if ((rx_struct = e100_get_rx_struct(bdp)) == NULL)
-			goto err;
-		rx_struct->skb = new_skb;
-		rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data,
-						     sizeof (rfd_t),
-						     PCI_DMA_FROMDEVICE);
-		if (!rx_struct->dma_addr)
-			goto err;
-		skb_reserve(new_skb, bdp->rfd_size);
-		return rx_struct;
-	} else {
-		return NULL;
-	}
-
-err:
-	dev_kfree_skb_irq(new_skb);
-	return NULL;
-}
-
-/**
- * e100_add_skb_to_end - add an skb to the end of our rfd list
- * @bdp: atapter's private data struct
- * @rx_struct: rx_list_elem with the new skb
- *
- * Adds a newly allocated skb to the end of our rfd list.
- */
-inline void
-e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct)
-{
-	rfd_t *rfdn;		/* The new rfd */
-	rfd_t *rfd;		/* The old rfd */
-	struct rx_list_elem *rx_struct_last;
-
-	(rx_struct->skb)->dev = bdp->device;
-	rfdn = RFD_POINTER(rx_struct->skb, bdp);
-	rfdn->rfd_header.cb_status = 0;
-	rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT);
-	rfdn->rfd_act_cnt = 0;
-	rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE);
-
-	pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size,
-			    PCI_DMA_TODEVICE);
-
-	if (!list_empty(&(bdp->active_rx_list))) {
-		rx_struct_last = list_entry(bdp->active_rx_list.prev,
-					    struct rx_list_elem, list_elem);
-		rfd = RFD_POINTER(rx_struct_last->skb, bdp);
-		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
-				    4, PCI_DMA_FROMDEVICE);
-		put_unaligned(cpu_to_le32(rx_struct->dma_addr),
-			      ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr))));
-
-		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
-				    8, PCI_DMA_TODEVICE);
-		rfd->rfd_header.cb_cmd &=
-			__constant_cpu_to_le16((u16) ~RFD_EL_BIT);
-
-		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
-				    4, PCI_DMA_TODEVICE);
-	}
-
-	list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list));
-}
-
-static inline void
-e100_alloc_skbs(struct e100_private *bdp)
-{
-	for (; bdp->skb_req > 0; bdp->skb_req--) {
-		struct rx_list_elem *rx_struct;
-
-		if ((rx_struct = e100_alloc_skb(bdp)) == NULL)
-			return;
-
-		e100_add_skb_to_end(bdp, rx_struct);
-	}
-}
-
-void e100_tx_srv(struct e100_private *);
-u32 e100_rx_srv(struct e100_private *);
-
-void e100_watchdog(struct net_device *);
-void e100_refresh_txthld(struct e100_private *);
-void e100_manage_adaptive_ifs(struct e100_private *);
-void e100_clear_pools(struct e100_private *);
-static void e100_clear_structs(struct net_device *);
-static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,
-					    struct sk_buff *);
-static void e100_set_multi_exec(struct net_device *dev);
-
-MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
-MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver");
-MODULE_LICENSE("GPL");
-
-E100_PARAM(TxDescriptors, "Number of transmit descriptors");
-E100_PARAM(RxDescriptors, "Number of receive descriptors");
-E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
-E100_PARAM(e100_speed_duplex, "Speed and Duplex settings");
-E100_PARAM(ucode, "Disable or enable microcode loading");
-E100_PARAM(ber, "Value for the BER correction algorithm");
-E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing");
-E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay");
-E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");
-E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");
-E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");
-
-/**
- * e100_exec_cmd - issue a comand
- * @bdp: atapter's private data struct
- * @scb_cmd_low: the command that is to be issued
- *
- * This general routine will issue a command to the e100.
- */
-static inline void
-e100_exec_cmd(struct e100_private *bdp, u8 cmd_low)
-{
-	writeb(cmd_low, &(bdp->scb->scb_cmd_low));
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
-}
-
-/**
- * e100_wait_scb - wait for SCB to clear
- * @bdp: atapter's private data struct
- *
- * This routine checks to see if the e100 has accepted a command.
- * It does so by checking the command field in the SCB, which will
- * be zeroed by the e100 upon accepting a command.  The loop waits
- * for up to 1 millisecond for command acceptance.
- *
- * Returns:
- *      true if the SCB cleared within 1 millisecond.
- *      false if it didn't clear within 1 millisecond
- */
-unsigned char
-e100_wait_scb(struct e100_private *bdp)
-{
-	int i;
-
-	/* loop on the scb for a few times */
-	for (i = 0; i < 100; i++) {
-		if (!readb(&bdp->scb->scb_cmd_low))
-			return true;
-		cpu_relax();
-	}
-
-	/* it didn't work. do it the slow way using udelay()s */
-	for (i = 0; i < E100_MAX_SCB_WAIT; i++) {
-		if (!readb(&bdp->scb->scb_cmd_low))
-			return true;
-		cpu_relax();
-		udelay(1);
-	}
-
-	return false;
-}
-
-/**
- * e100_wait_exec_simple - issue a command
- * @bdp: atapter's private data struct
- * @scb_cmd_low: the command that is to be issued
- *
- * This general routine will issue a command to the e100 after waiting for
- * the previous command to finish.
- *
- * Returns:
- *      true if the command was issued to the chip successfully
- *      false if the command was not issued to the chip
- */
-inline unsigned char
-e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low)
-{
-	if (!e100_wait_scb(bdp)) {
-		printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
-		       bdp->device->name);
-#ifdef E100_CU_DEBUG		
-		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
-			"timeout\n", bdp->device->name, 
-			bdp->last_cmd, bdp->last_sub_cmd);
-		printk(KERN_ERR "e100: %s: Current simple command (%x) "
-			"can't be executed\n", 
-			bdp->device->name, scb_cmd_low);
-#endif		
-		return false;
-	}
-	e100_exec_cmd(bdp, scb_cmd_low);
-#ifdef E100_CU_DEBUG	
-	bdp->last_cmd = scb_cmd_low;
-	bdp->last_sub_cmd = 0;
-#endif	
-	return true;
-}
-
-void
-e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
-{
-	writel(phys_addr, &(bdp->scb->scb_gen_ptr));
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
-	e100_exec_cmd(bdp, cmd);
-}
-
-unsigned char
-e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd)
-{
-	if (!e100_wait_scb(bdp)) {
-#ifdef E100_CU_DEBUG		
-		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
-			"timeout\n", bdp->device->name, 
-			bdp->last_cmd, bdp->last_sub_cmd);
-		printk(KERN_ERR "e100: %s: Current complex command "
-			"(%x/%x) can't be executed\n", 
-			bdp->device->name, cmd, sub_cmd);
-#endif		
-		return false;
-	}
-	e100_exec_cmplx(bdp, phys_addr, cmd);
-#ifdef E100_CU_DEBUG	
-	bdp->last_cmd = cmd;
-	bdp->last_sub_cmd = sub_cmd;
-#endif	
-	return true;
-}
-
-inline u8
-e100_wait_cus_idle(struct e100_private *bdp)
-{
-	int i;
-
-	/* loop on the scb for a few times */
-	for (i = 0; i < 100; i++) {
-		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
-		     SCB_CUS_ACTIVE)) {
-			return true;
-		}
-		cpu_relax();
-	}
-
-	for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) {
-		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
-		     SCB_CUS_ACTIVE)) {
-			return true;
-		}
-		cpu_relax();
-		udelay(1);
-	}
-
-	return false;
-}
-
-/**
- * e100_disable_clear_intr - disable and clear/ack interrupts
- * @bdp: atapter's private data struct
- *
- * This routine disables interrupts at the hardware, by setting
- * the M (mask) bit in the adapter's CSR SCB command word.
- * It also clear/ack interrupts.
- */
-static inline void
-e100_disable_clear_intr(struct e100_private *bdp)
-{
-	u16 intr_status;
-	/* Disable interrupts on our PCI board by setting the mask bit */
-	writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
-	intr_status = readw(&bdp->scb->scb_status);
-	/* ack and clear intrs */
-	writew(intr_status, &bdp->scb->scb_status);
-	readw(&bdp->scb->scb_status);
-}
-
-/**
- * e100_set_intr_mask - set interrupts
- * @bdp: atapter's private data struct
- *
- * This routine sets interrupts at the hardware, by resetting
- * the M (mask) bit in the adapter's CSR SCB command word
- */
-static inline void
-e100_set_intr_mask(struct e100_private *bdp)
-{
-	writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi);
-	readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */
-}
-
-static inline void
-e100_trigger_SWI(struct e100_private *bdp)
-{
-	/* Trigger interrupt on our PCI board by asserting SWI bit */
-	writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi);
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
-}
-
-static int
-e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
-{
-	static int first_time = true;
-	struct net_device *dev = NULL;
-	struct e100_private *bdp = NULL;
-	int rc = 0;
-	u16 cal_checksum, read_checksum;
-
-	dev = alloc_etherdev(sizeof (struct e100_private));
-	if (dev == NULL) {
-		printk(KERN_ERR "e100: Not able to alloc etherdev struct\n");
-		rc = -ENODEV;
-		goto out;
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	if (first_time) {
-		first_time = false;
-        	printk(KERN_NOTICE "%s - version %s\n",
-	               e100_full_driver_name, e100_driver_version);
-		printk(KERN_NOTICE "%s\n", e100_copyright);
-		printk(KERN_NOTICE "\n");
-	}
-
-	bdp = dev->priv;
-	bdp->pdev = pcid;
-	bdp->device = dev;
-
-	pci_set_drvdata(pcid, dev);
-	SET_NETDEV_DEV(dev, &pcid->dev);
-
-	bdp->flags = 0;
-	bdp->ifs_state = 0;
-	bdp->ifs_value = 0;
-	bdp->scb = 0;
-
-	init_timer(&bdp->nontx_timer_id);
-	bdp->nontx_timer_id.data = (unsigned long) bdp;
-	bdp->nontx_timer_id.function = (void *) &e100_non_tx_background;
-	INIT_LIST_HEAD(&(bdp->non_tx_cmd_list));
-	bdp->non_tx_command_state = E100_NON_TX_IDLE;
-
-	init_timer(&bdp->watchdog_timer);
-	bdp->watchdog_timer.data = (unsigned long) dev;
-	bdp->watchdog_timer.function = (void *) &e100_watchdog;
-
-	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
-		goto err_dev;
-	}
-
-	if ((rc = e100_alloc_space(bdp)) != 0) {
-		goto err_pci;
-	}
-
-	if (((bdp->pdev->device > 0x1030)
-	       && (bdp->pdev->device < 0x103F))
-	    || ((bdp->pdev->device >= 0x1050)
-	       && (bdp->pdev->device <= 0x1057))
-	    || (bdp->pdev->device == 0x2449)
-	    || (bdp->pdev->device == 0x2459)
-	    || (bdp->pdev->device == 0x245D)) {
-		bdp->rev_id = D101MA_REV_ID;	/* workaround for ICH3 */
-		bdp->flags |= IS_ICH;
-	}
-
-	if (bdp->rev_id == 0xff)
-		bdp->rev_id = 1;
-
-	if ((u8) bdp->rev_id >= D101A4_REV_ID)
-		bdp->flags |= IS_BACHELOR;
-
-	if ((u8) bdp->rev_id >= D102_REV_ID) {
-		bdp->flags |= USE_IPCB;
-		bdp->rfd_size = 32;
-	} else {
-		bdp->rfd_size = 16;
-	}
-
-	dev->vlan_rx_register = e100_vlan_rx_register;
-	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
-	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
-	dev->irq = pcid->irq;
-	dev->open = &e100_open;
-	dev->hard_start_xmit = &e100_xmit_frame;
-	dev->stop = &e100_close;
-	dev->change_mtu = &e100_change_mtu;
-	dev->get_stats = &e100_get_stats;
-	dev->set_multicast_list = &e100_set_multi;
-	dev->set_mac_address = &e100_set_mac;
-	dev->do_ioctl = &e100_ioctl;
-
-	if (bdp->flags & USE_IPCB)
-	dev->features = NETIF_F_SG | NETIF_F_IP_CSUM |
-			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		
-	if ((rc = register_netdev(dev)) != 0) {
-		goto err_dealloc;
-	}
-
-	e100_check_options(e100nics, bdp);
-
-	if (!e100_init(bdp)) {
-		printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
-		       e100nics);
-		rc = -ENODEV;
-		goto err_unregister_netdev;
-	}
-
-	/* Check if checksum is valid */
-	cal_checksum = e100_eeprom_calculate_chksum(bdp);
-	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
-	if (cal_checksum != read_checksum) {
-                printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
-		       e100nics);
-                rc = -ENODEV;
-                goto err_unregister_netdev;
-	}
-	
-	e100nics++;
-
-	e100_get_speed_duplex_caps(bdp);
-
-	printk(KERN_NOTICE
-	       "e100: %s: %s\n", 
-	       bdp->device->name, "Intel(R) PRO/100 Network Connection");
-	e100_print_brd_conf(bdp);
-
-	bdp->wolsupported = 0;
-	bdp->wolopts = 0;
-	if (bdp->rev_id >= D101A4_REV_ID)
-		bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
-	if (bdp->rev_id >= D101MA_REV_ID)
-		bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
-	
-	/* Check if WoL is enabled on EEPROM */
-	if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
-		/* Magic Packet WoL is enabled on device by default */
-		/* if EEPROM WoL bit is TRUE                        */
-		bdp->wolopts = WAKE_MAGIC;
-	}
-
-	printk(KERN_NOTICE "\n");
-
-	goto out;
-
-err_unregister_netdev:
-	unregister_netdev(dev);
-err_dealloc:
-	e100_dealloc_space(bdp);
-err_pci:
-	iounmap(bdp->scb);
-	pci_release_regions(pcid);
-	pci_disable_device(pcid);
-err_dev:
-	pci_set_drvdata(pcid, NULL);
-	free_netdev(dev);
-out:
-	return rc;
-}
-
-/**
- * e100_clear_structs - free resources
- * @dev: adapter's net_device struct
- *
- * Free all device specific structs, unmap i/o address, etc.
- */
-static void __devexit
-e100_clear_structs(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-
-	iounmap(bdp->scb);
-	pci_release_regions(bdp->pdev);
-	pci_disable_device(bdp->pdev);
-
-	e100_dealloc_space(bdp);
-	pci_set_drvdata(bdp->pdev, NULL);
-	free_netdev(dev);
-}
-
-static void __devexit
-e100_remove1(struct pci_dev *pcid)
-{
-	struct net_device *dev;
-	struct e100_private *bdp;
-
-	if (!(dev = (struct net_device *) pci_get_drvdata(pcid)))
-		return;
-
-	bdp = dev->priv;
-
-	unregister_netdev(dev);
-
-	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
-		del_timer_sync(&bdp->nontx_timer_id);
-		e100_free_nontx_list(bdp);
-		bdp->non_tx_command_state = E100_NON_TX_IDLE;
-	}
-
-	e100_clear_structs(dev);
-
-	--e100nics;
-}
-
-static struct pci_device_id e100_id_table[] = {
-	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },	
-	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
-	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
-	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
-	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
-	{0,} /* This has to be the last entry*/
-};
-MODULE_DEVICE_TABLE(pci, e100_id_table);
-
-static struct pci_driver e100_driver = {
-	.name         = "e100",
-	.id_table     = e100_id_table,
-	.probe        = e100_found1,
-	.remove       = __devexit_p(e100_remove1),
-#ifdef CONFIG_PM
-	.suspend      = e100_suspend,
-	.resume       = e100_resume,
-#endif
-};
-
-static int __init
-e100_init_module(void)
-{
-	int ret;
-        ret = pci_module_init(&e100_driver);
-
-	if(ret >= 0) {
-#ifdef CONFIG_PM
-		register_reboot_notifier(&e100_notifier_reboot);
-#endif 
-	}
-
-	return ret;
-}
-
-static void __exit
-e100_cleanup_module(void)
-{
-#ifdef CONFIG_PM	
-	unregister_reboot_notifier(&e100_notifier_reboot);
-#endif 
-
-	pci_unregister_driver(&e100_driver);
-}
-
-module_init(e100_init_module);
-module_exit(e100_cleanup_module);
-
-/**
- * e100_check_options - check command line options
- * @board: board number
- * @bdp: atapter's private data struct
- *
- * This routine does range checking on command-line options
- */
-void
-e100_check_options(int board, struct e100_private *bdp)
-{
-	if (board >= E100_MAX_NIC) {
-		printk(KERN_NOTICE 
-		       "e100: No configuration available for board #%d\n",
-		       board);
-		printk(KERN_NOTICE "e100: Using defaults for all values\n");
-		board = E100_MAX_NIC;
-	}
-
-	e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board],
-			    E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB,
-			    "TxDescriptor count");
-
-	e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board],
-			    E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD,
-			    "RxDescriptor count");
-
-	e100_set_int_option(&(bdp->params.e100_speed_duplex),
-			    e100_speed_duplex[board], 0, 4,
-			    E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode");
-
-	e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS,
-			    E100_DEFAULT_BER, "Bit Error Rate count");
-
-	e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM,
-			     "XsumRX value");
-
-	/* Default ucode value depended on controller revision */
-	if (bdp->rev_id >= D101MA_REV_ID) {
-		e100_set_bool_option(bdp, ucode[board], PRM_UCODE,
-				     E100_DEFAULT_UCODE, "ucode value");
-	} else {
-		e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false,
-				     "ucode value");
-	}
-
-	e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC,
-			     "flow control value");
-
-	e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS,
-			     "IFS value");
-
-	e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL,
-			     E100_DEFAULT_BUNDLE_SMALL_FR,
-			     "CPU saver bundle small frames value");
-
-	e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0,
-			    0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY,
-			    "CPU saver interrupt delay value");
-
-	e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1,
-			    0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX,
-			    "CPU saver bundle max value");
-
-}
-
-/**
- * e100_set_int_option - check and set an integer option
- * @option: a pointer to the relevant option field
- * @val: the value specified
- * @min: the minimum valid value
- * @max: the maximum valid value
- * @default_val: the default value
- * @name: the name of the option
- *
- * This routine does range checking on a command-line option.
- * If the option's value is '-1' use the specified default.
- * Otherwise, if the value is invalid, change it to the default.
- */
-void
-e100_set_int_option(int *option, int val, int min, int max, int default_val,
-		    char *name)
-{
-	if (val == -1) {	/* no value specified. use default */
-		*option = default_val;
-
-	} else if ((val < min) || (val > max)) {
-		printk(KERN_NOTICE
-		       "e100: Invalid %s specified (%i). "
-		       "Valid range is %i-%i\n",
-		       name, val, min, max);
-		printk(KERN_NOTICE "e100: Using default %s of %i\n", name,
-		       default_val);
-		*option = default_val;
-	} else {
-		printk(KERN_INFO "e100: Using specified %s of %i\n", name, val);
-		*option = val;
-	}
-}
-
-/**
- * e100_set_bool_option - check and set a boolean option
- * @bdp: atapter's private data struct
- * @val: the value specified
- * @mask: the mask for the relevant option
- * @default_val: the default value
- * @name: the name of the option
- *
- * This routine checks a boolean command-line option.
- * If the option's value is '-1' use the specified default.
- * Otherwise, if the value is invalid (not 0 or 1), 
- * change it to the default.
- */
-void
-e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
-		     int default_val, char *name)
-{
-	if (val == -1) {
-		if (default_val)
-			bdp->params.b_params |= mask;
-
-	} else if ((val != true) && (val != false)) {
-		printk(KERN_NOTICE
-		       "e100: Invalid %s specified (%i). "
-		       "Valid values are %i/%i\n",
-		       name, val, false, true);
-		printk(KERN_NOTICE "e100: Using default %s of %i\n", name,
-		       default_val);
-
-		if (default_val)
-			bdp->params.b_params |= mask;
-	} else {
-		printk(KERN_INFO "e100: Using specified %s of %i\n", name, val);
-		if (val)
-			bdp->params.b_params |= mask;
-	}
-}
-
-int
-e100_open(struct net_device *dev)
-{
-	struct e100_private *bdp;
-	int rc = 0;
-
-	bdp = dev->priv;
-
-	/* setup the tcb pool */
-	if (!e100_alloc_tcb_pool(bdp)) {
-		rc = -ENOMEM;
-		goto err_exit;
-	}
-	bdp->last_tcb = NULL;
-
-	bdp->tcb_pool.head = 0;
-	bdp->tcb_pool.tail = 1;	
-
-	e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data,
-			    bdp->params.TxDescriptors, bdp);
-
-	if (!e100_alloc_rfd_pool(bdp)) {
-		rc = -ENOMEM;
-		goto err_exit;
-	}
-
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) {
-		rc = -EAGAIN;
-		goto err_exit;
-	}
-
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) {
-		rc = -EAGAIN;
-		goto err_exit;
-	}
-
-	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
-
-	if (dev->flags & IFF_UP)
-		/* Otherwise process may sleep forever */
-		netif_wake_queue(dev);
-	else
-		netif_start_queue(dev);
-
-	e100_start_ru(bdp);
-	if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
-			      dev->name, dev)) != 0) {
-		del_timer_sync(&bdp->watchdog_timer);
-		goto err_exit;
-	}
-	bdp->intr_mask = 0;
-	e100_set_intr_mask(bdp);
-
-	e100_force_config(bdp);
-
-	goto exit;
-
-err_exit:
-	e100_clear_pools(bdp);
-exit:
-	return rc;
-}
-
-int
-e100_close(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-
-	e100_disable_clear_intr(bdp);
-	free_irq(dev->irq, dev);
-	bdp->intr_mask = SCB_INT_MASK;
-	e100_isolate_driver(bdp);
-
-	netif_carrier_off(bdp->device);
-	bdp->cur_line_speed = 0;
-	bdp->cur_dplx_mode = 0;
-	e100_clear_pools(bdp);
-
-	return 0;
-}
-
-static int
-e100_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-static int
-e100_xmit_frame(struct sk_buff *skb, struct net_device *dev)
-{
-	int rc = 0;
-	int notify_stop = false;
-	struct e100_private *bdp = dev->priv;
-
-	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
-		notify_stop = true;
-		rc = 1;
-		goto exit2;
-	}
-
-	/* tcb list may be empty temporarily during releasing resources */
-	if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) ||
-	    (bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
-		notify_stop = true;
-		rc = 1;
-		goto exit1;
-	}
-
-	bdp->drv_stats.net_stats.tx_bytes += skb->len;
-
-	e100_prepare_xmit_buff(bdp, skb);
-
-	dev->trans_start = jiffies;
-
-exit1:
-	spin_unlock(&bdp->bd_non_tx_lock);
-exit2:
-	if (notify_stop) {
-		netif_stop_queue(dev);
-	}
-
-	return rc;
-}
-
-/**
- * e100_get_stats - get driver statistics
- * @dev: adapter's net_device struct
- *
- * This routine is called when the OS wants the adapter's stats returned.
- * It returns the address of the net_device_stats stucture for the device.
- * If the statistics are currently being updated, then they might be incorrect
- * for a short while. However, since this cannot actually cause damage, no
- * locking is used.
- */
-struct net_device_stats *
-e100_get_stats(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-
-	bdp->drv_stats.net_stats.tx_errors =
-		bdp->drv_stats.net_stats.tx_carrier_errors +
-		bdp->drv_stats.net_stats.tx_aborted_errors;
-
-	bdp->drv_stats.net_stats.rx_errors =
-		bdp->drv_stats.net_stats.rx_crc_errors +
-		bdp->drv_stats.net_stats.rx_frame_errors +
-		bdp->drv_stats.net_stats.rx_length_errors +
-		bdp->drv_stats.rcv_cdt_frames;
-
-	return &(bdp->drv_stats.net_stats);
-}
-
-/**
- * e100_set_mac - set the MAC address
- * @dev: adapter's net_device struct
- * @addr: the new address
- *
- * This routine sets the ethernet address of the board
- * Returns:
- * 0  - if successful
- * -1 - otherwise
- */
-static int
-e100_set_mac(struct net_device *dev, void *addr)
-{
-	struct e100_private *bdp;
-	int rc = -1;
-	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
-
-	if (!is_valid_ether_addr(p_sockaddr->sa_data))
-		return -EADDRNOTAVAIL;
-	bdp = dev->priv;
-
-	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
-		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
-		rc = 0;
-	}
-
-	return rc;
-}
-
-static void
-e100_set_multi_exec(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-	mltcst_cb_t *mcast_buff;
-	cb_header_t *cb_hdr;
-	struct dev_mc_list *mc_list;
-	unsigned int i;
-	nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
-
-	if (cmd != NULL) {
-		mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast);
-		cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr);
-	} else {
-		return;
-	}
-
-	/* initialize the multi cast command */
-	cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST);
-
-	/* now fill in the rest of the multicast command */
-	*(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6);
-	for (i = 0, mc_list = dev->mc_list;
-	     (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS);
-	     i++, mc_list = mc_list->next) {
-		/* copy into the command */
-		memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]),
-		       (u8 *) &(mc_list->dmi_addr), ETH_ALEN);
-	}
-
-	if (!e100_exec_non_cu_cmd(bdp, cmd)) {
-		printk(KERN_WARNING "e100: %s: Multicast setup failed\n", 
-		       dev->name);
-	}
-}
-
-/**
- * e100_set_multi - set multicast status
- * @dev: adapter's net_device struct
- *
- * This routine is called to add or remove multicast addresses, and/or to
- * change the adapter's promiscuous state.
- */
-static void
-e100_set_multi(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-	unsigned char promisc_enbl;
-	unsigned char mulcast_enbl;
-
-	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
-	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
-			(dev->mc_count > MAX_MULTICAST_ADDRS));
-
-	e100_config_promisc(bdp, promisc_enbl);
-	e100_config_mulcast_enbl(bdp, mulcast_enbl);
-
-	/* reconfigure the chip if something has changed in its config space */
-	e100_config(bdp);
-
-	if (promisc_enbl || mulcast_enbl) {
-		return;	/* no need for Multicast Cmd */
-	}
-
-	/* get the multicast CB */
-	e100_set_multi_exec(dev);
-}
-
-static int
-e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-
-	switch (cmd) {
-
-	case SIOCETHTOOL:
-		return e100_do_ethtool_ioctl(dev, ifr);
-		break;
-
-	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
-	case SIOCGMIIREG:	/* Read MII PHY register. */
-	case SIOCSMIIREG:	/* Write to MII PHY register. */
-		return e100_mii_ioctl(dev, ifr, cmd);
-		break;
-
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
-
-}
-
-/**
- * e100init - initialize the adapter
- * @bdp: atapter's private data struct
- *
- * This routine is called when this driver is loaded. This is the initialization
- * routine which allocates memory, configures the adapter and determines the
- * system resources.
- *
- * Returns:
- *      true: if successful
- *      false: otherwise
- */
-static unsigned char
-e100_init(struct e100_private *bdp)
-{
-	u32 st_timeout = 0;
-	u32 st_result = 0;
-	e100_sw_init(bdp);
-
-	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
-        	if (st_timeout) {
-			printk(KERN_ERR "e100: selftest timeout\n");
-		} else {
-			printk(KERN_ERR "e100: selftest failed. Results: %x\n",
-					st_result);
-		}
-		return false;
-	}
-	else
-		printk(KERN_DEBUG "e100: selftest OK.\n");
-
-	/* read the MAC address from the eprom */
-	e100_rd_eaddr(bdp);
-	if (!is_valid_ether_addr(bdp->device->dev_addr)) {
-		printk(KERN_ERR "e100: Invalid Ethernet address\n");
-		return false;
-	}
-	/* read NIC's part number */
-	e100_rd_pwa_no(bdp);
-
-	if (!e100_hw_init(bdp))
-		return false;
-	/* Interrupts are enabled after device reset */
-	e100_disable_clear_intr(bdp);
-
-	return true;
-}
-
-/**
- * e100_sw_init - initialize software structs
- * @bdp: atapter's private data struct
- * 
- * This routine initializes all software structures. Sets up the
- * circular structures for the RFD's & TCB's. Allocates the per board
- * structure for storing adapter information. The CSR is also memory 
- * mapped in this routine.
- *
- * Returns :
- *      true: if S/W was successfully initialized
- *      false: otherwise
- */
-static unsigned char
-e100_sw_init(struct e100_private *bdp)
-{
-	bdp->next_cu_cmd = START_WAIT;	// init the next cu state
-
-	/* 
-	 * Set the value for # of good xmits per underrun. the value assigned
-	 * here is an intelligent  suggested default. Nothing magical about it.
-	 */
-	bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN;
-
-	/* get the default transmit threshold value */
-	bdp->tx_thld = TX_THRSHLD;
-
-	/* get the EPROM size */
-	bdp->eeprom_size = e100_eeprom_size(bdp);
-
-	/* Initialize our spinlocks */
-	spin_lock_init(&(bdp->bd_lock));
-	spin_lock_init(&(bdp->bd_non_tx_lock));
-	spin_lock_init(&(bdp->config_lock));
-	spin_lock_init(&(bdp->mdi_access_lock));
-	/* Initialize configuration data */
-	e100_config_init(bdp);
-
-	return 1;
-}
-
-static void
-e100_tco_workaround(struct e100_private *bdp)
-{
-	int i;
-
-	/* Do software reset */
-	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-
-	/* Do a dummy LOAD CU BASE command. */
-	/* This gets us out of pre-driver to post-driver. */
-	e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
-
-	/* Wait 20 msec for reset to take effect */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 50 + 1);
-
-	/* disable interrupts since they are enabled */
-	/* after device reset                        */
-	e100_disable_clear_intr(bdp);
-
-	/* Wait for command to be cleared up to 1 sec */
-	for (i=0; i<100; i++) {
-		if (!readb(&bdp->scb->scb_cmd_low))
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 100 + 1);
-	}
-
-	/* Wait for TCO request bit in PMDR register to be clear */
-	for (i=0; i<50; i++) {
-		if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 100 + 1);
-	}
-}
-
-/**
- * e100_hw_init - initialized tthe hardware
- * @bdp: atapter's private data struct
- *
- * This routine performs a reset on the adapter, and configures the adapter.
- * This includes configuring the 82557 LAN controller, validating and setting
- * the node address, detecting and configuring the Phy chip on the adapter,
- * and initializing all of the on chip counters.
- *
- * Returns:
- *      true - If the adapter was initialized
- *      false - If the adapter failed initialization
- */
-unsigned char
-e100_hw_init(struct e100_private *bdp)
-{
-	if (!e100_phy_init(bdp))
-		goto err;
-
-	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-	/* Only 82559 or above needs TCO workaround */
-	if (bdp->rev_id >= D101MA_REV_ID)
-		e100_tco_workaround(bdp);
-
-	/* Load the CU BASE (set to 0, because we use linear mode) */
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
-		goto err;
-
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
-		goto err;
-
-	/* Load interrupt microcode  */
-	if (e100_load_microcode(bdp)) {
-		bdp->flags |= DF_UCODE_LOADED;
-	}
-
-	if ((u8) bdp->rev_id < D101A4_REV_ID)
-		e100_config_init_82557(bdp);
-		
-	if (!e100_config(bdp))
-		goto err;
-
-	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
-		goto err;
-
-	/* Clear the internal counters */
-	if (!e100_clr_cntrs(bdp))
-		goto err;
-
-	/* Change for 82558 enhancement */
-	/* If 82558/9 and if the user has enabled flow control, set up the
-	 * Flow Control Reg. in the CSR */
-	if ((bdp->flags & IS_BACHELOR)
-	    && (bdp->params.b_params & PRM_FC)) {
-		writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
-		writeb(DFLT_FC_CMD,
-		       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
-	}
-
-	return true;
-err:
-	printk(KERN_ERR "e100: hw init failed\n");
-	return false;
-}
-
-/**
- * e100_setup_tcb_pool - setup TCB circular list
- * @head: Pointer to head of the allocated TCBs
- * @qlen: Number of elements in the queue
- * @bdp: atapter's private data struct
- * 
- * This routine arranges the contigiously allocated TCB's in a circular list.
- * Also does the one time initialization of the TCBs.
- */
-static void
-e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp)
-{
-	int ele_no;
-	tcb_t *pcurr_tcb;	/* point to current tcb */
-	u32 next_phys;		/* the next phys addr */
-	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
-
-	bdp->tx_count = 0;
-	if (bdp->flags & USE_IPCB) {
-		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
-	} else if (bdp->flags & IS_BACHELOR) {
-		txcommand |= CB_TRANSMIT | CB_CID_DEFAULT;
-	} else {
-		txcommand |= CB_TRANSMIT;
-	}
-
-	for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head;
-	     ele_no < qlen; ele_no++, pcurr_tcb++) {
-
-		/* set the phys addr for this TCB, next_phys has not incr. yet */
-		pcurr_tcb->tcb_phys = next_phys;
-		next_phys += sizeof (tcb_t);
-
-		/* set the link to next tcb */
-		if (ele_no == (qlen - 1))
-			pcurr_tcb->tcb_hdr.cb_lnk_ptr =
-				cpu_to_le32(bdp->tcb_phys);
-		else
-			pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys);
-
-		pcurr_tcb->tcb_hdr.cb_status = 0;
-		pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand);
-		pcurr_tcb->tcb_cnt = 0;	
-		pcurr_tcb->tcb_thrshld = bdp->tx_thld;	
-		if (ele_no < 2) {
-			pcurr_tcb->tcb_hdr.cb_status =
-				cpu_to_le16(CB_STATUS_COMPLETE);
-		}
-		pcurr_tcb->tcb_tbd_num = 1;
-
-		if (bdp->flags & IS_BACHELOR) {
-			pcurr_tcb->tcb_tbd_ptr =
-				__constant_cpu_to_le32(0xFFFFFFFF);
-		} else {
-			pcurr_tcb->tcb_tbd_ptr =
-				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
-		}
-
-		if (bdp->flags & IS_BACHELOR) {
-			pcurr_tcb->tcb_tbd_expand_ptr =
-				cpu_to_le32(pcurr_tcb->tcb_phys + 0x20);
-		} else {
-			pcurr_tcb->tcb_tbd_expand_ptr =
-				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
-		}
-		pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr;
-
-		if (bdp->flags & USE_IPCB) {
-			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]);
-			pcurr_tcb->tcbu.ipcb.ip_activation_high =
-				IPCB_IP_ACTIVATION_DEFAULT;
-			pcurr_tcb->tcbu.ipcb.vlan = 0;
-		} else {
-			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]);
-		}
-
-		pcurr_tcb->tcb_skb = NULL;
-	}
-
-	wmb();
-}
-
-/***************************************************************************/
-/***************************************************************************/
-/*       Memory Management Routines                                        */
-/***************************************************************************/
-
-/**
- * e100_alloc_space - allocate private driver data
- * @bdp: atapter's private data struct
- *
- * This routine allocates memory for the driver. Memory allocated is for the
- * selftest and statistics structures.
- *
- * Returns:
- *      0: if the operation was successful
- *      %-ENOMEM: if memory allocation failed
- */
-unsigned char
-e100_alloc_space(struct e100_private *bdp)
-{
-	unsigned long off;
-
-	/* allocate all the dma-able structures in one call:
-	 * selftest results, adapter stats, and non-tx cb commands */
-	if (!(bdp->dma_able =
-	      pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t),
-				   &(bdp->dma_able_phys)))) {
-		goto err;
-	}
-
-	/* now assign the various pointers into the struct we've just allocated */
-	off = offsetof(bd_dma_able_t, selftest);
-
-	bdp->selftest = (self_test_t *) (bdp->dma_able + off);
-	bdp->selftest_phys = bdp->dma_able_phys + off;
-
-	off = offsetof(bd_dma_able_t, stats_counters);
-
-	bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off);
-	bdp->stat_cnt_phys = bdp->dma_able_phys + off;
-
-	return 0;
-
-err:
-	printk(KERN_ERR
-	       "e100: Failed to allocate memory\n");
-	return -ENOMEM;
-}
-
-/**
- * e100_alloc_tcb_pool - allocate TCB circular list
- * @bdp: atapter's private data struct
- *
- * This routine allocates memory for the circular list of transmit descriptors.
- *
- * Returns:
- *       0: if allocation has failed.
- *       1: Otherwise. 
- */
-int
-e100_alloc_tcb_pool(struct e100_private *bdp)
-{
-	int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors;
-
-	/* allocate space for the TCBs */
-	if (!(bdp->tcb_pool.data =
-	      pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys)))
-		return 0;
-
-	memset(bdp->tcb_pool.data, 0x00, stcb);
-
-	return 1;
-}
-
-void
-e100_free_tcb_pool(struct e100_private *bdp)
-{
-	tcb_t *tcb;
-	int i;
-	/* Return tx skbs */ 
-	for (i = 0; i < bdp->params.TxDescriptors; i++) {
-	  	tcb = bdp->tcb_pool.data;
-		tcb += bdp->tcb_pool.head;
-  		e100_tx_skb_free(bdp, tcb);
-		if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail)
-		  	break;
-		bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
-	}
-	pci_free_consistent(bdp->pdev,
-			    sizeof (tcb_t) * bdp->params.TxDescriptors,
-			    bdp->tcb_pool.data, bdp->tcb_phys);
-	bdp->tcb_pool.head = 0;
-	bdp->tcb_pool.tail = 1;	
-	bdp->tcb_phys = 0;
-}
-
-static void
-e100_dealloc_space(struct e100_private *bdp)
-{
-	if (bdp->dma_able) {
-		pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t),
-				    bdp->dma_able, bdp->dma_able_phys);
-	}
-
-	bdp->selftest_phys = 0;
-	bdp->stat_cnt_phys = 0;
-	bdp->dma_able_phys = 0;
-	bdp->dma_able = 0;
-}
-
-static void
-e100_free_rfd_pool(struct e100_private *bdp)
-{
-	struct rx_list_elem *rx_struct;
-
-	while (!list_empty(&(bdp->active_rx_list))) {
-
-		rx_struct = list_entry(bdp->active_rx_list.next,
-				       struct rx_list_elem, list_elem);
-		list_del(&(rx_struct->list_elem));
-		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
-				 sizeof (rfd_t), PCI_DMA_TODEVICE);
-		dev_kfree_skb(rx_struct->skb);
-		kfree(rx_struct);
-	}
-
-	while (!list_empty(&(bdp->rx_struct_pool))) {
-		rx_struct = list_entry(bdp->rx_struct_pool.next,
-				       struct rx_list_elem, list_elem);
-		list_del(&(rx_struct->list_elem));
-		kfree(rx_struct);
-	}
-}
-
-/**
- * e100_alloc_rfd_pool - allocate RFDs
- * @bdp: atapter's private data struct
- *
- * Allocates initial pool of skb which holds both rfd and data,
- * and return a pointer to the head of the list
- */
-static int
-e100_alloc_rfd_pool(struct e100_private *bdp)
-{
-	struct rx_list_elem *rx_struct;
-	int i;
-
-	INIT_LIST_HEAD(&(bdp->active_rx_list));
-	INIT_LIST_HEAD(&(bdp->rx_struct_pool));
-	bdp->skb_req = bdp->params.RxDescriptors;
-	for (i = 0; i < bdp->skb_req; i++) {
-		rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC);
-		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
-	}
-	e100_alloc_skbs(bdp);
-	return !list_empty(&(bdp->active_rx_list));
-
-}
-
-void
-e100_clear_pools(struct e100_private *bdp)
-{
-	bdp->last_tcb = NULL;
-	e100_free_rfd_pool(bdp);
-	e100_free_tcb_pool(bdp);
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-/*      Run Time Functions                                                   */
-/*****************************************************************************/
-
-/**
- * e100_watchdog
- * @dev: adapter's net_device struct
- *
- * This routine runs every 2 seconds and updates our statitics and link state,
- * and refreshs txthld value.
- */
-void
-e100_watchdog(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-
-#ifdef E100_CU_DEBUG
-	if (e100_cu_unknown_state(bdp)) {
-		printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n",
-			dev->name);
-	}
-#endif	
-	if (!netif_running(dev)) {
-		return;
-	}
-
-	/* check if link state has changed */
-	if (e100_phy_check(bdp)) {
-		if (netif_carrier_ok(dev)) {
-			printk(KERN_ERR
-			       "e100: %s NIC Link is Up %d Mbps %s duplex\n",
-			       bdp->device->name, bdp->cur_line_speed,
-			       (bdp->cur_dplx_mode == HALF_DUPLEX) ?
-			       "Half" : "Full");
-
-			e100_config_fc(bdp);
-			e100_config(bdp);  
-
-		} else {
-			printk(KERN_ERR "e100: %s NIC Link is Down\n",
-			       bdp->device->name);
-		}
-	}
-
-	// toggle the tx queue according to link status
-	// this also resolves a race condition between tx & non-cu cmd flows
-	if (netif_carrier_ok(dev)) {
-		if (netif_running(dev))
-			netif_wake_queue(dev);
-	} else {
-		if (netif_running(dev))
-			netif_stop_queue(dev);
-		/* When changing to non-autoneg, device may lose  */
-		/* link with some switches. e100 will try to      */
-		/* revover link by sending command to PHY layer   */
-		if (bdp->params.e100_speed_duplex != E100_AUTONEG)
-			e100_force_speed_duplex_to_phy(bdp);
-	}
-
-	rmb();
-
-	if (e100_update_stats(bdp)) {
-
-		/* Check if a change in the IFS parameter is needed,
-		   and configure the device accordingly */
-		if (bdp->params.b_params & PRM_IFS)
-			e100_manage_adaptive_ifs(bdp);
-
-		/* Now adjust our dynamic tx threshold value */
-		e100_refresh_txthld(bdp);
-
-		/* Now if we are on a 557 and we havn't received any frames then we
-		 * should issue a multicast command to reset the RU */
-		if (bdp->rev_id < D101A4_REV_ID) {
-			if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) {
-				e100_set_multi(dev);
-			}
-		}
-	}
-	/* Issue command to dump statistics from device.        */
-	/* Check for command completion on next watchdog timer. */
-	e100_dump_stats_cntrs(bdp);
-
-	wmb();
-
-	/* relaunch watchdog timer in 2 sec */
-	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
-
-	if (list_empty(&bdp->active_rx_list))
-		e100_trigger_SWI(bdp);
-}
-
-/**
- * e100_manage_adaptive_ifs
- * @bdp: atapter's private data struct
- *
- * This routine manages the adaptive Inter-Frame Spacing algorithm
- * using a state machine.
- */
-void
-e100_manage_adaptive_ifs(struct e100_private *bdp)
-{
-	static u16 state_table[9][4] = {	// rows are states
-		{2, 0, 0, 0},	// state0   // column0: next state if increasing
-		{2, 0, 5, 30},	// state1   // column1: next state if decreasing
-		{5, 1, 5, 30},	// state2   // column2: IFS value for 100 mbit
-		{5, 3, 0, 0},	// state3   // column3: IFS value for 10 mbit
-		{5, 3, 10, 60},	// state4
-		{8, 4, 10, 60},	// state5
-		{8, 6, 0, 0},	// state6
-		{8, 6, 20, 60},	// state7
-		{8, 7, 20, 60}	// state8
-	};
-
-	u32 transmits =
-		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames);
-	u32 collisions =
-		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll);
-	u32 state = bdp->ifs_state;
-	u32 old_value = bdp->ifs_value;
-	int next_col;
-	u32 min_transmits;
-
-	if (bdp->cur_dplx_mode == FULL_DUPLEX) {
-		bdp->ifs_state = 0;
-		bdp->ifs_value = 0;
-
-	} else {		/* Half Duplex */
-		/* Set speed specific parameters */
-		if (bdp->cur_line_speed == 100) {
-			next_col = 2;
-			min_transmits = MIN_NUMBER_OF_TRANSMITS_100;
-
-		} else {	/* 10 Mbps */
-			next_col = 3;
-			min_transmits = MIN_NUMBER_OF_TRANSMITS_10;
-		}
-
-		if ((transmits / 32 < collisions)
-		    && (transmits > min_transmits)) {
-			state = state_table[state][0];	/* increment */
-
-		} else if (transmits < min_transmits) {
-			state = state_table[state][1];	/* decrement */
-		}
-
-		bdp->ifs_value = state_table[state][next_col];
-		bdp->ifs_state = state;
-	}
-
-	/* If the IFS value has changed, configure the device */
-	if (bdp->ifs_value != old_value) {
-		e100_config_ifs(bdp);
-		e100_config(bdp);
-	}
-}
-
-/**
- * e100intr - interrupt handler
- * @irq: the IRQ number
- * @dev_inst: the net_device struct
- * @regs: registers (unused)
- *
- * This routine is the ISR for the e100 board. It services
- * the RX & TX queues & starts the RU if it has stopped due
- * to no resources.
- */
-irqreturn_t
-e100intr(int irq, void *dev_inst, struct pt_regs *regs)
-{
-	struct net_device *dev;
-	struct e100_private *bdp;
-	u16 intr_status;
-
-	dev = dev_inst;
-	bdp = dev->priv;
-
-	intr_status = readw(&bdp->scb->scb_status);
-	/* If not my interrupt, just return */
-	if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) {
-		return IRQ_NONE;
-	}
-
-	/* disable and ack intr */
-	e100_disable_clear_intr(bdp);
-
-	/* the device is closed, don't continue or else bad things may happen. */
-	if (!netif_running(dev)) {
-		e100_set_intr_mask(bdp);
-		return IRQ_NONE;
-	}
-
-	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
-	if (intr_status & SCB_STATUS_ACK_SWI) {
-		e100_alloc_skbs(bdp);
-	}
-
-	/* do recv work if any */
-	if (intr_status &
-	    (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) 
-		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
-
-	/* clean up after tx'ed packets */
-	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
-		e100_tx_srv(bdp);
-
-	e100_set_intr_mask(bdp);
-	return IRQ_HANDLED;
-}
-
-/**
- * e100_tx_skb_free - free TX skbs resources
- * @bdp: atapter's private data struct
- * @tcb: associated tcb of the freed skb
- *
- * This routine frees resources of TX skbs.
- */
-static inline void
-e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
-{
-	if (tcb->tcb_skb) {
-		int i;
-		tbd_t *tbd_arr = tcb->tbd_ptr;
-		int frags = skb_shinfo(tcb->tcb_skb)->nr_frags;
-
-		for (i = 0; i <= frags; i++, tbd_arr++) {
-			pci_unmap_single(bdp->pdev,
-					 le32_to_cpu(tbd_arr->tbd_buf_addr),
-					 le16_to_cpu(tbd_arr->tbd_buf_cnt),
-					 PCI_DMA_TODEVICE);
-		}
-		dev_kfree_skb_irq(tcb->tcb_skb);
-		tcb->tcb_skb = NULL;
-	}
-}
-
-/**
- * e100_tx_srv - service TX queues
- * @bdp: atapter's private data struct
- *
- * This routine services the TX queues. It reclaims the TCB's & TBD's & other
- * resources used during the transmit of this buffer. It is called from the ISR.
- * We don't need a tx_lock since we always access buffers which were already
- * prepared.
- */
-void
-e100_tx_srv(struct e100_private *bdp)
-{
-	tcb_t *tcb;
-	int i;
-
-	/* go over at most TxDescriptors buffers */
-	for (i = 0; i < bdp->params.TxDescriptors; i++) {
-		tcb = bdp->tcb_pool.data;
-		tcb += bdp->tcb_pool.head;
-
-		rmb();
-
-		/* if the buffer at 'head' is not complete, break */
-		if (!(tcb->tcb_hdr.cb_status &
-		      __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
-			break;
-
-		/* service next buffer, clear the out of resource condition */
-		e100_tx_skb_free(bdp, tcb);
-
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
-
-		/* if we've caught up with 'tail', break */
-		if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) {
-			break;
-		}
-
-		bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
-	}
-}
-
-/**
- * e100_rx_srv - service RX queue
- * @bdp: atapter's private data struct
- * @max_number_of_rfds: max number of RFDs to process
- * @rx_congestion: flag pointer, to inform the calling function of congestion.
- *
- * This routine processes the RX interrupt & services the RX queues.
- * For each successful RFD, it allocates a new msg block, links that
- * into the RFD list, and sends the old msg upstream.
- * The new RFD is then put at the end of the free list of RFD's.
- * It returns the number of serviced RFDs.
- */
-u32
-e100_rx_srv(struct e100_private *bdp)
-{
-	rfd_t *rfd;		/* new rfd, received rfd */
-	int i;
-	u16 rfd_status;
-	struct sk_buff *skb;
-	struct net_device *dev;
-	unsigned int data_sz;
-	struct rx_list_elem *rx_struct;
-	u32 rfd_cnt = 0;
-
-	dev = bdp->device;
-
-	/* current design of rx is as following:
-	 * 1. socket buffer (skb) used to pass network packet to upper layer
-	 * 2. all HW host memory structures (like RFDs, RBDs and data buffers)
-	 *    are placed in a skb's data room
-	 * 3. when rx process is complete, we change skb internal pointers to exclude
-	 *    from data area all unrelated things (RFD, RDB) and to leave
-	 *    just rx'ed packet netto
-	 * 4. for each skb passed to upper layer, new one is allocated instead.
-	 * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made
-	 *    (watchdog trigger SWI intr and isr should allocate new skbs)
-	 */
-	for (i = 0; i < bdp->params.RxDescriptors; i++) {
-		if (list_empty(&(bdp->active_rx_list))) {
-			break;
-		}
-
-		rx_struct = list_entry(bdp->active_rx_list.next,
-				       struct rx_list_elem, list_elem);
-		skb = rx_struct->skb;
-
-		rfd = RFD_POINTER(skb, bdp);	/* locate RFD within skb */
-
-		// sync only the RFD header
-		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
-				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
-		rfd_status = le16_to_cpu(rfd->rfd_header.cb_status);	/* get RFD's status */
-		if (!(rfd_status & RFD_STATUS_COMPLETE))	/* does not contains data yet - exit */
-			break;
-
-		/* to allow manipulation with current skb we need to unlink it */
-		list_del(&(rx_struct->list_elem));
-
-		/* do not free & unmap badly received packet.
-		 * move it to the end of skb list for reuse */
-		if (!(rfd_status & RFD_STATUS_OK)) {
-			e100_add_skb_to_end(bdp, rx_struct);
-			continue;
-		}
-
-		data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff),
-				(sizeof (rfd_t) - bdp->rfd_size));
-
-		/* now sync all the data */
-		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
-				    (data_sz + bdp->rfd_size),
-				    PCI_DMA_FROMDEVICE);
-
-		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
-				 sizeof (rfd_t), PCI_DMA_FROMDEVICE);
-
-		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
-
-		/* end of dma access to rfd */
-		bdp->skb_req++;	/* incr number of requested skbs */
-		e100_alloc_skbs(bdp);	/* and get them */
-
-		/* set packet size, excluding checksum (2 last bytes) if it is present */
-		if ((bdp->flags & DF_CSUM_OFFLOAD)
-		    && (bdp->rev_id < D102_REV_ID))
-			skb_put(skb, (int) data_sz - 2);
-		else
-			skb_put(skb, (int) data_sz);
-
-		/* set the protocol */
-		skb->protocol = eth_type_trans(skb, dev);
-
-		/* set the checksum info */
-		if (bdp->flags & DF_CSUM_OFFLOAD) {
-			if (bdp->rev_id >= D102_REV_ID) {
-				skb->ip_summed = e100_D102_check_checksum(rfd);
-			} else {
-				skb->ip_summed = e100_D101M_checksum(bdp, skb);
-			}
-		} else {
-			skb->ip_summed = CHECKSUM_NONE;
-		}
-
-		bdp->drv_stats.net_stats.rx_bytes += skb->len;
-
-		if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
-			vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
-		} else {
-			netif_rx(skb);
-		}
-		dev->last_rx = jiffies;
-		
-		rfd_cnt++;
-	}			/* end of rfd loop */
-
-	/* restart the RU if it has stopped */
-	if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) {
-		e100_start_ru(bdp);
-	}
-
-	return rfd_cnt;
-}
-
-void
-e100_refresh_txthld(struct e100_private *bdp)
-{
-	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
-
-	/* as long as tx_per_underrun is not 0, we can go about dynamically *
-	 * adjusting the xmit threshold. we stop doing that & resort to defaults
-	 * * once the adjustments become meaningless. the value is adjusted by *
-	 * dumping the error counters & checking the # of xmit underrun errors *
-	 * we've had. */
-	if (bdp->tx_per_underrun) {
-		/* We are going to last values dumped from the dump statistics
-		 * command */
-		if (le32_to_cpu(pstat->xmt_gd_frames)) {
-			if (le32_to_cpu(pstat->xmt_uruns)) {
-				/* 
-				 * if we have had more than one underrun per "DEFAULT #
-				 * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the
-				 * THRESHOLD.
-				 */
-				if ((le32_to_cpu(pstat->xmt_gd_frames) /
-				     le32_to_cpu(pstat->xmt_uruns)) <
-				    bdp->tx_per_underrun) {
-					bdp->tx_thld += 3;
-				}
-			}
-
-			/* 
-			 * if we've had less than one underrun per the DEFAULT number of
-			 * of good xmits allowed, lower the THOLD but not less than 0 
-			 */
-			if (le32_to_cpu(pstat->xmt_gd_frames) >
-			    bdp->tx_per_underrun) {
-				bdp->tx_thld--;
-
-				if (bdp->tx_thld < 6)
-					bdp->tx_thld = 6;
-
-			}
-		}
-
-		/* end good xmits */
-		/* 
-		 * * if our adjustments are becoming unresonable, stop adjusting &
-		 * resort * to defaults & pray. A THOLD value > 190 means that the
-		 * adapter will * wait for 190*8=1520 bytes in TX FIFO before it
-		 * starts xmit. Since * MTU is 1514, it doesn't make any sense for
-		 * further increase. */
-		if (bdp->tx_thld >= 190) {
-			bdp->tx_per_underrun = 0;
-			bdp->tx_thld = 189;
-		}
-	}			/* end underrun check */
-}
-
-/**
- * e100_prepare_xmit_buff - prepare a buffer for transmission
- * @bdp: atapter's private data struct
- * @skb: skb to send
- *
- * This routine prepare a buffer for transmission. It checks
- * the message length for the appropiate size. It picks up a
- * free tcb from the TCB pool and sets up the corresponding
- * TBD's. If the number of fragments are more than the number
- * of TBD/TCB it copies all the fragments in a coalesce buffer.
- * It returns a pointer to the prepared TCB.
- */
-static inline tcb_t *
-e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
-{
-	tcb_t *tcb, *prev_tcb;
-
-	tcb = bdp->tcb_pool.data;
-	tcb += TCB_TO_USE(bdp->tcb_pool);
-
-	if (bdp->flags & USE_IPCB) {
-		tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT;
-		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET;
-		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
-	}
-
-	if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
-		(tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
-		(tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
-	}
-	
-	tcb->tcb_hdr.cb_status = 0;
-	tcb->tcb_thrshld = bdp->tx_thld;
-	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
-
-	/* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
-	if (!(++bdp->tx_count % TX_FRAME_CNT))
-		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
-	else
-		/* Clear I bit on other packets */
-		tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
-
-	tcb->tcb_skb = skb;
-
-	if (skb->ip_summed == CHECKSUM_HW) {
-		const struct iphdr *ip = skb->nh.iph;
-
-		if ((ip->protocol == IPPROTO_TCP) ||
-		    (ip->protocol == IPPROTO_UDP)) {
-
-			tcb->tcbu.ipcb.ip_activation_high |=
-				IPCB_HARDWAREPARSING_ENABLE;
-			tcb->tcbu.ipcb.ip_schedule |=
-				IPCB_TCPUDP_CHECKSUM_ENABLE;
-
-			if (ip->protocol == IPPROTO_TCP)
-				tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
-		}
-	}
-
-	if (!skb_shinfo(skb)->nr_frags) {
-		(tcb->tbd_ptr)->tbd_buf_addr =
-			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
-						   skb->len, PCI_DMA_TODEVICE));
-		(tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
-		tcb->tcb_tbd_num = 1;
-		tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr;
-	} else {
-		int i;
-		void *addr;
-		tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]);
-		skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
-
-		(tcb->tbd_ptr)->tbd_buf_addr =
-			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
-						   skb_headlen(skb),
-						   PCI_DMA_TODEVICE));
-		(tcb->tbd_ptr)->tbd_buf_cnt =
-			cpu_to_le16(skb_headlen(skb));
-
-		for (i = 0; i < skb_shinfo(skb)->nr_frags;
-		     i++, tbd_arr_ptr++, frag++) {
-
-			addr = ((void *) page_address(frag->page) +
-				frag->page_offset);
-
-			tbd_arr_ptr->tbd_buf_addr =
-				cpu_to_le32(pci_map_single(bdp->pdev,
-							   addr, frag->size,
-							   PCI_DMA_TODEVICE));
-			tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size);
-		}
-		tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1;
-		tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr;
-	}
-
-	/* clear the S-BIT on the previous tcb */
-	prev_tcb = bdp->tcb_pool.data;
-	prev_tcb += PREV_TCB_USED(bdp->tcb_pool);
-	prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT);
-
-	bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail);
-
-	wmb();
-
-	e100_start_cu(bdp, tcb);
-
-	return tcb;
-}
-
-/* Changed for 82558 enhancement */
-/**
- * e100_start_cu - start the adapter's CU
- * @bdp: atapter's private data struct
- * @tcb: TCB to be transmitted
- *
- * This routine issues a CU Start or CU Resume command to the 82558/9.
- * This routine was added because the prepare_ext_xmit_buff takes advantage
- * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as
- * soon as the first TBD is ready. 
- *
- * e100_start_cu must be called while holding the tx_lock ! 
- */
-u8
-e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
-{
-	unsigned long lock_flag;
-	u8 ret = true;
-
-	spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
-	switch (bdp->next_cu_cmd) {
-	case RESUME_NO_WAIT:
-		/*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to
-		 * wait for command word to clear, we reach here only if we are bachlor
-		 */
-		e100_exec_cmd(bdp, SCB_CUC_RESUME);
-		break;
-
-	case RESUME_WAIT:
-		if ((bdp->flags & IS_ICH) &&
-		    (bdp->cur_line_speed == 10) &&
-		    (bdp->cur_dplx_mode == HALF_DUPLEX)) {
-			e100_wait_exec_simple(bdp, SCB_CUC_NOOP);
-			udelay(1);
-		}
-		if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) &&
-		    (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) {
-			bdp->next_cu_cmd = RESUME_NO_WAIT;
-		}
-		break;
-
-	case START_WAIT:
-		// The last command was a non_tx CU command
-		if (!e100_wait_cus_idle(bdp))
-			printk(KERN_DEBUG
-			       "e100: %s: cu_start: timeout waiting for cu\n",
-			       bdp->device->name);
-		if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
-					  SCB_CUC_START, CB_TRANSMIT)) {
-			printk(KERN_DEBUG
-			       "e100: %s: cu_start: timeout waiting for scb\n",
-			       bdp->device->name);
-			e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
-					SCB_CUC_START);
-			ret = false;
-		}
-
-		bdp->next_cu_cmd = RESUME_WAIT;
-
-		break;
-	}
-
-	/* save the last tcb */
-	bdp->last_tcb = tcb;
-
-	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
-	return ret;
-}
-
-/* ====================================================================== */
-/* hw                                                                     */
-/* ====================================================================== */
-
-/**
- * e100_selftest - perform H/W self test
- * @bdp: atapter's private data struct
- * @st_timeout: address to return timeout value, if fails
- * @st_result: address to return selftest result, if fails
- *
- * This routine will issue PORT Self-test command to test the e100.
- * The self-test will fail if the adapter's master-enable bit is not
- * set in the PCI Command Register, or if the adapter is not seated
- * in a PCI master-enabled slot. we also disable interrupts when the
- * command is completed.
- *
- * Returns:
- *      true: if adapter passes self_test
- *      false: otherwise
- */
-unsigned char
-e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
-{
-	u32 selftest_cmd;
-
-	/* initialize the nic state before running test */
-	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-	/* Setup the address of the self_test area */
-	selftest_cmd = bdp->selftest_phys;
-
-	/* Setup SELF TEST Command Code in D3 - D0 */
-	selftest_cmd |= PORT_SELFTEST;
-
-	/* Initialize the self-test signature and results DWORDS */
-	bdp->selftest->st_sign = 0;
-	bdp->selftest->st_result = 0xffffffff;
-
-	/* Do the port command */
-	writel(selftest_cmd, &bdp->scb->scb_port);
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
-
-	/* Wait at least 10 milliseconds for the self-test to complete */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 100 + 1);
-
-	/* disable interrupts since they are enabled */
-	/* after device reset during selftest        */
-	e100_disable_clear_intr(bdp);
-
-	/* if The First Self Test DWORD Still Zero, We've timed out. If the
-	 * second DWORD is not zero then we have an error. */
-	if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) {
-
-		if (st_timeout)
-			*st_timeout = !(le32_to_cpu(bdp->selftest->st_sign));
-
-		if (st_result)
-			*st_result = le32_to_cpu(bdp->selftest->st_result);
-
-		return false;
-	}
-
-	return true;
-}
-
-/**
- * e100_setup_iaaddr - issue IA setup sommand
- * @bdp: atapter's private data struct
- * @eaddr: new ethernet address
- *
- * This routine will issue the IA setup command. This command
- * will notify the 82557 (e100) of what its individual (node)
- * address is. This command will be executed in polled mode.
- *
- * Returns:
- *      true: if the IA setup command was successfully issued and completed
- *      false: otherwise
- */
-unsigned char
-e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr)
-{
-	unsigned int i;
-	cb_header_t *ntcb_hdr;
-	unsigned char res;
-	nxmit_cb_entry_t *cmd;
-
-	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
-		res = false;
-		goto exit;
-	}
-
-	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
-	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS);
-
-	for (i = 0; i < ETH_ALEN; i++) {
-		(cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i];
-	}
-
-	res = e100_exec_non_cu_cmd(bdp, cmd);
-	if (!res)
-		printk(KERN_WARNING "e100: %s: IA setup failed\n", 
-		       bdp->device->name);
-
-exit:
-	return res;
-}
-
-/**
- * e100_start_ru - start the RU if needed
- * @bdp: atapter's private data struct
- *
- * This routine checks the status of the 82557's receive unit(RU),
- * and starts the RU if it was not already active.  However,
- * before restarting the RU, the driver gives the RU the buffers
- * it freed up during the servicing of the ISR. If there are
- * no free buffers to give to the RU, (i.e. we have reached a
- * no resource condition) the RU will not be started till the
- * next ISR.
- */
-void
-e100_start_ru(struct e100_private *bdp)
-{
-	struct rx_list_elem *rx_struct = NULL;
-	int buffer_found = 0;
-	struct list_head *entry_ptr;
-
-	list_for_each(entry_ptr, &(bdp->active_rx_list)) {
-		rx_struct =
-			list_entry(entry_ptr, struct rx_list_elem, list_elem);
-		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
-				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
-		if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) &
-		       __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) {
-			buffer_found = 1;
-			break;
-		}
-	}
-
-	/* No available buffers */
-	if (!buffer_found) {
-		return;
-	}
-
-	spin_lock(&bdp->bd_lock);
-
-	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) {
-		printk(KERN_DEBUG
-		       "e100: %s: start_ru: wait_scb failed\n", 
-		       bdp->device->name);
-		e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START);
-	}
-	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
-		bdp->next_cu_cmd = RESUME_WAIT;
-	}
-	spin_unlock(&bdp->bd_lock);
-}
-
-/**
- * e100_cmd_complete_location
- * @bdp: atapter's private data struct
- *
- * This routine returns a pointer to the location of the command-complete
- * DWord in the dump statistical counters area, according to the statistical
- * counters mode (557 - basic, 558 - extended, or 559 - TCO mode).
- * See e100_config_init() for the setting of the statistical counters mode.
- */
-static u32 *
-e100_cmd_complete_location(struct e100_private *bdp)
-{
-	u32 *cmd_complete;
-	max_counters_t *stats = bdp->stats_counters;
-
-	switch (bdp->stat_mode) {
-	case E100_EXTENDED_STATS:
-		cmd_complete =
-			(u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete);
-		break;
-
-	case E100_TCO_STATS:
-		cmd_complete =
-			(u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete);
-		break;
-
-	case E100_BASIC_STATS:
-	default:		
-		cmd_complete =
-			(u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete);
-		break;
-	}
-
-	return cmd_complete;
-}
-
-/**
- * e100_clr_cntrs - clear statistics counters
- * @bdp: atapter's private data struct
- *
- * This routine will clear the adapter error statistic counters.
- *
- * Returns:
- *      true: if successfully cleared stat counters
- *      false: otherwise
- */
-static unsigned char
-e100_clr_cntrs(struct e100_private *bdp)
-{
-	volatile u32 *pcmd_complete;
-
-	/* clear the dump counter complete word */
-	pcmd_complete = e100_cmd_complete_location(bdp);
-	*pcmd_complete = 0;
-	wmb();
-
-	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
-		return false;
-
-	/* wait 10 microseconds for the command to complete */
-	udelay(10);
-
-	if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT))
-		return false;
-
-	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
-		bdp->next_cu_cmd = RESUME_WAIT;
-	}
-
-	return true;
-}
-
-static unsigned char
-e100_update_stats(struct e100_private *bdp)
-{
-	u32 *pcmd_complete;
-	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
-
-	// check if last dump command completed
-	pcmd_complete = e100_cmd_complete_location(bdp);
-	if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
-	    *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
-		*pcmd_complete = 0;
-		return false;
-	}
-
-	/* increment the statistics */
-	bdp->drv_stats.net_stats.rx_packets +=
-		le32_to_cpu(pstat->rcv_gd_frames);
-	bdp->drv_stats.net_stats.tx_packets +=
-		le32_to_cpu(pstat->xmt_gd_frames);
-	bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err);
-	bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll);
-	bdp->drv_stats.net_stats.rx_length_errors +=
-		le32_to_cpu(pstat->rcv_shrt_frames);
-	bdp->drv_stats.net_stats.rx_over_errors +=
-		le32_to_cpu(pstat->rcv_rsrc_err);
-	bdp->drv_stats.net_stats.rx_crc_errors +=
-		le32_to_cpu(pstat->rcv_crc_errs);
-	bdp->drv_stats.net_stats.rx_frame_errors +=
-		le32_to_cpu(pstat->rcv_algn_errs);
-	bdp->drv_stats.net_stats.rx_fifo_errors +=
-		le32_to_cpu(pstat->rcv_oruns);
-	bdp->drv_stats.net_stats.tx_aborted_errors +=
-		le32_to_cpu(pstat->xmt_max_coll);
-	bdp->drv_stats.net_stats.tx_carrier_errors +=
-		le32_to_cpu(pstat->xmt_lost_crs);
-	bdp->drv_stats.net_stats.tx_fifo_errors +=
-		le32_to_cpu(pstat->xmt_uruns);
-
-	bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll);
-	bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred);
-	bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll);
-	bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll);
-	bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll);
-
-	if (bdp->stat_mode != E100_BASIC_STATS) {
-		ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats;
-
-		bdp->drv_stats.xmt_fc_pkts +=
-			le32_to_cpu(pex_stat->xmt_fc_frames);
-		bdp->drv_stats.rcv_fc_pkts +=
-			le32_to_cpu(pex_stat->rcv_fc_frames);
-		bdp->drv_stats.rcv_fc_unsupported +=
-			le32_to_cpu(pex_stat->rcv_fc_unsupported);
-	}
-
-	if (bdp->stat_mode == E100_TCO_STATS) {
-		tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats;
-
-		bdp->drv_stats.xmt_tco_pkts +=
-			le16_to_cpu(ptco_stat->xmt_tco_frames);
-		bdp->drv_stats.rcv_tco_pkts +=
-			le16_to_cpu(ptco_stat->rcv_tco_frames);
-	}
-
-	*pcmd_complete = 0;
-	return true;
-}
-
-/**
- * e100_dump_stat_cntrs
- * @bdp: atapter's private data struct
- *
- * This routine will dump the board statistical counters without waiting
- * for stat_dump to complete. Any access to this stats should verify the completion
- * of the command
- */
-void
-e100_dump_stats_cntrs(struct e100_private *bdp)
-{
-	unsigned long lock_flag_bd;
-
-	spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd);
-
-	/* dump h/w stats counters */
-	if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) {
-		if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
-			bdp->next_cu_cmd = RESUME_WAIT;
-		}
-	}
-
-	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd);
-}
-
-/**
- * e100_exec_non_cu_cmd
- * @bdp: atapter's private data struct
- * @command: the non-cu command to execute
- *
- * This routine will submit a command block to be executed,
- */
-unsigned char
-e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
-{
-	cb_header_t *ntcb_hdr;
-	unsigned long lock_flag;
-	unsigned long expiration_time;
-	unsigned char rc = true;
-	u8 sub_cmd;
-
-	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;	/* get hdr of non tcb cmd */
-	sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd);
-
-	/* Set the Command Block to be the last command block */
-	ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
-	ntcb_hdr->cb_status = 0;
-	ntcb_hdr->cb_lnk_ptr = 0;
-
-	wmb();
-	if (in_interrupt())
-		return e100_delayed_exec_non_cu_cmd(bdp, command);
-
-	if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
-		return e100_delayed_exec_non_cu_cmd(bdp, command);
-
-	spin_lock_bh(&(bdp->bd_non_tx_lock));
-
-	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
-		goto delayed_exec;
-	}
-
-	if (bdp->last_tcb) {
-		rmb();
-		if ((bdp->last_tcb->tcb_hdr.cb_status &
-		     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
-			goto delayed_exec;
-	}
-
-	if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) {
-		goto delayed_exec;
-	}
-
-	spin_lock_irqsave(&bdp->bd_lock, lock_flag);
-
-	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) {
-		spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
-		rc = false;
-		goto exit;
-	}
-
-	bdp->next_cu_cmd = START_WAIT;
-	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
-
-	/* now wait for completion of non-cu CB up to 20 msec */
-	expiration_time = jiffies + HZ / 50 + 1;
-	rmb();
-	while (!(ntcb_hdr->cb_status &
-		     __constant_cpu_to_le16(CB_STATUS_COMPLETE))) {
-
-		if (time_before(jiffies, expiration_time)) {
-			spin_unlock_bh(&(bdp->bd_non_tx_lock));
-			yield();
-			spin_lock_bh(&(bdp->bd_non_tx_lock));
-		} else {
-#ifdef E100_CU_DEBUG			
-			printk(KERN_ERR "e100: %s: non-TX command (%x) "
-				"timeout\n", bdp->device->name, sub_cmd);
-#endif			
-			rc = false;
-			goto exit;
-		}
-		rmb();
-	}
-
-exit:
-	e100_free_non_tx_cmd(bdp, command);
-
-	if (netif_running(bdp->device))
-		netif_wake_queue(bdp->device);
-
-	spin_unlock_bh(&(bdp->bd_non_tx_lock));
-	return rc;
-
-delayed_exec:
-	spin_unlock_bh(&(bdp->bd_non_tx_lock));
-	return e100_delayed_exec_non_cu_cmd(bdp, command);
-}
-
-/**
- * e100_sw_reset
- * @bdp: atapter's private data struct
- * @reset_cmd: s/w reset or selective reset
- *
- * This routine will issue a software reset to the adapter. It 
- * will also disable interrupts, as the are enabled after reset.
- */
-void
-e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
-{
-	/* Do  a selective reset first to avoid a potential PCI hang */
-	writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port);
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
-
-	/* wait for the reset to take effect */
-	udelay(20);
-	if (reset_cmd == PORT_SOFTWARE_RESET) {
-		writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port);
-
-		/* wait 20 micro seconds for the reset to take effect */
-		udelay(20);
-	}
-
-	/* Mask off our interrupt line -- it is unmasked after reset */
-	e100_disable_clear_intr(bdp);
-#ifdef E100_CU_DEBUG	
-	bdp->last_cmd = 0;
-	bdp->last_sub_cmd = 0;
-#endif	
-}
-
-/**
- * e100_load_microcode - Download microsocde to controller.
- * @bdp: atapter's private data struct
- *
- * This routine downloads microcode on to the controller. This
- * microcode is available for the 82558/9, 82550. Currently the
- * microcode handles interrupt bundling and TCO workaround.
- *
- * Returns:
- *      true: if successfull
- *      false: otherwise
- */
-static unsigned char
-e100_load_microcode(struct e100_private *bdp)
-{
-	static struct {
-		u8 rev_id;
-		u32 ucode[UCODE_MAX_DWORDS + 1];
-		int timer_dword;
-		int bundle_dword;
-		int min_size_dword;
-	} ucode_opts[] = {
-		{ D101A4_REV_ID,
-		  D101_A_RCVBUNDLE_UCODE,
-		  D101_CPUSAVER_TIMER_DWORD,
-		  D101_CPUSAVER_BUNDLE_DWORD,
-		  D101_CPUSAVER_MIN_SIZE_DWORD },
-		{ D101B0_REV_ID,
-		  D101_B0_RCVBUNDLE_UCODE,
-		  D101_CPUSAVER_TIMER_DWORD,
-		  D101_CPUSAVER_BUNDLE_DWORD,
-		  D101_CPUSAVER_MIN_SIZE_DWORD },
-		{ D101MA_REV_ID,
-		  D101M_B_RCVBUNDLE_UCODE,
-		  D101M_CPUSAVER_TIMER_DWORD,
-		  D101M_CPUSAVER_BUNDLE_DWORD,
-		  D101M_CPUSAVER_MIN_SIZE_DWORD },
-		{ D101S_REV_ID,
-		  D101S_RCVBUNDLE_UCODE,
-		  D101S_CPUSAVER_TIMER_DWORD,
-		  D101S_CPUSAVER_BUNDLE_DWORD,
-		  D101S_CPUSAVER_MIN_SIZE_DWORD },
-		{ D102_REV_ID,
-		  D102_B_RCVBUNDLE_UCODE,
-		  D102_B_CPUSAVER_TIMER_DWORD,
-		  D102_B_CPUSAVER_BUNDLE_DWORD,
-		  D102_B_CPUSAVER_MIN_SIZE_DWORD },
-		{ D102C_REV_ID,
-		  D102_C_RCVBUNDLE_UCODE,
-		  D102_C_CPUSAVER_TIMER_DWORD,
-		  D102_C_CPUSAVER_BUNDLE_DWORD,
-		  D102_C_CPUSAVER_MIN_SIZE_DWORD },
-		{ D102E_REV_ID,
-		  D102_E_RCVBUNDLE_UCODE,
-		  D102_E_CPUSAVER_TIMER_DWORD,
-		  D102_E_CPUSAVER_BUNDLE_DWORD,
-		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
-		{ 0, {0}, 0, 0, 0}
-	}, *opts;
-
-	opts = ucode_opts;
-
-	/* User turned ucode loading off */
-	if (!(bdp->params.b_params & PRM_UCODE))
-		return false;
-
-	/* These controllers do not need ucode */
-	if (bdp->flags & IS_ICH)
-		return false;
-
-	/* Search for ucode match against h/w rev_id */
-	while (opts->rev_id) {
-		if (bdp->rev_id == opts->rev_id) {
-			int i;
-			u32 *ucode_dword;
-			load_ucode_cb_t *ucode_cmd_ptr;
-			nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
-
-			if (cmd != NULL) {
-				ucode_cmd_ptr =
-					(load_ucode_cb_t *) cmd->non_tx_cmd;
-				ucode_dword = ucode_cmd_ptr->ucode_dword;
-			} else {
-				return false;
-			}
-
-			memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode));
-
-			/* Insert user-tunable settings */
-			ucode_dword[opts->timer_dword] &= 0xFFFF0000;
-			ucode_dword[opts->timer_dword] |=
-				(u16) bdp->params.IntDelay;
-			ucode_dword[opts->bundle_dword] &= 0xFFFF0000;
-			ucode_dword[opts->bundle_dword] |=
-				(u16) bdp->params.BundleMax;
-			ucode_dword[opts->min_size_dword] &= 0xFFFF0000;
-			ucode_dword[opts->min_size_dword] |=
-				(bdp->params.b_params & PRM_BUNDLE_SMALL) ?
-				0xFFFF : 0xFF80;
-
-			for (i = 0; i < UCODE_MAX_DWORDS; i++)
-				cpu_to_le32s(&(ucode_dword[i]));
-
-			ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd =
-				__constant_cpu_to_le16(CB_LOAD_MICROCODE);
-
-			return e100_exec_non_cu_cmd(bdp, cmd);
-		}
-		opts++;
-	}
-
-	return false;
-}
-
-/***************************************************************************/
-/***************************************************************************/
-/*       EEPROM  Functions                                                 */
-/***************************************************************************/
-
-/* Read PWA (printed wired assembly) number */
-void
-e100_rd_pwa_no(struct e100_private *bdp)
-{
-	bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO);
-	bdp->pwa_no <<= 16;
-	bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1);
-}
-
-/* Read the permanent ethernet address from the eprom. */
-void
-e100_rd_eaddr(struct e100_private *bdp)
-{
-	int i;
-	u16 eeprom_word;
-
-	for (i = 0; i < 6; i += 2) {
-		eeprom_word =
-			e100_eeprom_read(bdp,
-					 EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2));
-
-		bdp->device->dev_addr[i] =
-			bdp->perm_node_address[i] = (u8) eeprom_word;
-		bdp->device->dev_addr[i + 1] =
-			bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8);
-	}
-}
-
-/* Check the D102 RFD flags to see if the checksum passed */
-static unsigned char
-e100_D102_check_checksum(rfd_t *rfd)
-{
-	if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT)
-	    && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
-		 RFD_TCP_PACKET)
-		|| ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
-		    RFD_UDP_PACKET))
-	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID)
-	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) {
-		return CHECKSUM_UNNECESSARY;
-	}
-	return CHECKSUM_NONE;
-}
-
-/**
- * e100_D101M_checksum
- * @bdp: atapter's private data struct
- * @skb: skb received
- *
- * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The
- * D101M sums all words in frame excluding the ethernet II header (14 bytes) so
- * in case the packet is ethernet II and the protocol is IP, all is need is to
- * assign this value to skb->csum.
- */
-static unsigned char
-e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb)
-{
-	unsigned short proto = (skb->protocol);
-
-	if (proto == __constant_htons(ETH_P_IP)) {
-
-		skb->csum = get_unaligned((u16 *) (skb->tail));
-		return CHECKSUM_HW;
-	}
-	return CHECKSUM_NONE;
-}
-
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-/*       Auxilary Functions                                                */
-/***************************************************************************/
-
-/* Print the board's configuration */
-void
-e100_print_brd_conf(struct e100_private *bdp)
-{
-	/* Print the string if checksum Offloading was enabled */
-	if (bdp->flags & DF_CSUM_OFFLOAD)
-		printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
-	else {
-		if (bdp->rev_id >= D101MA_REV_ID) 
-			printk(KERN_NOTICE "  Hardware receive checksums disabled\n");
-	}
-
-	if ((bdp->flags & DF_UCODE_LOADED))
-		printk(KERN_NOTICE "  cpu cycle saver enabled\n");
-}
-
-/**
- * e100_pci_setup - setup the adapter's PCI information
- * @pcid: adapter's pci_dev struct
- * @bdp: atapter's private data struct
- *
- * This routine sets up all PCI information for the adapter. It enables the bus
- * master bit (some BIOS don't do this), requests memory ans I/O regions, and
- * calls ioremap() on the adapter's memory region.
- *
- * Returns:
- *      true: if successfull
- *      false: otherwise
- */
-static unsigned char
-e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp)
-{
-	struct net_device *dev = bdp->device;
-	int rc = 0;
-
-	if ((rc = pci_enable_device(pcid)) != 0) {
-		goto err;
-	}
-
-	/* dev and ven ID have already been checked so it is our device */
-	pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id));
-
-	/* address #0 is a memory region */
-	dev->mem_start = pci_resource_start(pcid, 0);
-	dev->mem_end = dev->mem_start + sizeof (scb_t);
-
-	/* address #1 is a IO region */
-	dev->base_addr = pci_resource_start(pcid, 1);
-
-	if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) {
-		goto err_disable;
-	}
-
-	pci_enable_wake(pcid, 0, 0);
-
-	/* if Bus Mastering is off, turn it on! */
-	pci_set_master(pcid);
-
-	/* address #0 is a memory mapping */
-	bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t));
-
-	if (!bdp->scb) {
-		printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n",
-		       dev->name, pci_resource_start(pcid, 0));
-		rc = -ENOMEM;
-		goto err_region;
-	}
-
-	return 0;
-
-err_region:
-	pci_release_regions(pcid);
-err_disable:
-	pci_disable_device(pcid);
-err:
-	return rc;
-}
-
-void
-e100_isolate_driver(struct e100_private *bdp)
-{
-
-	/* Check if interface is up                              */
-	/* NOTE: Can't use netif_running(bdp->device) because    */
-	/* dev_close clears __LINK_STATE_START before calling    */
-	/* e100_close (aka dev->stop)                            */
-	if (bdp->device->flags & IFF_UP) {
-		e100_disable_clear_intr(bdp);
-		del_timer_sync(&bdp->watchdog_timer);
-		netif_carrier_off(bdp->device);
-		netif_stop_queue(bdp->device); 
-		bdp->last_tcb = NULL;
-	} 
-	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-}
-
-static void
-e100_tcb_add_C_bit(struct e100_private *bdp)
-{
-	tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data;
-	int i;
-
-	for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) {
-		tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE);
-	}
-}
-
-/* 
- * Procedure:   e100_configure_device
- *
- * Description: This routine will configure device
- *
- * Arguments:
- *      bdp - Ptr to this card's e100_bdconfig structure
- *
- * Returns:
- *        true upon success
- *        false upon failure
- */
-unsigned char
-e100_configure_device(struct e100_private *bdp)
-{
-	/*load CU & RU base */
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
-		return false;
-
-	if (e100_load_microcode(bdp))
-		bdp->flags |= DF_UCODE_LOADED;
-
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
-		return false;
-
-	/* Issue the load dump counters address command */
-	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
-		return false;
-
-	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
-		printk(KERN_ERR "e100: e100_configure_device: "
-			"setup iaaddr failed\n");
-		return false;
-	}
-
-	e100_set_multi_exec(bdp->device);
-
-	/* Change for 82558 enhancement                                */
-	/* If 82558/9 and if the user has enabled flow control, set up */
-	/* flow Control Reg. in the CSR                                */
-	if ((bdp->flags & IS_BACHELOR)
-	    && (bdp->params.b_params & PRM_FC)) {
-		writeb(DFLT_FC_THLD,
-			&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
-		writeb(DFLT_FC_CMD,
-			&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
-	}
-
-	e100_force_config(bdp);
-
-	return true;
-}
-
-void
-e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
-{
-	u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
-	e100_sw_reset(bdp, cmd);
-	if (cmd == PORT_SOFTWARE_RESET) {
-		if (!e100_configure_device(bdp))
-			printk(KERN_ERR "e100: e100_deisolate_driver:" 
-		       		" device configuration failed\n");
-	} 
-
-	if (netif_running(bdp->device)) {
-
-		bdp->next_cu_cmd = START_WAIT;
-		bdp->last_tcb = NULL;
-
-		e100_start_ru(bdp);
-
-		/* relaunch watchdog timer in 2 sec */
-		mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
-
-		// we must clear tcbs since we may have lost Tx intrrupt
-		// or have unsent frames on the tcb chain
-		e100_tcb_add_C_bit(bdp);
-		e100_tx_srv(bdp);
-		netif_wake_queue(bdp->device);
-		e100_set_intr_mask(bdp);
-	}
-}
-
-static int
-e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
-{
-	struct ethtool_cmd ecmd;
-	int rc = -EOPNOTSUPP;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd)))
-		return -EFAULT;
-
-	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		rc = e100_ethtool_get_settings(dev, ifr);
-		break;
-	case ETHTOOL_SSET:
-		rc = e100_ethtool_set_settings(dev, ifr);
-		break;
-	case ETHTOOL_GDRVINFO:
-		rc = e100_ethtool_get_drvinfo(dev, ifr);
-		break;
-	case ETHTOOL_GREGS:
-		rc = e100_ethtool_gregs(dev, ifr);
-		break;
-	case ETHTOOL_NWAY_RST:
-		rc = e100_ethtool_nway_rst(dev, ifr);
-		break;
-	case ETHTOOL_GLINK:
-		rc = e100_ethtool_glink(dev, ifr);
-		break;
-	case ETHTOOL_GEEPROM:
-	case ETHTOOL_SEEPROM:
-		rc = e100_ethtool_eeprom(dev, ifr);
-		break;
-	case ETHTOOL_GSTATS: {
-		struct {
-			struct ethtool_stats cmd;
-			uint64_t data[E100_STATS_LEN];
-		} stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
-		struct e100_private *bdp = dev->priv;
-		void *addr = ifr->ifr_data;
-		int i;
-
-		for(i = 0; i < E100_STATS_LEN; i++)
-			stats.data[i] =
-				((unsigned long *)&bdp->drv_stats.net_stats)[i];
-		if(copy_to_user(addr, &stats, sizeof(stats)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GWOL:
-	case ETHTOOL_SWOL:
-		rc = e100_ethtool_wol(dev, ifr);
-		break;
-	case ETHTOOL_TEST:
-		rc = e100_ethtool_test(dev, ifr);
-		break;
-	case ETHTOOL_GSTRINGS:
-		rc = e100_ethtool_gstrings(dev,ifr);
-		break;
-	case ETHTOOL_PHYS_ID:
-		rc = e100_ethtool_led_blink(dev,ifr);
-		break;
-#ifdef	ETHTOOL_GRINGPARAM
-	case ETHTOOL_GRINGPARAM: {
-		struct ethtool_ringparam ering;
-		struct e100_private *bdp = dev->priv;
-		memset((void *) &ering, 0, sizeof(ering));
-		ering.rx_max_pending = E100_MAX_RFD;
-		ering.tx_max_pending = E100_MAX_TCB;
-		ering.rx_pending = bdp->params.RxDescriptors;
-		ering.tx_pending = bdp->params.TxDescriptors;
-		rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering))
-			? -EFAULT : 0;
-		return rc;
-	}
-#endif
-#ifdef	ETHTOOL_SRINGPARAM
-	case ETHTOOL_SRINGPARAM: {
-		struct ethtool_ringparam ering;
-		struct e100_private *bdp = dev->priv;
-		if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering)))
-			return -EFAULT;
-		if (ering.rx_pending > E100_MAX_RFD 
-		    || ering.rx_pending < E100_MIN_RFD)
-			return -EINVAL;
-		if (ering.tx_pending > E100_MAX_TCB 
-		    || ering.tx_pending < E100_MIN_TCB)
-			return -EINVAL;
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-			/* Use new values to open interface */
-			bdp->params.RxDescriptors = ering.rx_pending;
-			bdp->params.TxDescriptors = ering.tx_pending;
-			e100_hw_init(bdp);
-			e100_open(dev);
-		}
-		else {
-			bdp->params.RxDescriptors = ering.rx_pending;
-			bdp->params.TxDescriptors = ering.tx_pending;
-		}
-		return 0;
-	}
-#endif
-#ifdef	ETHTOOL_GPAUSEPARAM
-	case ETHTOOL_GPAUSEPARAM: {
-		struct ethtool_pauseparam epause;
-		struct e100_private *bdp = dev->priv;
-		memset((void *) &epause, 0, sizeof(epause));
-		if ((bdp->flags & IS_BACHELOR)
-		    && (bdp->params.b_params & PRM_FC)) {
-			epause.autoneg = 1;
-			if (bdp->flags && DF_LINK_FC_CAP) {
-				epause.rx_pause = 1;
-				epause.tx_pause = 1;
-			}
-			if (bdp->flags && DF_LINK_FC_TX_ONLY)
-				epause.tx_pause = 1;
-		}
-		rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause))
-			? -EFAULT : 0;
-		return rc;
-	}
-#endif
-#ifdef	ETHTOOL_SPAUSEPARAM
-	case ETHTOOL_SPAUSEPARAM: {
-		struct ethtool_pauseparam epause;
-		struct e100_private *bdp = dev->priv;
-		if (!(bdp->flags & IS_BACHELOR))
-			return -EINVAL;
-		if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause)))
-			return -EFAULT;
-		if (epause.autoneg == 1)
-			bdp->params.b_params |= PRM_FC;
-		else
-			bdp->params.b_params &= ~PRM_FC;
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-			e100_hw_init(bdp);
-			e100_open(dev);
-		}
-		return 0;
-	}
-#endif
-#ifdef	ETHTOOL_GRXCSUM
-	case ETHTOOL_GRXCSUM:
-	case ETHTOOL_GTXCSUM:
-	case ETHTOOL_GSG:
-	{	struct ethtool_value eval;
-		struct e100_private *bdp = dev->priv;
-		memset((void *) &eval, 0, sizeof(eval));
-		if ((ecmd.cmd == ETHTOOL_GRXCSUM) 
-		    && (bdp->params.b_params & PRM_XSUMRX))
-			eval.data = 1;
-		else
-			eval.data = 0;
-		rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval))
-			? -EFAULT : 0;
-		return rc;
-	}
-#endif
-#ifdef	ETHTOOL_SRXCSUM
-	case ETHTOOL_SRXCSUM:
-	case ETHTOOL_STXCSUM:
-	case ETHTOOL_SSG:
-	{	struct ethtool_value eval;
-		struct e100_private *bdp = dev->priv;
-		if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval)))
-			return -EFAULT;
-		if (ecmd.cmd == ETHTOOL_SRXCSUM) {
-			if (eval.data == 1) { 
-				if (bdp->rev_id >= D101MA_REV_ID)
-					bdp->params.b_params |= PRM_XSUMRX;
-				else
-					return -EINVAL;
-			} else {
-				if (bdp->rev_id >= D101MA_REV_ID)
-					bdp->params.b_params &= ~PRM_XSUMRX;
-				else
-					return 0;
-			}
-		} else {
-			if (eval.data == 1)
-				return -EINVAL;
-			else
-				return 0;
-		}
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-			e100_hw_init(bdp);
-			e100_open(dev);
-		}
-		return 0;
-	}
-#endif
-	default:
-		break;
-	}			//switch
-	return rc;
-}
-
-static int
-e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_cmd ecmd;
-	u16 advert = 0;
-
-	memset((void *) &ecmd, 0, sizeof (ecmd));
-
-	bdp = dev->priv;
-
-	ecmd.supported = bdp->speed_duplex_caps;
-
-	ecmd.port =
-		(bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
-	ecmd.transceiver = XCVR_INTERNAL;
-	ecmd.phy_address = bdp->phy_addr;
-
-	if (netif_carrier_ok(bdp->device)) {
-		ecmd.speed = bdp->cur_line_speed;
-		ecmd.duplex =
-			(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
-	}
-	else {
-		ecmd.speed = -1;
-		ecmd.duplex = -1;
-	}
-
-	ecmd.advertising = ADVERTISED_TP;
-
-	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
-		ecmd.autoneg = AUTONEG_ENABLE;
-		ecmd.advertising |= ADVERTISED_Autoneg;
-	} else {
-		ecmd.autoneg = AUTONEG_DISABLE;
-	}
-
-	if (bdp->speed_duplex_caps & SUPPORTED_MII) {
-		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert);
-
-		if (advert & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (advert & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (advert & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (advert & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-	} else {
-		ecmd.autoneg = AUTONEG_DISABLE;
-		ecmd.advertising &= ~ADVERTISED_Autoneg;
-	}
-
-	if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int
-e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	int e100_new_speed_duplex;
-	int ethtool_new_speed_duplex;
-	struct ethtool_cmd ecmd;
-
-	bdp = dev->priv;
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
-		return -EFAULT;
-	}
-
-	if ((ecmd.autoneg == AUTONEG_ENABLE)
-	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
-		bdp->params.e100_speed_duplex = E100_AUTONEG;
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-			e100_hw_init(bdp);
-			e100_open(dev);
-		}
-	} else {
-		if (ecmd.speed == SPEED_10) {
-			if (ecmd.duplex == DUPLEX_HALF) {
-				e100_new_speed_duplex =
-					E100_SPEED_10_HALF;
-				ethtool_new_speed_duplex =
-					SUPPORTED_10baseT_Half;
-			} else { 
-				e100_new_speed_duplex =
-					E100_SPEED_10_FULL;
-				ethtool_new_speed_duplex =
-					SUPPORTED_10baseT_Full;
-			} 
-		} else { 
-			if (ecmd.duplex == DUPLEX_HALF) {
-				e100_new_speed_duplex =
-					E100_SPEED_100_HALF;
-				ethtool_new_speed_duplex =
-					SUPPORTED_100baseT_Half;
-			} else { 
-				e100_new_speed_duplex =
-					E100_SPEED_100_FULL;
-				ethtool_new_speed_duplex =
-					SUPPORTED_100baseT_Full;
-			} 
-		}
-
-		if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
-			bdp->params.e100_speed_duplex =
-				e100_new_speed_duplex;
-			if (netif_running(dev)) {
-				spin_lock_bh(&dev->xmit_lock);
-				e100_close(dev);
-				spin_unlock_bh(&dev->xmit_lock);
-				e100_hw_init(bdp);
-				e100_open(dev);
-			}
-		} else {
-			return -EOPNOTSUPP;
-		} 
-	}
-
-	return 0;
-}
-
-static int
-e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_value info;
-
-	memset((void *) &info, 0, sizeof (info));
-
-	bdp = dev->priv;
-	info.cmd = ETHTOOL_GLINK;
-
-	/* Consider both PHY link and netif_running */
-	info.data = e100_update_link_state(bdp);
-
-	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int
-e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
-{
-	struct ethtool_test *info;
-	int rc = -EFAULT;
-
-	info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64),
-		       GFP_ATOMIC);
-
-	if (!info)
-		return -ENOMEM;
-
-	memset((void *) info, 0, sizeof(*info) +
-				 max_test_res * sizeof(u64));
-
-	if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
-		goto exit;
-
-	info->flags = e100_run_diag(dev, info->data, info->flags);
-
-	if (!copy_to_user(ifr->ifr_data, info,
-			 sizeof(*info) + max_test_res * sizeof(u64)))
-		rc = 0;
-exit:
-	kfree(info);
-	return rc;
-}
-
-static int
-e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	u32 regs_buff[E100_REGS_LEN];
-	struct ethtool_regs regs = {ETHTOOL_GREGS};
-	void *addr = ifr->ifr_data;
-	u16 mdi_reg;
-
-	bdp = dev->priv;
-
-	if(copy_from_user(&regs, addr, sizeof(regs)))
-		return -EFAULT;
-
-	regs.version = (1 << 24) | bdp->rev_id;
-	regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
-		readb(&(bdp->scb->scb_cmd_low)) << 16 |
-		readw(&(bdp->scb->scb_status));
-	e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg);
-	regs_buff[1] = mdi_reg;
-
-	if(copy_to_user(addr, &regs, sizeof(regs)))
-		return -EFAULT;
-
-	addr += offsetof(struct ethtool_regs, data);
-	if(copy_to_user(addr, regs_buff, regs.len))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int
-e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-
-	bdp = dev->priv;
-
-	if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
-	    (bdp->params.e100_speed_duplex == E100_AUTONEG)) {
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-			e100_hw_init(bdp);
-			e100_open(dev);
-		}
-	} else {
-		return -EFAULT;
-	}
-	return 0;
-}
-
-static int
-e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_drvinfo info;
-
-	memset((void *) &info, 0, sizeof (info));
-
-	bdp = dev->priv;
-
-	strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
-	strncpy(info.version, e100_driver_version, sizeof (info.version) - 1);
-	strncpy(info.fw_version, "N/A",
-		sizeof (info.fw_version) - 1);
-	strncpy(info.bus_info, pci_name(bdp->pdev),
-		sizeof (info.bus_info) - 1);
-	info.n_stats = E100_STATS_LEN;
-	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
-	info.eedump_len = (bdp->eeprom_size << 1);	
-	info.testinfo_len = max_test_res;
-	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int
-e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_eeprom ecmd;
-	u16 eeprom_data[256];
-	u16 *usr_eeprom_ptr;
-	u16 first_word, last_word;
-	int i, max_len;
-	void *ptr;
-	u8 *eeprom_data_bytes = (u8 *)eeprom_data;
-
-	bdp = dev->priv;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
-
-	usr_eeprom_ptr =
-		(u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
-
-        max_len = bdp->eeprom_size * 2;
-        
-        if (ecmd.offset > ecmd.offset + ecmd.len)
-        	return -EINVAL;
-        	
-	if ((ecmd.offset + ecmd.len) > max_len)
-		ecmd.len = (max_len - ecmd.offset);
-
-	first_word = ecmd.offset >> 1;
-	last_word = (ecmd.offset + ecmd.len - 1) >> 1;
-		
-	if (first_word >= bdp->eeprom_size)
-		return -EFAULT;
-
-	if (ecmd.cmd == ETHTOOL_GEEPROM) {
-        	for(i = 0; i <= (last_word - first_word); i++)
-			eeprom_data[i] = e100_eeprom_read(bdp, first_word + i);
-
-		ecmd.magic = E100_EEPROM_MAGIC;
-
-		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-			return -EFAULT;
-
-		if(ecmd.offset & 1)
-			eeprom_data_bytes++;
-		if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len))
-			return -EFAULT;
-	} else {
-		if (ecmd.magic != E100_EEPROM_MAGIC)
-			return -EFAULT;
-
-		ptr = (void *)eeprom_data;
-        	if(ecmd.offset & 1) {
-                	/* need modification of first changed EEPROM word */
-                	/* only the second byte of the word is being modified */
-			eeprom_data[0] = e100_eeprom_read(bdp, first_word);
-                	ptr++;
-        	}
-        	if((ecmd.offset + ecmd.len) & 1) {
-	                /* need modification of last changed EEPROM word */
-	                /* only the first byte of the word is being modified */
-			eeprom_data[last_word - first_word] = 
-				e100_eeprom_read(bdp, last_word);
-		}
-        	if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len))
-	                return -EFAULT;
-
-		e100_eeprom_write_block(bdp, first_word, eeprom_data,
-					last_word - first_word + 1);
-
-		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
-#define E100_BLINK_INTERVAL	(HZ/4)
-/**
- * e100_led_control
- * @bdp: atapter's private data struct
- * @led_mdi_op: led operation
- *
- * Software control over adapter's led. The possible operations are:
- * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE.
- */
-static void
-e100_led_control(struct e100_private *bdp, u16 led_mdi_op)
-{
-	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
-		       bdp->phy_addr, led_mdi_op);
-
-}
-/**
- * e100_led_blink_callback
- * @data: pointer to atapter's private data struct
- *
- * Blink timer callback function. Toggles ON/OFF led status bit and calls
- * led hardware access function. 
- */
-static void
-e100_led_blink_callback(unsigned long data)
-{
-	struct e100_private *bdp = (struct e100_private *) data;
-
-	if(bdp->flags & LED_IS_ON) {
-		bdp->flags &= ~LED_IS_ON;
-		e100_led_control(bdp, PHY_82555_LED_OFF);
-	} else {
-		bdp->flags |= LED_IS_ON;
-		if (bdp->rev_id >= D101MA_REV_ID)
-			e100_led_control(bdp, PHY_82555_LED_ON_559);
-		else
-			e100_led_control(bdp, PHY_82555_LED_ON_PRE_559);
-	}
-
-	mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL);
-}
-/**
- * e100_ethtool_led_blink
- * @dev: pointer to atapter's net_device struct
- * @ifr: pointer to ioctl request structure
- *
- * Blink led ioctl handler. Initialtes blink timer and sleeps until
- * blink period expires. Than it kills timer and returns. The led control
- * is returned back to hardware when blink timer is killed.
- */
-static int
-e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_value ecmd;
-
-	bdp = dev->priv;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
-
-	if(!bdp->blink_timer.function) {
-		init_timer(&bdp->blink_timer);
-		bdp->blink_timer.function = e100_led_blink_callback;
-		bdp->blink_timer.data = (unsigned long) bdp;
-	}
-
-	mod_timer(&bdp->blink_timer, jiffies);
-
-	set_current_state(TASK_INTERRUPTIBLE);
-
-	if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
-		ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
-
-	schedule_timeout(ecmd.data * HZ);
-
-	del_timer_sync(&bdp->blink_timer);
-
-	e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL);
-
-	return 0;
-}
-
-static inline int
-e100_10BaseT_adapter(struct e100_private *bdp)
-{
-	return ((bdp->pdev->device == 0x1229) &&
-		(bdp->pdev->subsystem_vendor == 0x8086) &&
-		(bdp->pdev->subsystem_device == 0x0003));
-}
-
-static void
-e100_get_speed_duplex_caps(struct e100_private *bdp)
-{
-	u16 status;
-
-	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
-
-	bdp->speed_duplex_caps = 0;
-
-	bdp->speed_duplex_caps |=
-		(status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0;
-
-	bdp->speed_duplex_caps |=
-		(status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0;
-
-	bdp->speed_duplex_caps |=
-		(status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0;
-
-	bdp->speed_duplex_caps |=
-		(status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0;
-
-	bdp->speed_duplex_caps |=
-		(status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0;
-
-	if (IS_NC3133(bdp))
-		bdp->speed_duplex_caps =
-			(SUPPORTED_FIBRE | SUPPORTED_100baseT_Full);
-	else
-		bdp->speed_duplex_caps |= SUPPORTED_TP;
-
-	if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) {
-		bdp->speed_duplex_caps =
-			(SUPPORTED_10baseT_Half | SUPPORTED_TP);
-	} else {
-		bdp->speed_duplex_caps |= SUPPORTED_MII;
-	}
-
-}
-
-#ifdef CONFIG_PM
-static unsigned char
-e100_setup_filter(struct e100_private *bdp)
-{
-	cb_header_t *ntcb_hdr;
-	unsigned char res = false;
-	nxmit_cb_entry_t *cmd;
-
-	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
-		goto exit;
-	}
-
-	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
-	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER);
-
-	/* Set EL and FIX bit */
-	(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] =
-		__constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX);
-
-	if (bdp->wolopts & WAKE_UCAST) {
-		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
-			__constant_cpu_to_le32(CB_FILTER_IA_MATCH);
-	}
-
-	if (bdp->wolopts & WAKE_ARP) {
-		/* Setup ARP bit and lower IP parts */
-		/* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */
-		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
-			cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes);
-	}
-
-	res = e100_exec_non_cu_cmd(bdp, cmd);
-	if (!res)
-		printk(KERN_WARNING "e100: %s: Filter setup failed\n",
-		       bdp->device->name);
-
-exit:
-	return res;
-
-}
-
-static void
-e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp)
-{
-	e100_config_wol(bdp);
-
-	if (e100_config(bdp)) {
-		if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP))
-			if (!e100_setup_filter(bdp))
-				printk(KERN_ERR
-				       "e100: WOL options failed\n");
-	} else {
-		printk(KERN_ERR "e100: config WOL failed\n");
-	}
-}
-#endif
-
-static u16
-e100_get_ip_lbytes(struct net_device *dev)
-{
-	struct in_ifaddr *ifa;
-	struct in_device *in_dev;
-	u32 res = 0;
-
-	in_dev = (struct in_device *) dev->ip_ptr;
-	/* Check if any in_device bound to interface */
-	if (in_dev) {
-		/* Check if any IP address is bound to interface */
-		if ((ifa = in_dev->ifa_list) != NULL) {
-			res = __constant_ntohl(ifa->ifa_address);
-			res = __constant_htons(res & 0x0000ffff);
-		}
-	}
-	return res;
-}
-
-static int
-e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
-{
-	struct e100_private *bdp;
-	struct ethtool_wolinfo wolinfo;
-	int res = 0;
-
-	bdp = dev->priv;
-
-	if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) {
-		return -EFAULT;
-	}
-
-	switch (wolinfo.cmd) {
-	case ETHTOOL_GWOL:
-		wolinfo.supported = bdp->wolsupported;
-		wolinfo.wolopts = bdp->wolopts;
-		if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
-			res = -EFAULT;
-		break;
-	case ETHTOOL_SWOL:
-		/* If ALL requests are supported or request is DISABLE wol */
-		if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
-		    || (wolinfo.wolopts == 0)) {
-			bdp->wolopts = wolinfo.wolopts;
-		} else {
-			res = -EOPNOTSUPP;
-		}
-		if (wolinfo.wolopts & WAKE_ARP)
-			bdp->ip_lbytes = e100_get_ip_lbytes(dev);
-		break;
-	default:
-		break;
-	}
-	return res;
-}
-
-static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
-{
-	struct ethtool_gstrings info;
-	char *strings = NULL;
-	char *usr_strings;
-	int i;
-
-	memset((void *) &info, 0, sizeof(info));
-
-	usr_strings = (u8 *) (ifr->ifr_data + 
-			      offsetof(struct ethtool_gstrings, data));
-
-	if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
-		return -EFAULT;
-
-	switch (info.string_set) {
-	case ETH_SS_TEST: {
-		int ret = 0;
-		if (info.len > max_test_res)
-			info.len = max_test_res;
-		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
-		if (!strings)
-			return -ENOMEM;
-		memset(strings, 0, info.len * ETH_GSTRING_LEN);
-
-		for (i = 0; i < info.len; i++) {
-			sprintf(strings + i * ETH_GSTRING_LEN, "%s",
-				test_strings[i]);
-		}
-		if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-			ret = -EFAULT;
-		if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
-			ret = -EFAULT;
-		kfree(strings);
-		return ret;
-	}
-	case ETH_SS_STATS: {
-		char *strings = NULL;
-		void *addr = ifr->ifr_data;
-		info.len = E100_STATS_LEN;
-		strings = *e100_gstrings_stats;
-		if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
-			return -EFAULT;
-		addr += offsetof(struct ethtool_gstrings, data);
-		if(copy_to_user(addr, strings,
-		   info.len * ETH_GSTRING_LEN))
-			return -EFAULT;
-		return 0;
-	}
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static int
-e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct e100_private *bdp;
-	struct mii_ioctl_data *data_ptr =
-		(struct mii_ioctl_data *) &(ifr->ifr_data);
-
-	bdp = dev->priv;
-
-	switch (cmd) {
-	case SIOCGMIIPHY:
-		data_ptr->phy_id = bdp->phy_addr & 0x1f;
-		break;
-
-	case SIOCGMIIREG:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
-			      &(data_ptr->val_out));
-		break;
-
-	case SIOCSMIIREG:
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		/* If reg = 0 && change speed/duplex */
-		if (data_ptr->reg_num == 0 && 
-			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
-			|| data_ptr->val_in == (BMCR_RESET) /* reset cmd */ 
-			|| data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) 
-			|| data_ptr->val_in == 0)) {
-				if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART)
-					|| data_ptr->val_in == (BMCR_RESET))
-					bdp->params.e100_speed_duplex = E100_AUTONEG;
-				else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX))
-					bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
-				else if (data_ptr->val_in == (BMCR_SPEED100))
-					bdp->params.e100_speed_duplex = E100_SPEED_100_HALF;
-				else if (data_ptr->val_in == (BMCR_FULLDPLX))
-					bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
-				else
-					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
-				if (netif_running(dev)) {
-					spin_lock_bh(&dev->xmit_lock);
-					e100_close(dev);
-					spin_unlock_bh(&dev->xmit_lock);
-					e100_hw_init(bdp);
-					e100_open(dev);
-				}
-		}
-		else 
-			/* Only allows changing speed/duplex */
-			return -EINVAL;
-		
-		break;
-
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
-}
-
-nxmit_cb_entry_t *
-e100_alloc_non_tx_cmd(struct e100_private *bdp)
-{
-	nxmit_cb_entry_t *non_tx_cmd_elem;
-
-	if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *)
-	      kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) {
-		return NULL;
-	}
-	non_tx_cmd_elem->non_tx_cmd =
-		pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t),
-				     &(non_tx_cmd_elem->dma_addr));
-	if (non_tx_cmd_elem->non_tx_cmd == NULL) {
-		kfree(non_tx_cmd_elem);
-		return NULL;
-	}
-	return non_tx_cmd_elem;
-}
-
-void
-e100_free_non_tx_cmd(struct e100_private *bdp,
-		     nxmit_cb_entry_t *non_tx_cmd_elem)
-{
-	pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t),
-			    non_tx_cmd_elem->non_tx_cmd,
-			    non_tx_cmd_elem->dma_addr);
-	kfree(non_tx_cmd_elem);
-}
-
-static void
-e100_free_nontx_list(struct e100_private *bdp)
-{
-	nxmit_cb_entry_t *command;
-	int i;
-
-	while (!list_empty(&bdp->non_tx_cmd_list)) {
-		command = list_entry(bdp->non_tx_cmd_list.next,
-				     nxmit_cb_entry_t, list_elem);
-		list_del(&(command->list_elem));
-		e100_free_non_tx_cmd(bdp, command);
-	}
-
-	for (i = 0; i < CB_MAX_NONTX_CMD; i++) {
-		bdp->same_cmd_entry[i] = NULL;
-	}
-}
-
-static unsigned char
-e100_delayed_exec_non_cu_cmd(struct e100_private *bdp,
-			     nxmit_cb_entry_t *command)
-{
-	nxmit_cb_entry_t *same_command;
-	cb_header_t *ntcb_hdr;
-	u16 cmd;
-
-	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;
-
-	cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd);
-
-	spin_lock_bh(&(bdp->bd_non_tx_lock));
-
-	same_command = bdp->same_cmd_entry[cmd];
-
-	if (same_command != NULL) {
-		memcpy((void *) (same_command->non_tx_cmd),
-		       (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t));
-		e100_free_non_tx_cmd(bdp, command);
-	} else {
-		list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list));
-		bdp->same_cmd_entry[cmd] = command;
-	}
-
-	if (bdp->non_tx_command_state == E100_NON_TX_IDLE) {
-		bdp->non_tx_command_state = E100_WAIT_TX_FINISH;
-		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
-	}
-
-	spin_unlock_bh(&(bdp->bd_non_tx_lock));
-	return true;
-}
-
-static void
-e100_non_tx_background(unsigned long ptr)
-{
-	struct e100_private *bdp = (struct e100_private *) ptr;
-	nxmit_cb_entry_t *active_command;
-	int restart = true;
-	cb_header_t *non_tx_cmd;
-	u8 sub_cmd;
-
-	spin_lock_bh(&(bdp->bd_non_tx_lock));
-
-	switch (bdp->non_tx_command_state) {
-	case E100_WAIT_TX_FINISH:
-		if (bdp->last_tcb != NULL) {
-			rmb();
-			if ((bdp->last_tcb->tcb_hdr.cb_status &
-			     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
-				goto exit;
-		}
-		if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) ==
-		    SCB_CUS_ACTIVE) {
-			goto exit;
-		}
-		break;
-
-	case E100_WAIT_NON_TX_FINISH:
-		active_command = list_entry(bdp->non_tx_cmd_list.next,
-					    nxmit_cb_entry_t, list_elem);
-		rmb();
-
-		if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status
-		      & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
-		    && time_before(jiffies, active_command->expiration_time)) {
-			goto exit;
-		} else {
-			non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd;
-			sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd);
-#ifdef E100_CU_DEBUG			
-			if (!(non_tx_cmd->cb_status 
-			    & __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
-				printk(KERN_ERR "e100: %s: Queued "
-					"command (%x) timeout\n", 
-					bdp->device->name, sub_cmd);
-#endif			
-			list_del(&(active_command->list_elem));
-			e100_free_non_tx_cmd(bdp, active_command);
-		}
-		break;
-
-	default:
-		break;
-	}			//switch
-
-	if (list_empty(&bdp->non_tx_cmd_list)) {
-		bdp->non_tx_command_state = E100_NON_TX_IDLE;
-		spin_lock_irq(&(bdp->bd_lock));
-		bdp->next_cu_cmd = START_WAIT;
-		spin_unlock_irq(&(bdp->bd_lock));
-		restart = false;
-		goto exit;
-	} else {
-		u16 cmd_type;
-
-		bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
-		active_command = list_entry(bdp->non_tx_cmd_list.next,
-					    nxmit_cb_entry_t, list_elem);
-		sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd;
-		spin_lock_irq(&(bdp->bd_lock));
-		e100_wait_exec_cmplx(bdp, active_command->dma_addr,
-				     SCB_CUC_START, sub_cmd);
-		spin_unlock_irq(&(bdp->bd_lock));
-		active_command->expiration_time = jiffies + HZ;
-		cmd_type = CB_CMD_MASK &
-			le16_to_cpu(((cb_header_t *)
-				     (active_command->non_tx_cmd))->cb_cmd);
-		bdp->same_cmd_entry[cmd_type] = NULL;
-	}
-
-exit:
-	if (restart) {
-		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
-	} else {
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
-	}
-	spin_unlock_bh(&(bdp->bd_non_tx_lock));
-}
-
-static void
-e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
-{
-	struct e100_private *bdp = netdev->priv;
-
-	e100_disable_clear_intr(bdp);
-	bdp->vlgrp = grp;
-
-	if(grp) {
-		/* enable VLAN tag insert/strip */
-		e100_config_vlan_drop(bdp, true);
-
-	} else {
-		/* disable VLAN tag insert/strip */
-		e100_config_vlan_drop(bdp, false);
-	}
-
-	e100_config(bdp);
-	e100_set_intr_mask(bdp);
-}
-
-static void
-e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
-{
-	/* We don't do Vlan filtering */
-	return;
-}
-
-static void
-e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
-{
-	struct e100_private *bdp = netdev->priv;
-
-	if(bdp->vlgrp)
-		bdp->vlgrp->vlan_devices[vid] = NULL;
-	/* We don't do Vlan filtering */
-	return;
-}
-
-#ifdef CONFIG_PM
-static int
-e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
-{
-        struct pci_dev *pdev = NULL;
-	
-        switch(event) {
-        case SYS_DOWN:
-        case SYS_HALT:
-        case SYS_POWER_OFF:
-		while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-                        if(pci_dev_driver(pdev) == &e100_driver) {
-				/* If net_device struct is allocated? */
-                                if (pci_get_drvdata(pdev))
-					e100_suspend(pdev, 3);
-
-			}
-		}
-        }
-        return NOTIFY_DONE;
-}
-
-static int
-e100_suspend(struct pci_dev *pcid, u32 state)
-{
-	struct net_device *netdev = pci_get_drvdata(pcid);
-	struct e100_private *bdp = netdev->priv;
-
-	e100_isolate_driver(bdp);
-	pci_save_state(pcid, bdp->pci_state);
-
-	/* Enable or disable WoL */
-	e100_do_wol(pcid, bdp);
-	
-	/* If wol is enabled */
-	if (bdp->wolopts || e100_asf_enabled(bdp)) {
-		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
-		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
-	} else {
-		/* Disable bus mastering */
-		pci_disable_device(pcid);
-		pci_set_power_state(pcid, state);
-	}
-	return 0;
-}
-
-static int
-e100_resume(struct pci_dev *pcid)
-{
-	struct net_device *netdev = pci_get_drvdata(pcid);
-	struct e100_private *bdp = netdev->priv;
-
-	pci_set_power_state(pcid, 0);
-	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
-	pci_restore_state(pcid, bdp->pci_state);
-
-	/* Also do device full reset because device was in D3 state */
-	e100_deisolate_driver(bdp, true);
-
-	return 0;
-}
-
-/**
- * e100_asf_enabled - checks if ASF is configured on the current adaper
- *                    by reading registers 0xD and 0x90 in the EEPROM 
- * @bdp: atapter's private data struct
- *
- * Returns: true if ASF is enabled
- */
-static unsigned char
-e100_asf_enabled(struct e100_private *bdp)
-{
-	u16 asf_reg;
-	u16 smbus_addr_reg;
-	if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) {
-		asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF);
-		if ((asf_reg & EEPROM_FLAG_ASF)
-		    && !(asf_reg & EEPROM_FLAG_GCL)) {
-			smbus_addr_reg = 
-				e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR);
-			if ((smbus_addr_reg & 0xFF) != 0xFE) 
-				return true;
-		}
-	}
-	return false;
-}
-#endif /* CONFIG_PM */
-
-#ifdef E100_CU_DEBUG
-unsigned char
-e100_cu_unknown_state(struct e100_private *bdp)
-{
-	u8 scb_cmd_low;
-	u16 scb_status;
-	scb_cmd_low = bdp->scb->scb_cmd_low;
-	scb_status = le16_to_cpu(bdp->scb->scb_status);
-	/* If CU is active and executing unknown cmd */
-	if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN)
-		return true;
-	else
-		return false;
-}
-#endif
-
--- diff/drivers/net/e100/e100_phy.c	2004-01-19 10:22:57.000000000 +0000
+++ source/drivers/net/e100/e100_phy.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1163 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#include "e100_phy.h"
-
-void e100_handle_zlock(struct e100_private *bdp);
-
-/* 
- * Procedure:	e100_mdi_write
- *
- * Description: This routine will write a value to the specified MII register
- *		of an external MDI compliant device (e.g. PHY 100).  The
- *		command will execute in polled mode.
- *
- * Arguments:
- *	bdp - Ptr to this card's e100_bdconfig structure
- *	reg_addr - The MII register that we are writing to
- *	phy_addr - The MDI address of the Phy component.
- *	data - The value that we are writing to the MII register.
- *
- * Returns:
- *	NOTHING
- */
-int
-e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
-{
-	int e100_retry;
-	u32 temp_val;
-	unsigned int mdi_cntrl;
-
-	spin_lock_bh(&bdp->mdi_access_lock);
-	temp_val = (((u32) data) | (reg_addr << 16) |
-		    (phy_addr << 21) | (MDI_WRITE << 26));
-	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
-	readw(&bdp->scb->scb_status);
-
-	/* wait 20usec before checking status */
-	udelay(20);
-
-	/* poll for the mdi write to complete */
-	e100_retry = E100_CMD_WAIT;
-	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
-
-		udelay(20);
-		e100_retry--;
-	}
-	spin_unlock_bh(&bdp->mdi_access_lock);
-	if (mdi_cntrl & MDI_PHY_READY) 
-		return 0;
-	else {
-		printk(KERN_ERR "e100: MDI write timeout\n");
-		return 1;
-	}
-}
-
-/* 
- * Procedure:	e100_mdi_read
- *
- * Description: This routine will read a value from the specified MII register
- *		of an external MDI compliant device (e.g. PHY 100), and return
- *		it to the calling routine.  The command will execute in polled
- *		mode.
- *
- * Arguments:
- *	bdp - Ptr to this card's e100_bdconfig structure
- *	reg_addr - The MII register that we are reading from
- *	phy_addr - The MDI address of the Phy component.
- *
- * Results:
- *	data - The value that we read from the MII register.
- *
- * Returns:
- *	NOTHING
- */
-int
-e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
-{
-	int e100_retry;
-	u32 temp_val;
-	unsigned int mdi_cntrl;
-
-	spin_lock_bh(&bdp->mdi_access_lock);
-	/* Issue the read command to the MDI control register. */
-	temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));
-	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
-	readw(&bdp->scb->scb_status);
-
-	/* wait 20usec before checking status */
-	udelay(20);
-
-	/* poll for the mdi read to complete */
-	e100_retry = E100_CMD_WAIT;
-	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {
-
-		udelay(20);
-		e100_retry--;
-	}
-
-	spin_unlock_bh(&bdp->mdi_access_lock);
-	if (mdi_cntrl & MDI_PHY_READY) {
-		/* return the lower word */
-		*data = (u16) mdi_cntrl;
-		return 0;
-	}
-	else {
-		printk(KERN_ERR "e100: MDI read timeout\n");
-		return 1;
-	}
-}
-
-static unsigned char
-e100_phy_valid(struct e100_private *bdp, unsigned int phy_address)
-{
-	u16 ctrl_reg, stat_reg;
-
-	/* Read the MDI control register */
-	e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg);
-
-	/* Read the status register twice, bacause of sticky bits */
-	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
-	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
-
-	if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0)))
-		return false;
-
-	return true;
-}
-
-static void
-e100_phy_address_detect(struct e100_private *bdp)
-{
-	unsigned int addr;
-	unsigned char valid_phy_found = false;
-
-	if (IS_NC3133(bdp)) {
-		bdp->phy_addr = 0;
-		return;
-	}
-
-	if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) {
-		bdp->phy_addr = PHY_DEFAULT_ADDRESS;
-		valid_phy_found = true;
-
-	} else {
-		for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) {
-			if (e100_phy_valid(bdp, addr)) {
-				bdp->phy_addr = addr;
-				valid_phy_found = true;
-				break;
-			}
-		}
-	}
-
-	if (!valid_phy_found) {
-		bdp->phy_addr = PHY_ADDRESS_503;
-	}
-}
-
-static void
-e100_phy_id_detect(struct e100_private *bdp)
-{
-	u16 low_id_reg, high_id_reg;
-
-	if (bdp->phy_addr == PHY_ADDRESS_503) {
-		bdp->PhyId = PHY_503;
-		return;
-	}
-	if (!(bdp->flags & IS_ICH)) {
-		if (bdp->rev_id >= D102_REV_ID) {
-			bdp->PhyId = PHY_82562ET;
-			return;
-		}
-	}
-
-	/* Read phy id from the MII register */
-	e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg);
-	e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg);
-
-	bdp->PhyId = ((unsigned int) low_id_reg |
-		      ((unsigned int) high_id_reg << 16));
-}
-
-static void
-e100_phy_isolate(struct e100_private *bdp)
-{
-	unsigned int phy_address;
-	u16 ctrl_reg;
-
-	/* Go over all phy addresses. Deisolate the selected one, and isolate
-	 * all the rest */
-	for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) {
-		if (phy_address != bdp->phy_addr) {
-			e100_mdi_write(bdp, MII_BMCR, phy_address,
-				       BMCR_ISOLATE);
-
-		} else {
-			e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg);
-			ctrl_reg &= ~BMCR_ISOLATE;
-			e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
-		}
-
-		udelay(100);
-	}
-}
-
-static unsigned char
-e100_phy_specific_setup(struct e100_private *bdp)
-{
-	u16 misc_reg;
-
-	if (bdp->phy_addr == PHY_ADDRESS_503) {
-		switch (bdp->params.e100_speed_duplex) {
-		case E100_AUTONEG:
-			/* The adapter can't autoneg. so set to 10/HALF */
-			printk(KERN_INFO
-			       "e100: 503 serial component detected which "
-			       "cannot autonegotiate\n");
-			printk(KERN_INFO
-			       "e100: speed/duplex forced to "
-			       "10Mbps / Half duplex\n");
-			bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
-			break;
-
-		case E100_SPEED_100_HALF:
-		case E100_SPEED_100_FULL:
-			printk(KERN_ERR
-			       "e100: 503 serial component detected "
-			       "which does not support 100Mbps\n");
-			printk(KERN_ERR
-			       "e100: Change the forced speed/duplex "
-			       "to a supported setting\n");
-			return false;
-		}
-
-		return true;
-	}
-
-	if (IS_NC3133(bdp)) {
-		u16 int_reg;
-
-		/* enable 100BASE fiber interface */
-		e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr,
-			       MDI_NC3133_100FX_ENABLE);
-
-		if ((bdp->params.e100_speed_duplex != E100_AUTONEG) &&
-		    (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) {
-			/* just inform user about 100 full */
-			printk(KERN_ERR "e100: NC3133 NIC can only run "
-			       "at 100Mbps full duplex\n");
-		}
-
-		bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
-
-		/* enable interrupts */
-		e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG,
-			      bdp->phy_addr, &int_reg);
-		int_reg |= MDI_NC3133_INT_ENABLE;
-		e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG,
-			       bdp->phy_addr, int_reg);
-	}
-
-	/* Handle the National TX */
-	if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) {
-		e100_mdi_read(bdp, NSC_CONG_CONTROL_REG,
-			      bdp->phy_addr, &misc_reg);
-
-		misc_reg |= NSC_TX_CONG_TXREADY;
-
-		/* disable the congestion control bit in the National Phy */
-		misc_reg &= ~NSC_TX_CONG_ENABLE;
-
-		e100_mdi_write(bdp, NSC_CONG_CONTROL_REG,
-			       bdp->phy_addr, misc_reg);
-	}
-
-	return true;
-}
-
-/* 
- * Procedure:	e100_phy_fix_squelch
- *
- * Description:
- *	Help find link on certain rare scenarios.
- *	NOTE: This routine must be called once per watchdog,
- *	      and *after* setting the current link state.
- *
- * Arguments:
- *	bdp - Ptr to this card's e100_bdconfig structure
- *
- * Returns:
- *	NOTHING
- */
-static void
-e100_phy_fix_squelch(struct e100_private *bdp)
-{
-	if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED))
-		return;
-
-	if (netif_carrier_ok(bdp->device)) {
-		switch (bdp->PhyState) {
-		case 0:
-			break;
-		case 1:
-			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
-				       bdp->phy_addr, 0x0000);
-			break;
-		case 2:
-			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-				       bdp->phy_addr, 0x3000);
-			break;
-		}
-		bdp->PhyState = 0;
-		bdp->PhyDelay = 0;
-
-	} else if (!bdp->PhyDelay--) {
-		switch (bdp->PhyState) {
-		case 0:
-			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
-				       bdp->phy_addr, EXTENDED_SQUELCH_BIT);
-			bdp->PhyState = 1;
-			break;
-		case 1:
-			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
-				       bdp->phy_addr, 0x0000);
-			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-				       bdp->phy_addr, 0x2010);
-			bdp->PhyState = 2;
-			break;
-		case 2:
-			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-				       bdp->phy_addr, 0x3000);
-			bdp->PhyState = 0;
-			break;
-		}
-
-		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-			       BMCR_ANENABLE | BMCR_ANRESTART);
-		bdp->PhyDelay = 3;
-	}
-}
-
-/* 
- * Procedure:	e100_fix_polarity
- *
- * Description:
- *	Fix for 82555 auto-polarity toggle problem. With a short cable 
- *	connecting an 82555 with an 840A link partner, if the medium is noisy,
- *	the 82555 sometime thinks that the polarity might be wrong and so 
- *	toggles polarity. This happens repeatedly and results in a high bit 
- *	error rate.
- *	NOTE: This happens only at 10 Mbps
- *
- * Arguments:
- *	bdp - Ptr to this card's e100_bdconfig structure
- *
- * Returns:
- *	NOTHING
- */
-static void
-e100_fix_polarity(struct e100_private *bdp)
-{
-	u16 status;
-	u16 errors;
-	u16 misc_reg;
-	int speed;
-
-	if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) &&
-	    (bdp->PhyId != PHY_82562EM))
-		return;
-
-	/* If the user wants auto-polarity disabled, do only that and nothing *
-	 * else. * e100_autopolarity == 0 means disable --- we do just the
-	 * disabling * e100_autopolarity == 1 means enable  --- we do nothing at
-	 * all * e100_autopolarity >= 2 means we do the workaround code. */
-	/* Change for 82558 enhancement */
-	switch (E100_AUTOPOLARITY) {
-	case 0:
-		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
-			      bdp->phy_addr, &misc_reg);
-		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
-			       (u16) (misc_reg | DISABLE_AUTO_POLARITY));
-		break;
-
-	case 1:
-		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
-			      bdp->phy_addr, &misc_reg);
-		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
-			       (u16) (misc_reg & ~DISABLE_AUTO_POLARITY));
-		break;
-
-	case 2:
-		/* we do this only if link is up */
-		if (!netif_carrier_ok(bdp->device)) {
-			break;
-		}
-
-		e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status);
-		speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10;
-
-		/* we need to do this only if speed is 10 */
-		if (speed != 10) {
-			break;
-		}
-
-		/* see if we have any end of frame errors */
-		e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
-			      bdp->phy_addr, &errors);
-
-		/* if non-zero, wait for 100 ms before reading again */
-		if (errors) {
-			udelay(200);
-			e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
-				      bdp->phy_addr, &errors);
-
-			/* if non-zero again, we disable polarity */
-			if (errors) {
-				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
-					      bdp->phy_addr, &misc_reg);
-				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
-					       bdp->phy_addr,
-					       (u16) (misc_reg |
-						      DISABLE_AUTO_POLARITY));
-			}
-		}
-
-		if (!errors) {
-			/* it is safe to read the polarity now */
-			e100_mdi_read(bdp, PHY_82555_CSR,
-				      bdp->phy_addr, &status);
-
-			/* if polarity is normal, disable polarity */
-			if (!(status & PHY_82555_POLARITY_BIT)) {
-				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
-					      bdp->phy_addr, &misc_reg);
-				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
-					       bdp->phy_addr,
-					       (u16) (misc_reg |
-						      DISABLE_AUTO_POLARITY));
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-}
-
-/* 
- * Procedure:	e100_find_speed_duplex
- *
- * Description: This routine will figure out what line speed and duplex mode
- *		the PHY is currently using.
- *
- * Arguments:
- *	bdp - Ptr to this card's e100_bdconfig structure
- *
- * Returns:
- *	NOTHING
- */
-static void
-e100_find_speed_duplex(struct e100_private *bdp)
-{
-	unsigned int PhyId;
-	u16 stat_reg, misc_reg;
-	u16 ad_reg, lp_ad_reg;
-
-	PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK;
-
-	/* First we should check to see if we have link */
-	/* If we don't have a link no reason to print a speed and duplex */
-	if (!e100_update_link_state(bdp)) {
-		bdp->cur_line_speed = 0;
-		bdp->cur_dplx_mode = 0;
-		return;
-	}
-
-	/* On the 82559 and later controllers, speed/duplex is part of the *
-	 * SCB. So, we save an mdi_read and get these from the SCB. * */
-	if (bdp->rev_id >= D101MA_REV_ID) {
-		/* Read speed */
-		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1)
-			bdp->cur_line_speed = 100;
-		else
-			bdp->cur_line_speed = 10;
-
-		/* Read duplex */
-		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2)
-			bdp->cur_dplx_mode = FULL_DUPLEX;
-		else
-			bdp->cur_dplx_mode = HALF_DUPLEX;
-
-		return;
-	}
-
-	/* If this is a Phy 100, then read bits 1 and 0 of extended register 0,
-	 * to get the current speed and duplex settings. */
-	if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) ||
-	    (PhyId == PHY_82555_TX)) {
-
-		/* Read Phy 100 extended register 0 */
-		e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg);
-
-		/* Get current speed setting */
-		if (misc_reg & PHY_100_ER0_SPEED_INDIC)
-			bdp->cur_line_speed = 100;
-		else
-			bdp->cur_line_speed = 10;
-
-		/* Get current duplex setting -- FDX enabled if bit is set */
-		if (misc_reg & PHY_100_ER0_FDX_INDIC)
-			bdp->cur_dplx_mode = FULL_DUPLEX;
-		else
-			bdp->cur_dplx_mode = HALF_DUPLEX;
-
-		return;
-	}
-
-	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
-	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg);
-
-	/* See if Auto-Negotiation was complete (bit 5, reg 1) */
-	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
-
-	/* If a True NWAY connection was made, then we can detect speed/dplx
-	 * by ANDing our adapter's advertised abilities with our link partner's
-	 * advertised ablilities, and then assuming that the highest common
-	 * denominator was chosed by NWAY. */
-	if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) {
-
-		/* Read our advertisement register */
-		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
-
-		/* Read our link partner's advertisement register */
-		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
-
-		/* AND the two advertisement registers together, and get rid
-		 * of any extraneous bits. */
-		ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY);
-
-		/* Get speed setting */
-		if (ad_reg &
-		    (ADVERTISE_100HALF | ADVERTISE_100FULL |
-		     ADVERTISE_100BASE4))
-
-			bdp->cur_line_speed = 100;
-		else
-			bdp->cur_line_speed = 10;
-
-		/* Get duplex setting -- use priority resolution algorithm */
-		if (ad_reg & ADVERTISE_100BASE4) {
-			bdp->cur_dplx_mode = HALF_DUPLEX;
-		} else if (ad_reg & ADVERTISE_100FULL) {
-			bdp->cur_dplx_mode = FULL_DUPLEX;
-		} else if (ad_reg & ADVERTISE_100HALF) {
-			bdp->cur_dplx_mode = HALF_DUPLEX;
-		} else if (ad_reg & ADVERTISE_10FULL) {
-			bdp->cur_dplx_mode = FULL_DUPLEX;
-		} else {
-			bdp->cur_dplx_mode = HALF_DUPLEX;
-		}
-
-		return;
-	}
-
-	/* If we are connected to a dumb (non-NWAY) repeater or hub, and the
-	 * line speed was determined automatically by parallel detection, then
-	 * we have no way of knowing exactly what speed the PHY is set to
-	 * unless that PHY has a propietary register which indicates speed in
-	 * this situation. The NSC TX PHY does have such a register. Also,
-	 * since NWAY didn't establish the connection, the duplex setting
-	 * should HALF duplex. */
-	bdp->cur_dplx_mode = HALF_DUPLEX;
-
-	if (PhyId == PHY_NSC_TX) {
-		/* Read register 25 to get the SPEED_10 bit */
-		e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg);
-
-		/* If bit 6 was set then we're at 10Mbps */
-		if (misc_reg & NSC_TX_SPD_INDC_SPEED)
-			bdp->cur_line_speed = 10;
-		else
-			bdp->cur_line_speed = 100;
-
-	} else {
-		/* If we don't know the line speed, default to 10Mbps */
-		bdp->cur_line_speed = 10;
-	}
-}
-
-/* 
- * Procedure: e100_force_speed_duplex
- *
- * Description: This routine forces line speed and duplex mode of the
- * adapter based on the values the user has set in e100.c.
- *
- * Arguments:  bdp - Pointer to the e100_private structure for the board
- *
- * Returns: void
- *
- */
-void
-e100_force_speed_duplex(struct e100_private *bdp)
-{
-	u16 control;
-	unsigned long expires;
-
-	bdp->flags |= DF_SPEED_FORCED;
-
-	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
-	control &= ~BMCR_ANENABLE;
-	control &= ~BMCR_LOOPBACK;
-
-	switch (bdp->params.e100_speed_duplex) {
-	case E100_SPEED_10_HALF:
-		control &= ~BMCR_SPEED100;
-		control &= ~BMCR_FULLDPLX;
-		bdp->cur_line_speed = 10;
-		bdp->cur_dplx_mode = HALF_DUPLEX;
-		break;
-
-	case E100_SPEED_10_FULL:
-		control &= ~BMCR_SPEED100;
-		control |= BMCR_FULLDPLX;
-		bdp->cur_line_speed = 10;
-		bdp->cur_dplx_mode = FULL_DUPLEX;
-		break;
-
-	case E100_SPEED_100_HALF:
-		control |= BMCR_SPEED100;
-		control &= ~BMCR_FULLDPLX;
-		bdp->cur_line_speed = 100;
-		bdp->cur_dplx_mode = HALF_DUPLEX;
-		break;
-
-	case E100_SPEED_100_FULL:
-		control |= BMCR_SPEED100;
-		control |= BMCR_FULLDPLX;
-		bdp->cur_line_speed = 100;
-		bdp->cur_dplx_mode = FULL_DUPLEX;
-		break;
-	}
-
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
-
-	/* loop must run at least once */
-	expires = jiffies + 2 * HZ;
-	do {
-		if (e100_update_link_state(bdp) || 
-		    time_after(jiffies, expires)) {
-			break;
-		} else {
-			yield();
-		}
-
-	} while (true);
-}
-
-void
-e100_force_speed_duplex_to_phy(struct e100_private *bdp)
-{
-	u16 control;
-
-	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
-	control &= ~BMCR_ANENABLE;
-	control &= ~BMCR_LOOPBACK;
-
-	switch (bdp->params.e100_speed_duplex) {
-	case E100_SPEED_10_HALF:
-		control &= ~BMCR_SPEED100;
-		control &= ~BMCR_FULLDPLX;
-		break;
-
-	case E100_SPEED_10_FULL:
-		control &= ~BMCR_SPEED100;
-		control |= BMCR_FULLDPLX;
-		break;
-
-	case E100_SPEED_100_HALF:
-		control |= BMCR_SPEED100;
-		control &= ~BMCR_FULLDPLX;
-		break;
-
-	case E100_SPEED_100_FULL:
-		control |= BMCR_SPEED100;
-		control |= BMCR_FULLDPLX;
-		break;
-	}
-
-	/* Send speed/duplex command to PHY layer. */
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
-}
-
-/* 
- * Procedure: e100_set_fc
- *
- * Description: Checks the link's capability for flow control.
- * 
- * Arguments:  bdp - Pointer to the e100_private structure for the board
- *		    
- * Returns: void
- *
- */
-static void
-e100_set_fc(struct e100_private *bdp)
-{
-	u16 ad_reg;
-	u16 lp_ad_reg;
-	u16 exp_reg;
-
-	/* no flow control for 82557, forced links or half duplex */
-	if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) ||
-	    (bdp->cur_dplx_mode == HALF_DUPLEX) ||
-	    !(bdp->flags & IS_BACHELOR)) {
-
-		bdp->flags &= ~DF_LINK_FC_CAP;
-		return;
-	}
-
-	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
-	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg);
-
-	if (exp_reg & EXPANSION_NWAY) {
-		/* Read our advertisement register */
-		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
-
-		/* Read our link partner's advertisement register */
-		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
-
-		ad_reg &= lp_ad_reg;	/* AND the 2 ad registers */
-
-		if (ad_reg & NWAY_AD_FC_SUPPORTED)
-			bdp->flags |= DF_LINK_FC_CAP;
-		else
-			/* If link partner is capable of autoneg, but  */
-			/* not capable of flow control, Received PAUSE */
-			/* frames are still honored, i.e.,             */
-		        /* transmitted frames would be paused */
-			/* by incoming PAUSE frames           */
-			bdp->flags |= DF_LINK_FC_TX_ONLY;
-
-	} else {
-		bdp->flags &= ~DF_LINK_FC_CAP;
-	}
-}
-
-/* 
- * Procedure: e100_phy_check
- * 
- * Arguments:  bdp - Pointer to the e100_private structure for the board
- *
- * Returns: true if link state was changed
- *	   false otherwise
- *
- */
-unsigned char
-e100_phy_check(struct e100_private *bdp)
-{
-	unsigned char old_link;
-	unsigned char changed = false;
-
-	old_link = netif_carrier_ok(bdp->device) ? 1 : 0;
-	e100_find_speed_duplex(bdp);
-
-	if (!old_link && netif_carrier_ok(bdp->device)) {
-		e100_set_fc(bdp);
-		changed = true;
-	}
-
-	if (old_link && !netif_carrier_ok(bdp->device)) {
-		/* reset the zero lock state */
-		bdp->zlock_state = ZLOCK_INITIAL;
-
-		// set auto lock for phy auto-negotiation on link up
-		if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX)
-			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-				       bdp->phy_addr, 0);
-		changed = true;
-	}
-
-	e100_phy_fix_squelch(bdp);
-	e100_handle_zlock(bdp);
-
-	return changed;
-}
-
-/* 
- * Procedure:	e100_auto_neg
- *
- * Description: This routine will start autonegotiation and wait
- *		     for it to complete
- *
- * Arguments:
- *	bdp		- pointer to this card's e100_bdconfig structure
- *	force_restart	- defines if autoneg should be restarted even if it
- *			has been completed before
- * Returns:
- *	NOTHING
- */
-static void
-e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
-{
-	u16 stat_reg;
-	unsigned long expires;
-
-	bdp->flags &= ~DF_SPEED_FORCED;
-
-	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
-	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
-
-	/* if we are capable of performing autoneg then we restart if needed */
-	if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) {
-
-		if ((!force_restart) &&
-		    (stat_reg & BMSR_ANEGCOMPLETE)) {
-			goto exit;
-		}
-
-		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-			       BMCR_ANENABLE | BMCR_ANRESTART);
-
-		/* wait for autoneg to complete (up to 3 seconds) */
-		expires = jiffies + HZ * 3;
-		do {
-			/* now re-read the value. Sticky so read twice */
-			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
-			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
-
-			if ((stat_reg & BMSR_ANEGCOMPLETE) ||
-			    time_after(jiffies, expires) ) {
-				goto exit;
-			} else {
-				yield();
-			}
-		} while (true);
-	}
-
-exit:
-	e100_find_speed_duplex(bdp);
-}
-
-void
-e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
-{
-	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
-        	if (bdp->rev_id >= D102_REV_ID) 
-			/* Enable MDI/MDI-X auto switching */
-                	e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		                       MDI_MDIX_AUTO_SWITCH_ENABLE);
-		e100_auto_neg(bdp, force_restart);
-
-	} else {
-        	if (bdp->rev_id >= D102_REV_ID) 
-			/* Disable MDI/MDI-X auto switching */
-                	e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		                       MDI_MDIX_RESET_ALL_MASK);
-		e100_force_speed_duplex(bdp);
-	}
-
-	e100_set_fc(bdp);
-}
-
-void
-e100_phy_autoneg(struct e100_private *bdp)
-{
-	u16 ctrl_reg;
-
-	ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
-
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
-
-	udelay(100);
-}
-
-void
-e100_phy_set_loopback(struct e100_private *bdp)
-{
-	u16 ctrl_reg;
-	ctrl_reg = BMCR_LOOPBACK;
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
-		udelay(100);
-}
-	
-void
-e100_phy_reset(struct e100_private *bdp)
-{
-	u16 ctrl_reg;
-	ctrl_reg = BMCR_RESET;
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
-	/* ieee 802.3 : The reset process shall be completed       */
-	/* within 0.5 seconds from the settting of PHY reset bit.  */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 2);
-}
-
-unsigned char
-e100_phy_init(struct e100_private *bdp)
-{
-	e100_phy_reset(bdp);
-	e100_phy_address_detect(bdp);
-	e100_phy_isolate(bdp);
-	e100_phy_id_detect(bdp);
-
-	if (!e100_phy_specific_setup(bdp))
-		return false;
-
-	bdp->PhyState = 0;
-	bdp->PhyDelay = 0;
-	bdp->zlock_state = ZLOCK_INITIAL;
-
-	e100_phy_set_speed_duplex(bdp, false);
-	e100_fix_polarity(bdp);
-
-	return true;
-}
-
-/* 
- * Procedure: e100_get_link_state
- * 
- * Description: This routine checks the link status of the adapter
- *
- * Arguments:  bdp - Pointer to the e100_private structure for the board
- *		    
- *
- * Returns: true - If a link is found
- *		false - If there is no link
- *
- */
-unsigned char
-e100_get_link_state(struct e100_private *bdp)
-{
-	unsigned char link = false;
-	u16 status;
-
-	/* Check link status */
-	/* If the controller is a 82559 or later one, link status is available
-	 * from the CSR. This avoids the mdi_read. */
-	if (bdp->rev_id >= D101MA_REV_ID) {
-		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) {
-			link = true;
-		} else {
-			link = false;
-		}
-
-	} else {
-		/* Read the status register twice because of sticky bits */
-		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
-		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
-
-		if (status & BMSR_LSTATUS) {
-			link = true;
-		} else {
-			link = false;
-		}
-	}
-
-	return link;
-}
-
-/* 
- * Procedure: e100_update_link_state
- * 
- * Description: This routine updates the link status of the adapter,
- * 		also considering netif_running
- *
- * Arguments:  bdp - Pointer to the e100_private structure for the board
- *		    
- *
- * Returns: true - If a link is found
- *		false - If there is no link
- *
- */
-unsigned char
-e100_update_link_state(struct e100_private *bdp)
-{
-	unsigned char link;
-
-	/* Logical AND PHY link & netif_running */
-	link = e100_get_link_state(bdp) && netif_running(bdp->device);
-
-	if (link) {
-		if (!netif_carrier_ok(bdp->device))
-			netif_carrier_on(bdp->device);
-	} else {
-		if (netif_carrier_ok(bdp->device))
-			netif_carrier_off(bdp->device);
-	}
-
-	return link;
-}
-
-/**************************************************************************\
- **
- ** PROC NAME:     e100_handle_zlock
- **    This function manages a state machine that controls
- **    the driver's zero locking algorithm.
- **    This function is called by e100_watchdog() every ~2 second.
- ** States:
- **    The current link handling state is stored in 
- **    bdp->zlock_state, and is one of:
- **    ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING
- **    Detailed description of the states and the transitions
- **    between states is found below.
- **    Note that any time the link is down / there is a reset
- **    state will be changed outside this function to ZLOCK_INITIAL
- ** Algorithm:
- **    1. If link is up & 100 Mbps continue else stay in #1:
- **    2. Set 'auto lock'
- **    3. Read & Store 100 times 'Zero' locked in 1 sec interval
- **    4. If max zero read >= 0xB continue else goto 1
- **    5. Set most popular 'Zero' read in #3
- **    6. Sleep 5 minutes
- **    7. Read number of errors, if it is > 300 goto 2 else goto 6
- ** Data Structures (in DRIVER_DATA):
- **    zlock_state           - current state of the algorithm
- **    zlock_read_cnt        - counts number of reads (up to 100)
- **    zlock_read_data[i]    - counts number of times 'Zero' read was i, 0 <= i <= 15
- **    zlock_sleep_cnt       - keeps track of "sleep" time (up to 300 secs = 5 minutes)
- **                                
- ** Parameters:    DRIVER_DATA    *bdp
- **
- **                bdp  - Pointer to HSM's adapter data space
- **
- ** Return Value:  NONE
- **
- ** See Also:      e100_watchdog()
- **
- \**************************************************************************/
-void
-e100_handle_zlock(struct e100_private *bdp)
-{
-	u16 pos;
-	u16 eq_reg;
-	u16 err_cnt;
-	u8 mpz;			/* Most Popular Zero */
-
-	switch (bdp->zlock_state) {
-	case ZLOCK_INITIAL:
-
-		if (((u8) bdp->rev_id <= D102_REV_ID) ||
-		    !(bdp->cur_line_speed == 100) ||
-		    !netif_carrier_ok(bdp->device)) {
-			break;
-		}
-
-		/* initialize hw and sw and start reading */
-		e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-			       bdp->phy_addr, 0);
-		/* reset read counters: */
-		bdp->zlock_read_cnt = 0;
-		for (pos = 0; pos < 16; pos++)
-			bdp->zlock_read_data[pos] = 0;
-		/* start reading in the next call back: */
-		bdp->zlock_state = ZLOCK_READING;
-
-		/* FALL THROUGH !! */
-
-	case ZLOCK_READING:
-		/* state: reading (100 times) zero locked in 1 sec interval
-		 * prev states: ZLOCK_INITIAL
-		 * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */
-
-		e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR,
-			      bdp->phy_addr, &eq_reg);
-		pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4;
-		bdp->zlock_read_data[pos]++;
-		bdp->zlock_read_cnt++;
-
-		if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) {
-			/* check if we read a 'Zero' value of 0xB or greater */
-			if ((bdp->zlock_read_data[0xB]) ||
-			    (bdp->zlock_read_data[0xC]) ||
-			    (bdp->zlock_read_data[0xD]) ||
-			    (bdp->zlock_read_data[0xE]) ||
-			    (bdp->zlock_read_data[0xF])) {
-
-				/* we've read 'Zero' value of 0xB or greater,
-				 * find most popular 'Zero' value and lock it */
-				mpz = 0;
-				/* this loop finds the most popular 'Zero': */
-				for (pos = 1; pos < 16; pos++) {
-					if (bdp->zlock_read_data[pos] >
-					    bdp->zlock_read_data[mpz])
-
-						mpz = pos;
-				}
-				/* now lock the most popular 'Zero': */
-				eq_reg = (ZLOCK_SET_ZERO | mpz);
-				e100_mdi_write(bdp,
-					       PHY_82555_MDI_EQUALIZER_CSR,
-					       bdp->phy_addr, eq_reg);
-
-				/* sleep for 5 minutes: */
-				bdp->zlock_sleep_cnt = jiffies;
-				bdp->zlock_state = ZLOCK_SLEEPING;
-				/* we will be reading the # of errors after 5
-				 * minutes, so we need to reset the error
-				 * counters - these registers are self clearing
-				 * on read, so read them */
-				e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
-					      bdp->phy_addr, &err_cnt);
-
-			} else {
-				/* we did not read a 'Zero' value of 0xB or
-				 * above. go back to the start */
-				bdp->zlock_state = ZLOCK_INITIAL;
-			}
-
-		}
-		break;
-
-	case ZLOCK_SLEEPING:
-		/* state: sleeping for 5 minutes
-		 * prev states: ZLOCK_READING
-		 * next states: ZLOCK_READING, ZLOCK_SLEEPING */
-
-		/* if 5 minutes have passed: */
-		if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) {
-			/* read and sum up the number of errors:  */
-			e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
-				      bdp->phy_addr, &err_cnt);
-			/* if we've more than 300 errors (this number was
-			 * calculated according to the spec max allowed errors
-			 * (80 errors per 1 million frames) for 5 minutes in
-			 * 100 Mbps (or the user specified max BER number) */
-			if (err_cnt > bdp->params.ber) {
-				/* start again in the next callback: */
-				bdp->zlock_state = ZLOCK_INITIAL;
-			} else {
-				/* we don't have more errors than allowed,
-				 * sleep for 5 minutes */
-				bdp->zlock_sleep_cnt = jiffies;
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-}
--- diff/drivers/net/e100/e100_phy.h	2003-05-21 11:49:55.000000000 +0100
+++ source/drivers/net/e100/e100_phy.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,158 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef _E100_PHY_INC_
-#define _E100_PHY_INC_
-
-#include "e100.h"
-
-/*
- * Auto-polarity enable/disable
- * e100_autopolarity = 0 => disable auto-polarity
- * e100_autopolarity = 1 => enable auto-polarity
- * e100_autopolarity = 2 => let software determine
- */
-#define E100_AUTOPOLARITY 2
-
-#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \
-                        ((bdp)->pdev->subsystem_device == 0xB0E1))
-
-#define PHY_503                 0
-#define PHY_100_A               0x000003E0
-#define PHY_100_C               0x035002A8
-#define PHY_NSC_TX              0x5c002000
-#define PHY_82562ET             0x033002A8
-#define PHY_82562EM             0x032002A8
-#define PHY_82562EH             0x017002A8
-#define PHY_82555_TX            0x015002a8	/* added this for 82555 */
-#define PHY_OTHER               0xFFFF
-#define MAX_PHY_ADDR            31
-#define MIN_PHY_ADDR            0
-
-#define PHY_MODEL_REV_ID_MASK   0xFFF0FFFF
-
-#define PHY_DEFAULT_ADDRESS 1
-#define PHY_ADDRESS_503 32
-
-/* MDI Control register bit definitions */
-#define MDI_PHY_READY	    BIT_28	/* PHY is ready for next MDI cycle */
-
-#define MDI_NC3133_CONFIG_REG           0x19
-#define MDI_NC3133_100FX_ENABLE         BIT_2
-#define MDI_NC3133_INT_ENABLE_REG       0x17
-#define MDI_NC3133_INT_ENABLE           BIT_1
-
-/* MDI Control register opcode definitions */
-#define MDI_WRITE 1		/* Phy Write */
-#define MDI_READ  2		/* Phy read */
-
-/* MDI register set*/
-#define AUTO_NEG_NEXT_PAGE_REG	    0x07	/* Auto-negotiation next page xmit */
-#define EXTENDED_REG_0		    0x10	/* Extended reg 0 (Phy 100 modes) */
-#define EXTENDED_REG_1		    0x14	/* Extended reg 1 (Phy 100 error indications) */
-#define NSC_CONG_CONTROL_REG	    0x17	/* National (TX) congestion control */
-#define NSC_SPEED_IND_REG	    0x19	/* National (TX) speed indication */
-
-#define HWI_CONTROL_REG             0x1D	/* HWI Control register */
-/* MDI/MDI-X Control Register bit definitions */
-#define MDI_MDIX_RES_TIMER          BIT_0_3	/* minimum slot time for resolution timer */
-#define MDI_MDIX_CONFIG_IS_OK       BIT_4	/* 1 = resolution algorithm completes OK */
-#define MDI_MDIX_STATUS             BIT_5	/* 1 = MDIX (croos over), 0 = MDI (straight through) */
-#define MDI_MDIX_SWITCH             BIT_6	/* 1 = Forces to MDIX, 0 = Forces to MDI */
-#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7	/* 1 = MDI/MDI-X feature enabled */
-#define MDI_MDIX_CONCT_CONFIG       BIT_8	/* Sets the MDI/MDI-X connectivity configuration (test prupose only) */
-#define MDI_MDIX_CONCT_TEST_ENABLE  BIT_9	/* 1 = Enables connectivity testing */
-#define MDI_MDIX_RESET_ALL_MASK     0x0000
-
-/* HWI Control Register bit definitions */
-#define HWI_TEST_DISTANCE           BIT_0_8	/* distance to cable problem */
-#define HWI_TEST_HIGHZ_PROBLEM      BIT_9	/* 1 = Open Circuit */
-#define HWI_TEST_LOWZ_PROBLEM       BIT_10	/* 1 = Short Circuit */
-#define HWI_TEST_RESERVED           (BIT_11 | BIT_12)	/* reserved */
-#define HWI_TEST_EXECUTE            BIT_13	/* 1 = Execute the HWI test on the PHY */
-#define HWI_TEST_ABILITY            BIT_14	/* 1 = test passed */
-#define HWI_TEST_ENABLE             BIT_15	/* 1 = Enables the HWI feature */
-#define HWI_RESET_ALL_MASK          0x0000
-
-/* ############Start of 82555 specific defines################## */
-
-/* Intel 82555 specific registers */
-#define PHY_82555_CSR		    0x10	/* 82555 CSR */
-#define PHY_82555_SPECIAL_CONTROL   0x11	/* 82555 special control register */
-
-#define PHY_82555_RCV_ERR	    0x15	/* 82555 100BaseTx Receive Error
-						 * Frame Counter */
-#define PHY_82555_SYMBOL_ERR	    0x16	/* 82555 RCV Symbol Error Counter */
-#define PHY_82555_PREM_EOF_ERR	    0x17	/* 82555 100BaseTx RCV Premature End
-						 * of Frame Error Counter */
-#define PHY_82555_EOF_COUNTER	    0x18	/* 82555 end of frame error counter */
-#define PHY_82555_MDI_EQUALIZER_CSR 0x1a	/* 82555 specific equalizer reg. */
-
-/* 82555 CSR bits */
-#define PHY_82555_SPEED_BIT    BIT_1
-#define PHY_82555_POLARITY_BIT BIT_8
-
-/* 82555 equalizer reg. opcodes */
-#define ENABLE_ZERO_FORCING  0x2010	/* write to ASD conf. reg. 0 */
-#define DISABLE_ZERO_FORCING 0x2000	/* write to ASD conf. reg. 0 */
-
-/* 82555 special control reg. opcodes */
-#define DISABLE_AUTO_POLARITY 0x0010
-#define EXTENDED_SQUELCH_BIT  BIT_2
-
-/* ############End of 82555 specific defines##################### */
-
-/* Auto-Negotiation advertisement register bit definitions*/
-#define NWAY_AD_FC_SUPPORTED    0x0400	/* Flow Control supported */
-
-/* Auto-Negotiation link partner ability register bit definitions*/
-#define NWAY_LP_ABILITY	        0x07e0	/* technologies supported */
-
-/* PHY 100 Extended Register 0 bit definitions*/
-#define PHY_100_ER0_FDX_INDIC	BIT_0	/* 1 = FDX, 0 = half duplex */
-#define PHY_100_ER0_SPEED_INDIC BIT_1	/* 1 = 100Mbps, 0= 10Mbps */
-
-/* National Semiconductor TX phy congestion control register bit definitions*/
-#define NSC_TX_CONG_TXREADY  BIT_10	/* Makes TxReady an input */
-#define NSC_TX_CONG_ENABLE   BIT_8	/* Enables congestion control */
-
-/* National Semiconductor TX phy speed indication register bit definitions*/
-#define NSC_TX_SPD_INDC_SPEED BIT_6	/* 0 = 100Mbps, 1=10Mbps */
-
-/************* function prototypes ************/
-extern unsigned char e100_phy_init(struct e100_private *bdp);
-extern unsigned char e100_update_link_state(struct e100_private *bdp);
-extern unsigned char e100_phy_check(struct e100_private *bdp);
-extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
-				      unsigned char force_restart);
-extern void e100_phy_autoneg(struct e100_private *bdp);
-extern void e100_phy_reset(struct e100_private *bdp);
-extern void e100_phy_set_loopback(struct e100_private *bdp);
-extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
-extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *);
-
-#endif
--- diff/drivers/net/e100/e100_test.c	2003-06-09 14:18:19.000000000 +0100
+++ source/drivers/net/e100/e100_test.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,500 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#include "e100_phy.h"
-#include "e100_config.h"
-
-extern u16 e100_eeprom_read(struct e100_private *, u16);
-extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8);
-extern void e100_phy_reset(struct e100_private *bdp);
-extern void e100_phy_autoneg(struct e100_private *bdp);
-extern void e100_phy_set_loopback(struct e100_private *bdp);
-extern void e100_force_speed_duplex(struct e100_private *bdp);
-
-static u8 e100_diag_selftest(struct net_device *);
-static u8 e100_diag_eeprom(struct net_device *);
-static u8 e100_diag_loopback(struct net_device *);
-
-static u8 e100_diag_one_loopback (struct net_device *, u8);
-static u8 e100_diag_rcv_loopback_pkt(struct e100_private *);
-static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *);
-static u8 e100_diag_loopback_alloc(struct e100_private *);
-static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
-static u8 e100_diag_check_pkt(u8 *);
-static void e100_diag_loopback_free(struct e100_private *);
-static int e100_cable_diag(struct e100_private *bdp);
-
-#define LB_PACKET_SIZE 1500
-
-/**
- * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines  
- * @dev: atapter's net device data struct
- * @test_info: array with test request mask also used to store test results
- *
- * RETURNS: updated flags field of struct ethtool_test
- */
-u32
-e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
-{
-	struct e100_private* bdp = dev->priv;
-	u8 test_result = 0;
-
-	if (!e100_get_link_state(bdp)) {
-		test_result = ETH_TEST_FL_FAILED;
-		test_info[test_link] = true;
-	}
-	if (!e100_diag_eeprom(dev)) {
-		test_result = ETH_TEST_FL_FAILED;
-		test_info[test_eeprom] = true;
-	}
-	if (flags & ETH_TEST_FL_OFFLINE) {
-		u8 fail_mask;
-		if (netif_running(dev)) {
-			spin_lock_bh(&dev->xmit_lock);
-			e100_close(dev);
-			spin_unlock_bh(&dev->xmit_lock);
-		}
-		if (e100_diag_selftest(dev)) {
-			test_result = ETH_TEST_FL_FAILED;
-			test_info[test_self_test] = true;
-		}
-
-		fail_mask = e100_diag_loopback(dev);
-		if (fail_mask) {
-			test_result = ETH_TEST_FL_FAILED;
-			if (fail_mask & PHY_LOOPBACK)
-				test_info[test_loopback_phy] = true;
-			if (fail_mask & MAC_LOOPBACK)
-				test_info[test_loopback_mac] = true;
-		}
-
-		test_info[cable_diag] = e100_cable_diag(bdp);
-		/* Need hw init regardless of netif_running */
-		e100_hw_init(bdp);
-		if (netif_running(dev)) {
-			e100_open(dev);
-		}
-	}
-	else {
-		test_info[test_self_test] = false;
-		test_info[test_loopback_phy] = false;
-		test_info[test_loopback_mac] = false;
-		test_info[cable_diag] = false;
-	}
-
-	return flags | test_result;
-}
-
-/**
- * e100_diag_selftest - run hardware selftest 
- * @dev: atapter's net device data struct
- */
-static u8
-e100_diag_selftest(struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-	u32 st_timeout, st_result;
-	u8 retval = 0;
-
-	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
-		if (!st_timeout) {
-			if (st_result & CB_SELFTEST_REGISTER_BIT)
-				retval |= REGISTER_TEST_FAIL;
-			if (st_result & CB_SELFTEST_DIAG_BIT)
-				retval |= SELF_TEST_FAIL;
-			if (st_result & CB_SELFTEST_ROM_BIT)
-				retval |= ROM_TEST_FAIL;
-		} else {
-            		retval = TEST_TIMEOUT;
-		}
-	}
-
-	return retval;
-}
-
-/**
- * e100_diag_eeprom - validate eeprom checksum correctness
- * @dev: atapter's net device data struct
- *
- */
-static u8
-e100_diag_eeprom (struct net_device *dev)
-{
-	struct e100_private *bdp = dev->priv;
-	u16 i, eeprom_sum, eeprom_actual_csm;
-
-	for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) {
-		eeprom_sum += e100_eeprom_read(bdp, i);
-	}
-
-	eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1);
-
-	if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) {
-		return true;
-	}
-
-	return false;
-}
-
-/**
- * e100_diag_loopback - performs loopback test  
- * @dev: atapter's net device data struct
- */
-static u8
-e100_diag_loopback (struct net_device *dev)
-{
-	u8 rc = 0;
-
-	printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name);
-	e100_hw_init(dev->priv);
-	if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
-		rc |= PHY_LOOPBACK;
-	}
-	printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name);
-
-	printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name);
-	e100_hw_init(dev->priv);
-	if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
-		rc |= MAC_LOOPBACK;
-	}
-	printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name);
-
-	return rc;
-}
-
-/**
- * e100_diag_loopback - performs loopback test  
- * @dev: atapter's net device data struct
- * @mode: lopback test type
- */
-static u8
-e100_diag_one_loopback (struct net_device *dev, u8 mode)
-{
-        struct e100_private *bdp = dev->priv;
-        u8 res = false;
-   	u8 saved_dynamic_tbd = false;
-   	u8 saved_extended_tcb = false;
-
-	if (!e100_diag_loopback_alloc(bdp))
-		return false;
-
-	/* change the config block to standard tcb and the correct loopback */
-        e100_diag_config_loopback(bdp, true, mode,
-				  &saved_extended_tcb, &saved_dynamic_tbd);
-
-	e100_diag_loopback_cu_ru_exec(bdp);
-
-        if (e100_diag_rcv_loopback_pkt(bdp)) {
-		res = true;
-	}
-
-        e100_diag_loopback_free(bdp);
-
-        /* change the config block to previous tcb mode and the no loopback */
-        e100_diag_config_loopback(bdp, false, mode,
-				  &saved_extended_tcb, &saved_dynamic_tbd);
-	return res;
-}
-
-/**
- * e100_diag_config_loopback - setup/clear loopback before/after lpbk test
- * @bdp: atapter's private data struct
- * @set_loopback: true if the function is called to set lb
- * @loopback_mode: the loopback mode(MAC or PHY)
- * @tcb_extended: true if need to set extended tcb mode after clean loopback
- * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback
- *
- */
-void
-e100_diag_config_loopback(struct e100_private* bdp,
-			  u8 set_loopback,
-			  u8 loopback_mode,
-			  u8* tcb_extended,
-			  u8* dynamic_tbd)
-{
-	/* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd.
-	 * the previous values are saved in the params tcb_extended/dynamic_tbd
-	 * if set_loopback == false - we want to restore previous value.
-	 */
-	if (set_loopback || (*tcb_extended))
-		  *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended);
-
-	if (set_loopback || (*dynamic_tbd))
-		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
-
-	if (set_loopback) {
-		/* ICH PHY loopback is broken */
-		if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK)
-			loopback_mode = MAC_LOOPBACK;
-		/* Configure loopback on MAC */
-		e100_config_loopback_mode(bdp,loopback_mode);
-	} else {
-		e100_config_loopback_mode(bdp,NO_LOOPBACK);
-	}
-
-	e100_config(bdp);
-
-	if (loopback_mode == PHY_LOOPBACK) {
-		if (set_loopback)
-                        /* Set PHY loopback mode */
-                        e100_phy_set_loopback(bdp);
-		else
-			/* Reset PHY loopback mode */
-			e100_phy_reset(bdp);	
-		/* Wait for PHY state change */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-                schedule_timeout(HZ);
-	} else { /* For MAC loopback wait 500 msec to take effect */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 2);
-	}
-}
-  
-/**
- * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback
- * @bdp: atapter's private data struct
- *
- */
-static u8
-e100_diag_loopback_alloc(struct e100_private *bdp)
-{
-	dma_addr_t dma_handle;
-	tcb_t *tcb;
-	rfd_t *rfd;
-	tbd_t *tbd;
-
-	/* tcb, tbd and transmit buffer are allocated */
-	tcb = pci_alloc_consistent(bdp->pdev,
-				   (sizeof (tcb_t) + sizeof (tbd_t) +
-				    LB_PACKET_SIZE),
-				   &dma_handle);
-        if (tcb == NULL)
-		return false;
-
-	memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE);
-	tcb->tcb_phys = dma_handle;
-	tcb->tcb_hdr.cb_status = 0;
-	tcb->tcb_hdr.cb_cmd =
-		cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
-	/* Next command is null */
-	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff);
-	tcb->tcb_cnt = 0;
-	tcb->tcb_thrshld = bdp->tx_thld;
-	tcb->tcb_tbd_num = 1;
-	/* Set up tcb tbd pointer */
-	tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
-	tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
-	/* Set up tbd transmit buffer */
-	tbd->tbd_buf_addr =
-		cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
-	tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
-	/* The value of first 512 bytes is FF */
-	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512);
-	/* The value of second 512 bytes is BA */
-	memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
-	wmb();
-	rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
-
-	if (rfd == NULL) {
-		pci_free_consistent(bdp->pdev,
-				    sizeof (tcb_t) + sizeof (tbd_t) +
-				    LB_PACKET_SIZE, tcb, tcb->tcb_phys);
-		return false;
-	}
-
-	memset(rfd, 0x00, sizeof (rfd_t));
-
-	/* init all fields in rfd */
-	rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
-	rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
-	/* dma_handle is physical address of rfd */
-	bdp->loopback.dma_handle = dma_handle;
-	bdp->loopback.tcb = tcb;
-	bdp->loopback.rfd = rfd;
-	wmb();
-	return true;
-}
-
-/**
- * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt
- * @bdp: atapter's private data struct
- *
- */
-static void
-e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
-{
-	/*load CU & RU base */ 
-	if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0))
-		printk(KERN_ERR "e100: SCB_RUC_START failed!\n");
-
-	bdp->next_cu_cmd = START_WAIT;
-	e100_start_cu(bdp, bdp->loopback.tcb);
-	bdp->last_tcb = NULL;
-	rmb();
-}
-/**
- * e100_diag_check_pkt - checks if a given packet is a loopback packet
- * @bdp: atapter's private data struct
- *
- * Returns true if OK false otherwise.
- */
-static u8
-e100_diag_check_pkt(u8 *datap)
-{
-	int i;
-	for (i = 0; i<512; i++) {
-		if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) {
-			printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i);
-			return false;
-			}
-	}
-	printk (KERN_DEBUG "e100: Check received loopback packet OK\n");
-	return true;
-}
-
-/**
- * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet
- * @bdp: atapter's private data struct
- *
- * Returns true if OK false otherwise.
- */
-static u8
-e100_diag_rcv_loopback_pkt(struct e100_private* bdp) 
-{    
-	rfd_t *rfdp;
-	u16 rfd_status;
-	unsigned long expires = jiffies + HZ * 2;
-
-        rfdp =bdp->loopback.rfd;
-
-        rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
-
-        while (!(rfd_status & RFD_STATUS_COMPLETE)) { 
-		if (time_before(jiffies, expires)) {
-			yield();
-			rmb();
-			rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
-		} else {
-			break;
-		}
-        }
-
-        if (rfd_status & RFD_STATUS_COMPLETE) {
-		printk(KERN_DEBUG "e100: Loopback packet received\n");
-                return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
-	}
-	else {
-		printk(KERN_ERR "e100: Loopback packet not received\n");
-		return false;
-	}
-}
-
-/**
- * e100_diag_loopback_free - free data allocated for loopback pkt send/receive
- * @bdp: atapter's private data struct
- *
- */
-static void
-e100_diag_loopback_free (struct e100_private *bdp)
-{
-        pci_free_consistent(bdp->pdev,
-			    sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE,
-			    bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys);
-
-        pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd,
-			    bdp->loopback.dma_handle);
-}
-
-static int
-e100_cable_diag(struct e100_private *bdp)
-{	
-	int saved_open_circut = 0xffff;
-	int saved_short_circut = 0xffff;
-	int saved_distance = 0xffff;
-	int saved_same = 0;
-	int cable_status = E100_CABLE_UNKNOWN;
-	int i;
-	
-	/* If we have link, */	
-	if (e100_get_link_state(bdp))
-		return E100_CABLE_OK;
-	
-	if (bdp->rev_id < D102_REV_ID)
-		return E100_CABLE_UNKNOWN;
-
-	/* Disable MDI/MDI-X auto switching */
-        e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		MDI_MDIX_RESET_ALL_MASK);
-	/* Set to 100 Full as required by cable test */
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-		BMCR_SPEED100 | BMCR_FULLDPLX);
-
-	/* Test up to 100 times */
-	for (i = 0; i < 100; i++) {
-		u16 ctrl_reg;
-		int distance, open_circut, short_circut, near_end;
-
-		/* Enable and execute cable test */
-		e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-			(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-		/* Wait for cable test finished */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/100 + 1);
-		/* Read results */
-		e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
-		distance = ctrl_reg & HWI_TEST_DISTANCE;
-		open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
-		short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
-
-		if ((distance == saved_distance) &&
-	    	    (open_circut == saved_open_circut) &&
-	    	    (short_circut == saved_short_circut)) 
-			saved_same++;
-		else {
-			saved_same = 0;
-			saved_distance = distance;
-			saved_open_circut = open_circut;
-			saved_short_circut = short_circut;
-		}
-		/* If results are the same 3 times */
-		if (saved_same == 3) {
-			near_end = ((distance * HWI_REGISTER_GRANULARITY) <
-			       HWI_NEAR_END_BOUNDARY);
-			if (open_circut)
-				cable_status = (near_end) ? 
-					E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR;
-			if (short_circut)
-				cable_status = (near_end) ?
-					E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR;
-			break;
-		}
-	}
-	/* Reset cable test */
-        e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,					       HWI_RESET_ALL_MASK);
-	return cable_status;
-}
-
--- diff/drivers/net/e100/e100_ucode.h	2003-05-21 11:49:55.000000000 +0100
+++ source/drivers/net/e100/e100_ucode.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,365 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2003 Intel Corporation. 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.
-  
-  This program is distributed in the hope that it will be useful, but WITHOUT 
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
-  more details.
-  
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-#ifndef _E100_UCODE_H_
-#define _E100_UCODE_H_
-
-/*
-e100_ucode.h
-
-This file contains the loadable micro code arrays to implement receive 
-bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, 
-D102 B-step, D102 B-step with TCO work around and D102 C-step.
-
-Each controller has its own specific micro code array.  The array for one 
-controller is totally incompatible with any other controller, and if used 
-will most likely cause the controller to lock up and stop responding to 
-the driver.  Each micro code array has its own parameter offsets (described 
-below), and they each have their own version number.
-*/
-
-/*************************************************************************
-*  CPUSaver parameters
-*
-*  All CPUSaver parameters are 16-bit literals that are part of a
-*  "move immediate value" instruction.  By changing the value of
-*  the literal in the instruction before the code is loaded, the
-*  driver can change algorithm.
-*
-*  CPUSAVER_DWORD - This is the location of the instruction that loads
-*    the dead-man timer with its inital value.  By writing a 16-bit
-*    value to the low word of this instruction, the driver can change
-*    the timer value.  The current default is either x600 or x800;
-*    experiments show that the value probably should stay within the
-*    range of x200 - x1000.
-*
-*  CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction
-*    that sets the maximum number of frames that will be bundled.  In
-*    some situations, such as the TCP windowing algorithm, it may be
-*    better to limit the growth of the bundle size than let it go as
-*    high as it can, because that could cause too much added latency.
-*    The default is six, because this is the number of packets in the
-*    default TCP window size.  A value of 1 would make CPUSaver indicate
-*    an interrupt for every frame received.  If you do not want to put
-*    a limit on the bundle size, set this value to xFFFF.
-*
-*  CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction
-*    that contains a bit-mask describing the minimum size frame that
-*    will be bundled.  The default masks the lower 7 bits, which means
-*    that any frame less than 128 bytes in length will not be bundled,
-*    but will instead immediately generate an interrupt.  This does
-*    not affect the current bundle in any way.  Any frame that is 128
-*    bytes or large will be bundled normally.  This feature is meant
-*    to provide immediate indication of ACK frames in a TCP environment.
-*    Customers were seeing poor performance when a machine with CPUSaver
-*    enabled was sending but not receiving.  The delay introduced when
-*    the ACKs were received was enough to reduce total throughput, because
-*    the sender would sit idle until the ACK was finally seen.
-*
-*    The current default is 0xFF80, which masks out the lower 7 bits.
-*    This means that any frame which is x7F (127) bytes or smaller
-*    will cause an immediate interrupt.  Because this value must be a 
-*    bit mask, there are only a few valid values that can be used.  To
-*    turn this feature off, the driver can write the value xFFFF to the
-*    lower word of this instruction (in the same way that the other
-*    parameters are used).  Likewise, a value of 0xF800 (2047) would
-*    cause an interrupt to be generated for every frame, because all
-*    standard Ethernet frames are <= 2047 bytes in length.
-*************************************************************************/
-
-#ifndef UCODE_MAX_DWORDS
-#define UCODE_MAX_DWORDS	134
-#endif
-
-/********************************************************/
-/*  CPUSaver micro code for the D101A                   */
-/********************************************************/
-
-/*  Version 2.0  */
-
-/*  This value is the same for both A and B step of 558.  */
-
-#define D101_CPUSAVER_TIMER_DWORD		72
-#define D101_CPUSAVER_BUNDLE_DWORD		UCODE_MAX_DWORDS
-#define D101_CPUSAVER_MIN_SIZE_DWORD		UCODE_MAX_DWORDS
-
-#define     D101_A_RCVBUNDLE_UCODE \
-{\
-0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
-0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \
-0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
-0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \
-0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \
-0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \
-0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
-0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \
-0x00101213, 0x00041000, 0x0038051E, 0x00101313, \
-0x00010400, 0x00380521, 0x00050600, 0x00100824, \
-0x00101310, 0x00041000, 0x00080600, 0x00101B10, \
-0x0038051E, 0x00000000, 0x00000000, 0x00000000  \
-}
-
-/********************************************************/
-/*  CPUSaver micro code for the D101B                   */
-/********************************************************/
-
-/*  Version 2.0  */
-
-#define     D101_B0_RCVBUNDLE_UCODE \
-{\
-0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
-0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \
-0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
-0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \
-0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \
-0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \
-0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
-0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \
-0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \
-0x00010400, 0x00380522, 0x00050600, 0x00100837, \
-0x00101310, 0x00041000, 0x00080600, 0x00101790, \
-0x0038051F, 0x00000000, 0x00000000, 0x00000000  \
-}
-
-/********************************************************/
-/*  CPUSaver micro code for the D101M (B-step only)     */
-/********************************************************/
-
-/*  Version 2.10.1  */
-
-/*  Parameter values for the D101M B-step  */
-#define D101M_CPUSAVER_TIMER_DWORD		78
-#define D101M_CPUSAVER_BUNDLE_DWORD		65
-#define D101M_CPUSAVER_MIN_SIZE_DWORD		126
-
-#define D101M_B_RCVBUNDLE_UCODE \
-{\
-0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
-0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
-0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
-0x00380438, 0x00000000, 0x00140000, 0x00380555, \
-0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
-0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
-0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
-0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
-0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
-0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
-0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
-0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
-0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
-0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
-0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
-0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
-0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
-0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
-0x00380559, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
-0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
-0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
-}
-
-/********************************************************/
-/*  CPUSaver micro code for the D101S                   */
-/********************************************************/
-
-/*  Version 1.20.1  */
-
-/*  Parameter values for the D101S  */
-#define D101S_CPUSAVER_TIMER_DWORD		78
-#define D101S_CPUSAVER_BUNDLE_DWORD		67
-#define D101S_CPUSAVER_MIN_SIZE_DWORD		128
-
-#define D101S_RCVBUNDLE_UCODE \
-{\
-0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
-0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
-0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
-0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
-0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
-0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
-0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
-0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
-0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
-0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
-0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
-0x00101313, 0x00380700, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
-0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
-0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
-0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
-0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
-0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
-0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
-0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
-0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00130831, \
-0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
-0x00041000, 0x00010004, 0x00380700  \
-}
-
-/********************************************************/
-/*  CPUSaver micro code for the D102 B-step             */
-/********************************************************/
-
-/*  Version 2.0  */
-/*  Parameter values for the D102 B-step  */
-#define D102_B_CPUSAVER_TIMER_DWORD		82
-#define D102_B_CPUSAVER_BUNDLE_DWORD		106
-#define D102_B_CPUSAVER_MIN_SIZE_DWORD		70
-
-#define     D102_B_RCVBUNDLE_UCODE \
-{\
-0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \
-0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \
-0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \
-0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
-0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \
-0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \
-0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \
-0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \
-0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \
-0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \
-0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \
-0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \
-0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \
-0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \
-0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \
-0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \
-0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \
-0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \
-0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \
-0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \
-0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \
-0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \
-0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \
-0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \
-0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \
-}
-
-/********************************************************/
-/*  Micro code for the D102 C-step                      */
-/********************************************************/
-
-/*  Parameter values for the D102 C-step  */
-#define D102_C_CPUSAVER_TIMER_DWORD		46
-#define D102_C_CPUSAVER_BUNDLE_DWORD		74
-#define D102_C_CPUSAVER_MIN_SIZE_DWORD		54
-
-#define     D102_C_RCVBUNDLE_UCODE \
-{ \
-0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \
-0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \
-0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \
-0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \
-0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \
-0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \
-0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \
-0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
-0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \
-0x00E00E85, 0x00000000, 0x00000000, 0x00000000  \
-}
-
-/********************************************************/
-/*  Micro code for the D102 E-step                      */
-/********************************************************/
-
-/*  Parameter values for the D102 E-step  */
-#define D102_E_CPUSAVER_TIMER_DWORD		42
-#define D102_E_CPUSAVER_BUNDLE_DWORD		54
-#define D102_E_CPUSAVER_MIN_SIZE_DWORD		46
-
-#define     D102_E_RCVBUNDLE_UCODE \
-{\
-0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \
-0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
-0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
-0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
-0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
-0x00300006, 0x00E014FB, 0x00000000, 0x00000000  \
-}
-
-#endif /* _E100_UCODE_H_ */
--- diff/fs/devfs/internal.h	2003-02-13 11:46:39.000000000 +0000
+++ source/fs/devfs/internal.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-
-extern dev_t devfs_alloc_devnum(umode_t mode);
-extern void devfs_dealloc_devnum(umode_t mode, dev_t devnum);
--- diff/include/linux/if_pppvar.h	2002-10-16 04:29:05.000000000 +0100
+++ source/include/linux/if_pppvar.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,138 +0,0 @@
-/*	From: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp */
-/*
- * if_pppvar.h - private structures and declarations for PPP.
- *
- * Copyright (c) 1994 The Australian National University.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, provided that the above copyright
- * notice appears in all copies.  This software is provided without any
- * warranty, express or implied. The Australian National University
- * makes no representations about the suitability of this software for
- * any purpose.
- *
- * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
- * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
- * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
- * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
- * OR MODIFICATIONS.
- *
- * Copyright (c) 1989 Carnegie Mellon University.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- *  ==FILEVERSION 990806==
- *
- *  NOTE TO MAINTAINERS:
- *   If you modify this file at all, please set the above date.
- *   if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
- *   if everyone increases the FILEVERSION number above, then scripts
- *   can do the right thing when deciding whether to install a new if_pppvar.h
- *   file.  Don't change the format of that line otherwise, so the
- *   installation script can recognize it.
- */
-
-/*
- * Supported network protocols.  These values are used for
- * indexing sc_npmode.
- */
-
-#define NP_IP	0		/* Internet Protocol */
-#define NP_IPX	1		/* IPX protocol */
-#define NP_AT	2		/* Appletalk protocol */
-#define NP_IPV6	3		/* Internet Protocol */
-#define NUM_NP	4		/* Number of NPs. */
-
-#define OBUFSIZE	256	/* # chars of output buffering */
-
-/*
- * Structure describing each ppp unit.
- */
-
-struct ppp {
-	int		magic;		/* magic value for structure	*/
-	struct ppp	*next;		/* unit with next index		*/
-	unsigned long	inuse;		/* are we allocated?		*/
-	int		line;		/* network interface unit #	*/
-	__u32		flags;		/* miscellaneous control flags	*/
-	int		mtu;		/* maximum xmit frame size	*/
-	int		mru;		/* maximum receive frame size	*/
-	struct slcompress *slcomp;	/* for TCP header compression	*/
-	struct sk_buff_head xmt_q;	/* frames to send from pppd	*/
-	struct sk_buff_head rcv_q;	/* frames for pppd to read	*/
-	unsigned long	xmit_busy;	/* bit 0 set when xmitter busy  */
-
-	/* Information specific to using ppp on async serial lines. */
-	struct tty_struct *tty;		/* ptr to TTY structure	*/
-	struct tty_struct *backup_tty;	/* TTY to use if tty gets closed */
-	__u8		escape;		/* 0x20 if prev char was PPP_ESC */
-	__u8		toss;		/* toss this frame		*/
-	volatile __u8	tty_pushing;	/* internal state flag		*/
-	volatile __u8	woke_up;	/* internal state flag		*/
-	__u32		xmit_async_map[8]; /* 1 bit means that given control 
-					   character is quoted on output*/
-	__u32		recv_async_map; /* 1 bit means that given control 
-					   character is ignored on input*/
-	__u32		bytes_sent;	/* Bytes sent on frame	*/
-	__u32		bytes_rcvd;	/* Bytes recvd on frame	*/
-
-	/* Async transmission information */
-	struct sk_buff	*tpkt;		/* frame currently being sent	*/
-	int		tpkt_pos;	/* how much of it we've done	*/
-	__u16		tfcs;		/* FCS so far for it		*/
-	unsigned char	*optr;		/* where we're up to in sending */
-	unsigned char	*olim;		/* points past last valid char	*/
-
-	/* Async reception information */
-	struct sk_buff	*rpkt;		/* frame currently being rcvd	*/
-	__u16		rfcs;		/* FCS so far of rpkt		*/
-
-	/* Queues for select() functionality */
-	wait_queue_head_t read_wait;	/* queue for reading processes	*/
-
-	/* info for detecting idle channels */
-	unsigned long	last_xmit;	/* time of last transmission	*/
-	unsigned long	last_recv;	/* time last packet received    */
-
-	/* Statistic information */
-	struct pppstat	stats;		/* statistic information	*/
-
-	/* PPP compression protocol information */
-	struct	compressor *sc_xcomp;	/* transmit compressor */
-	void	*sc_xc_state;		/* transmit compressor state */
-	struct	compressor *sc_rcomp;	/* receive decompressor */
-	void	*sc_rc_state;		/* receive decompressor state */
-
-	enum	NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
-	int	 sc_xfer;		/* PID of reserved PPP table */
-	char	name[16];		/* space for unit name */
-	struct net_device	dev;		/* net device structure */
-	struct net_device_stats estats;	/* more detailed stats */
-
-	/* tty output buffer */
-	unsigned char	obuf[OBUFSIZE];	/* buffer for characters to send */
-};
-
-#define PPP_MAGIC	0x5002
-#define PPP_VERSION	"2.3.7"
--- diff/include/linux/isdn/fsm.h	2002-11-11 11:09:38.000000000 +0000
+++ source/include/linux/isdn/fsm.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,58 +0,0 @@
-/* Linux ISDN subsystem, finite state machine
- *
- * Author       Karsten Keil
- * Copyright              by Karsten Keil      <keil@isdn4linux.de>
- *              2001-2002 by Kai Germaschewski <kai@germaschewski.name>
- * 
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef __ISDN_FSM_H__
-#define __ISDN_FSM_H__
-
-#include <linux/kernel.h>
-#include <linux/timer.h>
-
-struct fsm_inst;
-
-typedef int (*fsm_fn)(struct fsm_inst *, int, void *);
-
-struct fsm {
-	fsm_fn *jumpmatrix;
-	int st_cnt, ev_cnt, fn_cnt;
-	char **st_str, **ev_str;
-	struct fsm_node *fn_tbl;
-};
-
-struct fsm_inst {
-	struct fsm *fsm;
-	int state;
-	int debug;
-	void *userdata;
-	int userint;
-	void (*printdebug) (struct fsm_inst *, char *, ...);
-};
-
-struct fsm_node {
-	int st, ev;
-	fsm_fn fn;
-};
-
-struct fsm_timer {
-	struct fsm_inst *fi;
-	struct timer_list tl;
-	int ev;
-	void *arg;
-};
-
-int  fsm_new(struct fsm *fsm);
-void fsm_free(struct fsm *fsm);
-int  fsm_event(struct fsm_inst *fi, int event, void *arg);
-void fsm_change_state(struct fsm_inst *fi, int newstate);
-void fsm_init_timer(struct fsm_inst *fi, struct fsm_timer *ft);
-int  fsm_add_timer(struct fsm_timer *ft, int timeout, int event);
-void fsm_mod_timer(struct fsm_timer *ft, int timeout, int event);
-void fsm_del_timer(struct fsm_timer *ft);
-
-#endif
--- diff/include/linux/modsetver.h	2002-10-16 04:28:20.000000000 +0100
+++ source/include/linux/modsetver.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,10 +0,0 @@
-/* Symbol versioning nastiness.  */
-
-#define __SYMBOL_VERSION(x)       __ver_ ## x
-#define __VERSIONED_SYMBOL2(x,v)  x ## _R ## v
-#define __VERSIONED_SYMBOL1(x,v)  __VERSIONED_SYMBOL2(x,v)
-#define __VERSIONED_SYMBOL(x)     __VERSIONED_SYMBOL1(x,__SYMBOL_VERSION(x))
-
-#ifndef _set_ver
-#define _set_ver(x)		  __VERSIONED_SYMBOL(x)
-#endif
--- diff/include/linux/ppp.h	2002-10-16 04:27:11.000000000 +0100
+++ source/include/linux/ppp.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-/*
- *	Back compatibility for a while.
- */
-#include <linux/if_ppp.h>
